Skip to content

Commit

Permalink
Merge pull request #3 from FastyBird/feature/use-interface
Browse files Browse the repository at this point in the history
Refactored to interface + separate services for easy mocking
  • Loading branch information
akadlec authored Aug 29, 2024
2 parents aa04528 + 1bc475f commit 582a987
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 47 deletions.
16 changes: 9 additions & 7 deletions .docs/en/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ This extension has some configuration options:

```neon
fbDateTimeFactory:
timezone: Europe/Prague
timeZone: Europe/Prague
system: true # Use system clock
frozen: unixtimestam or DateTimeInterface # Could be used in tests for easy date settings
```

Where:
Expand All @@ -43,20 +45,20 @@ use FastyBird\DateTimeFactory;
class YourCustomPresenter
{

/** @var DateTimeFactory\Factory */
private DateTimeFactory\Factory $dateTimeFactory;
/** @var DateTimeFactory\Clock */
private DateTimeFactory\Clock $dateTimeFactory;

public function __construct(
DateTimeFactory\Factory $dateTimeFactory
DateTimeFactory\Clock $dateTimeFactory
) {
$this->dateTimeFactory = $dateTimeFactory;
$this->dateTime = $dateTime;
}

public function actionSomethingToDo()
{
// your cool code here...

$now = $this->dateTimeFactory->getNow();
$now = $this->dateTime->getNow();

$article->setCreatedAt($now);

Expand All @@ -65,7 +67,7 @@ class YourCustomPresenter
}
```

The only one method of factory: `$dateTimeFactory->getNow()` is returning immutable DateTime object.
The only one method of factory: `$dateTime->getNow()` is returning immutable DateTime object.

***
Homepage [http://www.fastybird.com](http://www.fastybird.com) and
Expand Down
25 changes: 25 additions & 0 deletions src/Clock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types = 1);

/**
* Clock.php
*
* @license More in LICENSE.md
* @copyright https://www.fastybird.com
* @author Adam Kadlec <adam.kadlec@fastybird.com>
* @package FastyBird:DateTimeFactory!
* @subpackage common
* @since 0.1.0
*
* @date 08.03.20
*/

namespace FastyBird\DateTimeFactory;

use DateTimeInterface;

interface Clock
{

public function getNow(): DateTimeInterface;

}
27 changes: 19 additions & 8 deletions src/DI/DateTimeFactoryExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,24 @@ class DateTimeFactoryExtension extends DI\CompilerExtension
{

public static function register(
Nette\Configurator $config,
Nette\Bootstrap\Configurator $config,
string $extensionName = 'dateTimeFactory',
): void
{
$config->onCompile[] = static function (
Nette\Configurator $config,
Nette\Bootstrap\Configurator $config,
DI\Compiler $compiler,
) use ($extensionName): void {
$compiler->addExtension($extensionName, new DateTimeFactoryExtension());
$compiler->addExtension($extensionName, new self());
};
}

public function getConfigSchema(): Schema\Schema
{
return Schema\Expect::structure([
'timezone' => Schema\Expect::string('UTC'),
'timeZone' => Schema\Expect::string('UTC'),
'system' => Schema\Expect::bool(true),
'frozen' => Schema\Expect::anyOf(Schema\Expect::float(), Schema\Expect::mixed()),
]);
}

Expand All @@ -63,14 +65,23 @@ public function loadConfiguration(): void
assert($configuration instanceof stdClass);

if (
!in_array($configuration->timezone, DateTimeZone::listIdentifiers(), true)
!in_array($configuration->timeZone, DateTimeZone::listIdentifiers(), true)
) {
throw new Exceptions\InvalidArgument('Timezone have to be valid PHP timezone string');
}

$builder->addDefinition($this->prefix('datetime.factory'), new DI\Definitions\ServiceDefinition())
->setType(DateTimeFactory\Factory::class)
->setArgument('timezone', $configuration->timezone);
if ($configuration->system) {
$builder->addDefinition($this->prefix('datetime.factory'), new DI\Definitions\ServiceDefinition())
->setType(DateTimeFactory\SystemClock::class)
->setArgument('timeZone', new DateTimeZone($configuration->timeZone));
} elseif ($configuration->frozen !== null) {
$builder->addDefinition($this->prefix('datetime.factory'), new DI\Definitions\ServiceDefinition())
->setType(DateTimeFactory\FrozenClock::class)
->setArguments([
'timestamp' => $configuration->frozen,
'timeZone' => new DateTimeZone($configuration->timeZone),
]);
}
}

}
71 changes: 71 additions & 0 deletions src/FrozenClock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php declare(strict_types = 1);

/**
* FrozenClock.php
*
* @license More in LICENSE.md
* @copyright https://www.fastybird.com
* @author Adam Kadlec <adam.kadlec@fastybird.com>
* @package FastyBird:DateTimeFactory!
* @subpackage common
* @since 0.1.0
*
* @date 29.08.24
*/

namespace FastyBird\DateTimeFactory;

use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use Nette;
use function assert;
use function date_default_timezone_get;
use function floor;
use function round;

class FrozenClock implements Clock
{

use Nette\SmartObject;

private DateTimeImmutable $dt;

public function __construct(float|DateTimeInterface $timestamp, DateTimeZone|null $timeZone = null)
{
if ($timestamp instanceof DateTime) {
$dt = DateTimeImmutable::createFromMutable($timestamp);

} elseif ($timestamp instanceof DateTimeImmutable) {
$dt = $timestamp;

} else {
[$seconds, $microseconds] = $this->getParts($timestamp);

$dt = DateTimeImmutable::createFromFormat('U', (string) $seconds);
assert($dt instanceof DateTimeImmutable);

$dt = $dt->modify("+$microseconds microsecond");
}

$this->dt = $dt->setTimezone($timeZone ?? new DateTimeZone(date_default_timezone_get()));
}

public function getNow(): DateTimeInterface
{
return clone $this->dt;
}

/**
* @return array{float, float}
*/
private function getParts(float $seconds): array
{
$wholeSeconds = floor($seconds);
$microseconds = round(($seconds - $wholeSeconds) * 1E6);

return [$wholeSeconds, $microseconds];
}

}
18 changes: 8 additions & 10 deletions src/Factory.php → src/SystemClock.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php declare(strict_types = 1);

/**
* DateFactory.php
* SystemClock.php
*
* @license More in LICENSE.md
* @copyright https://www.fastybird.com
Expand All @@ -19,26 +19,24 @@
use DateTimeInterface;
use DateTimeZone;
use Nette;
use function date_default_timezone_get;

class Factory
class SystemClock implements Clock
{

use Nette\SmartObject;

private DateTimeZone $timezone;
private DateTimeZone $timeZone;

public function __construct(string $timezone = 'Europe/Prague')
public function __construct(DateTimeZone|null $timeZone = null)
{
$this->timezone = new DateTimeZone($timezone);
$this->timeZone = $timeZone ?? new DateTimeZone(date_default_timezone_get());
}

public function getNow(): DateTimeInterface
{
$dateTime = new DateTimeImmutable();

$dateTime = $dateTime->setTimezone($this->timezone);

return $dateTime;
return (new DateTimeImmutable('now'))
->setTimezone($this->timeZone);
}

}
8 changes: 4 additions & 4 deletions tests/cases/unit/ExtensionTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class ExtensionTest extends BaseMockeryTestCase
{
$container = $this->createContainer();

Assert::notNull($container->getByType(DateTimeFactory\Factory::class));
Assert::notNull($container->getByType(DateTimeFactory\SystemClock::class));
}

/**
Expand All @@ -29,11 +29,11 @@ final class ExtensionTest extends BaseMockeryTestCase
{
$rootDir = __DIR__ . '/../../..';

$config = new Nette\Configurator();
$config = new Nette\Bootstrap\Configurator();
$config->setTempDirectory(TEMP_DIR);

$config->addParameters(['container' => ['class' => 'SystemContainer_' . md5((string) time())]]);
$config->addParameters(['appDir' => $rootDir, 'wwwDir' => $rootDir]);
$config->addStaticParameters(['container' => ['class' => 'SystemContainer_' . md5((string) time())]]);
$config->addStaticParameters(['appDir' => $rootDir, 'wwwDir' => $rootDir]);

DateTimeFactory\DI\DateTimeFactoryExtension::register($config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ require_once __DIR__ . '/../../bootstrap.php';
/**
* @testCase
*/
final class DateTimeFactoryTest extends BaseMockeryTestCase
final class SystemClockTest extends BaseMockeryTestCase
{

public function testType(): void
{
$dateTimeFactory = $this->createContainer()->getByType(DateTimeFactory\Factory::class);
$dateTimeFactory = $this->createContainer()->getByType(DateTimeFactory\Clock::class);

$first = $dateTimeFactory->getNow();
$second = $dateTimeFactory->getNow();
Expand All @@ -29,7 +29,7 @@ final class DateTimeFactoryTest extends BaseMockeryTestCase

public function testGetNow(): void
{
$dateTimeFactory = $this->createContainer()->getByType(DateTimeFactory\Factory::class);
$dateTimeFactory = $this->createContainer()->getByType(DateTimeFactory\Clock::class);

$before = new DateTimeImmutable();
$first = $dateTimeFactory->getNow();
Expand All @@ -47,12 +47,12 @@ final class DateTimeFactoryTest extends BaseMockeryTestCase

public function testTimeZone(): void
{
$dateTimeFactory = $this->createContainer()->getByType(DateTimeFactory\Factory::class);
$dateTimeFactory = $this->createContainer()->getByType(DateTimeFactory\Clock::class);

Assert::same('UTC', $dateTimeFactory->getNow()->getTimezone()->getName());

$dateTimeFactory = $this->createContainer(__DIR__ . '/timezone.neon')
->getByType(DateTimeFactory\Factory::class);
->getByType(DateTimeFactory\Clock::class);

Assert::same('Europe/Amsterdam', $dateTimeFactory->getNow()->getTimezone()->getName());
}
Expand All @@ -66,13 +66,13 @@ final class DateTimeFactoryTest extends BaseMockeryTestCase
{
$rootDir = __DIR__ . '/../../';

$config = new Nette\Configurator();
$config = new Nette\Bootstrap\Configurator();
$config->setTempDirectory(TEMP_DIR);

$config->addParameters(['container' => ['class' => 'SystemContainer_' . md5((string) time())]]);
$config->addParameters(['appDir' => $rootDir, 'wwwDir' => $rootDir]);
$config->addStaticParameters(['container' => ['class' => 'SystemContainer_' . md5((string) time())]]);
$config->addStaticParameters(['appDir' => $rootDir, 'wwwDir' => $rootDir]);

if ($additionalConfig && file_exists($additionalConfig)) {
if ($additionalConfig !== null && file_exists($additionalConfig)) {
$config->addConfig($additionalConfig);
}

Expand All @@ -83,5 +83,5 @@ final class DateTimeFactoryTest extends BaseMockeryTestCase

}

$test_case = new DateTimeFactoryTest();
$test_case = new SystemClockTest();
$test_case->run();
16 changes: 8 additions & 8 deletions tests/cases/unit/timezone.neon
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#
# DateTime factory DI configuration
#
# @license More in LICENSE.md
# @copyright https://www.fastybird.com
# @author Adam Kadlec <adam.kadlec@fastybird.com>
# @package FastyBird:DateTimeFactory!
# @subpackage config
# @since 0.1.0
# @license More in LICENSE.md
# @copyright https://www.fastybird.com
# @author Adam Kadlec <adam.kadlec@fastybird.com>
# @package FastyBird:DateTimeFactory!
# @subpackage config
# @since 0.1.0
#
# @date 19.07.20
# @date 19.07.20

dateTimeFactory:
timezone: 'Europe/Amsterdam'
timeZone: 'Europe/Amsterdam'

0 comments on commit 582a987

Please sign in to comment.