Commit b09f9222 authored by catch's avatar catch

Issue #2717207 by mpdonadio, dawehner, catch, alexpott: Add a time service to...

Issue #2717207 by mpdonadio, dawehner, catch, alexpott: Add a time service to provide consistent interaction with time()/microtime() and superglobals
parent 9f26c569
......@@ -346,6 +346,9 @@ services:
class: Drupal\Core\Database\Connection
factory: Drupal\Core\Database\Database::getConnection
arguments: [default]
datetime.time:
class: Drupal\Component\Datetime\Time
arguments: ['@request_stack']
file_system:
class: Drupal\Core\File\FileSystem
arguments: ['@stream_wrapper_manager', '@settings', '@logger.channel.file']
......
......@@ -84,6 +84,9 @@
*
* @see http://php.net/manual/reserved.variables.server.php
* @see http://php.net/manual/function.time.php
*
* @deprecated in Drupal 8.3.0, will be removed before Drupal 9.0.0.
* Use \Drupal::time()->getRequestTime();
*/
define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
......
......@@ -738,4 +738,14 @@ public static function entityDefinitionUpdateManager() {
return static::getContainer()->get('entity.definition_update_manager');
}
/**
* Returns the time service.
*
* @return \Drupal\Component\Datetime\TimeInterface
* The time service.
*/
public static function time() {
return static::getContainer()->get('datetime.time');
}
}
<?php
namespace Drupal\Component\Datetime;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Provides a class for obtaining system time.
*/
class Time implements TimeInterface {
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* Constructs a Time object.
*
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(RequestStack $request_stack) {
$this->requestStack = $request_stack;
}
/**
* @{inheritdoc}
*/
public function getRequestTime() {
return $this->requestStack->getCurrentRequest()->server->get('REQUEST_TIME');
}
/**
* @{inheritdoc}
*/
public function getRequestMicroTime() {
return $this->requestStack->getCurrentRequest()->server->get('REQUEST_TIME_FLOAT');
}
/**
* @{inheritdoc}
*/
public function getCurrentTime() {
return time();
}
/**
* @{inheritdoc}
*/
public function getCurrentMicroTime() {
return microtime(TRUE);
}
}
<?php
namespace Drupal\Component\Datetime;
/**
* Defines an interface for obtaining system time.
*/
interface TimeInterface {
/**
* Returns the timestamp for the current request.
*
* This method should be used to obtain the current system time at the start
* of the request. It will be the same value for the life of the request
* (even for long execution times).
*
* This method can replace instances of
* @code
* $request_time = $_SERVER['REQUEST_TIME'];
* $request_time = REQUEST_TIME;
* $request_time = $requestStack->getCurrentRequest()->server->get('REQUEST_TIME');
* $request_time = $request->server->get('REQUEST_TIME');
* @endcode
* and most instances of
* @code
* $time = time();
* @endcode
* with
* @code
* $request_time = \Drupal::time()->getRequestTime();
* @endcode
* or the equivalent using the injected service.
*
* Using the time service, rather than other methods, is especially important
* when creating tests, which require predictable timestamps.
*
* @return int
* A Unix timestamp.
*
* @see \Drupal\Component\Datetime\TimeInterface::getRequestMicroTime()
* @see \Drupal\Component\Datetime\TimeInterface::getCurrentTime()
* @see \Drupal\Component\Datetime\TimeInterface::getCurrentMicroTime()
*/
public function getRequestTime();
/**
* Returns the timestamp for the current request with microsecond precision.
*
* This method should be used to obtain the current system time, with
* microsecond precision, at the start of the request. It will be the same
* value for the life of the request (even for long execution times).
*
* This method can replace instances of
* @code
* $request_time_float = $_SERVER['REQUEST_TIME_FLOAT'];
* $request_time_float = $requestStack->getCurrentRequest()->server->get('REQUEST_TIME_FLOAT');
* $request_time_float = $request->server->get('REQUEST_TIME_FLOAT');
* @endcode
* and many instances of
* @code
* $microtime = microtime();
* $microtime = microtime(TRUE);
* @endcode
* with
* @code
* $request_time = \Drupal::time()->getRequestMicroTime();
* @endcode
* or the equivalent using the injected service.
*
* Using the time service, rather than other methods, is especially important
* when creating tests, which require predictable timestamps.
*
* @return float
* A Unix timestamp with a fractional portion.
*
* @see \Drupal\Component\Datetime\TimeInterface::getRequestTime()
* @see \Drupal\Component\Datetime\TimeInterface::getCurrentTime()
* @see \Drupal\Component\Datetime\TimeInterface::getCurrentMicroTime()
*/
public function getRequestMicroTime();
/**
* Returns the current system time as an integer.
*
* This method should be used to obtain the current system time, at the time
* the method was called.
*
* This method can replace many instances of
* @code
* $time = time();
* @endcode
* with
* @code
* $request_time = \Drupal::time()->getCurrentTime();
* @endcode
* or the equivalent using the injected service.
*
* This method should only be used when the current system time is actually
* needed, such as with timers or time interval calculations. If only the
* time at the start of the request is needed,
* use TimeInterface::getRequestTime().
*
* Using the time service, rather than other methods, is especially important
* when creating tests, which require predictable timestamps.
*
* @return int
* A Unix timestamp.
*
* @see \Drupal\Component\Datetime\TimeInterface::getRequestTime()
* @see \Drupal\Component\Datetime\TimeInterface::getRequestMicroTime()
* @see \Drupal\Component\Datetime\TimeInterface::getCurrentMicroTime()
*/
public function getCurrentTime();
/**
* Returns the current system time with microsecond precision.
*
* This method should be used to obtain the current system time, with
* microsecond precision, at the time the method was called.
*
* This method can replace many instances of
* @code
* $microtime = microtime();
* $microtime = microtime(TRUE);
* @endcode
* with
* @code
* $request_time = \Drupal::time()->getCurrentMicroTime();
* @endcode
* or the equivalent using the injected service.
*
* This method should only be used when the current system time is actually
* needed, such as with timers or time interval calculations. If only the
* time at the start of the request and microsecond precision is needed,
* use TimeInterface::getRequestMicroTime().
*
* Using the time service, rather than other methods, is especially important
* when creating tests, which require predictable timestamps.
*
* @return float
* A Unix timestamp with a fractional portion.
*
* @see \Drupal\Component\Datetime\TimeInterface::getRequestTime()
* @see \Drupal\Component\Datetime\TimeInterface::getRequestMicroTime()
* @see \Drupal\Component\Datetime\TimeInterface::getCurrentTime()
*/
public function getCurrentMicroTime();
}
<?php
namespace Drupal\Tests\Component\Datetime;
use Drupal\Component\Datetime\Time;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
/**
* @coversDefaultClass \Drupal\Component\Datetime\Time
* @group Datetime
*
* Isolate the tests to prevent side effects from altering system time.
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
*/
class TimeTest extends UnitTestCase {
/**
* The mocked request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack|\PHPUnit_Framework_MockObject_MockObject
*/
protected $requestStack;
/**
* The mocked time class.
*
* @var \Drupal\Component\Datetime\Time
*/
protected $time;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack');
$this->time = new Time($this->requestStack);
}
/**
* Tests the getRequestTime method.
*
* @covers ::getRequestTime
*/
public function testGetRequestTime() {
$expected = 12345678;
$request = Request::createFromGlobals();
$request->server->set('REQUEST_TIME', $expected);
// Mocks a the request stack getting the current request.
$this->requestStack->expects($this->any())
->method('getCurrentRequest')
->willReturn($request);
$this->assertEquals($expected, $this->time->getRequestTime());
}
/**
* Tests the getRequestMicroTime method.
*
* @covers ::getRequestMicroTime
*/
public function testGetRequestMicroTime() {
$expected = 1234567.89;
$request = Request::createFromGlobals();
$request->server->set('REQUEST_TIME_FLOAT', $expected);
// Mocks a the request stack getting the current request.
$this->requestStack->expects($this->any())
->method('getCurrentRequest')
->willReturn($request);
$this->assertEquals($expected, $this->time->getRequestMicroTime());
}
/**
* Tests the getCurrentTime method.
*
* @covers ::getCurrentTime
*/
public function testGetCurrentTime() {
$expected = 12345678;
$this->assertEquals($expected, $this->time->getCurrentTime());
}
/**
* Tests the getCurrentMicroTime method.
*
* @covers ::getCurrentMicroTime
*/
public function testGetCurrentMicroTime() {
$expected = 1234567.89;
$this->assertEquals($expected, $this->time->getCurrentMicroTime());
}
}
namespace Drupal\Component\Datetime;
/**
* Shadow time() system call.
*
* @returns int
*/
function time() {
return 12345678;
}
/**
* Shadow microtime system call.
*
* @returns float
*/
function microtime() {
return 1234567.89;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment