mirror of
https://github.com/beste/clock.git
synced 2026-10-17 19:27:35 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
201ed087ca | ||
|
|
f3edef9cbc | ||
|
|
98d1e6f1d8 | ||
|
|
731f4c9651 |
@@ -4,7 +4,8 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- '1.x'
|
||||
- '2.x'
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
|
||||
+7
-3
@@ -1,8 +1,12 @@
|
||||
# CHANGELOG
|
||||
|
||||
## [Unreleased]
|
||||
## 2.1.0 - 2022-04-22
|
||||
Adds the `WrappingClock` which allows using an object with a `now()` method returning a `DateTimeImmutable` object
|
||||
as a "real" clock.
|
||||
|
||||
## 2.0.0 - 2022-04-20
|
||||
This release introduces a compatibility layer with the PSR-20 draft, allowing us to already
|
||||
get some interoperability by depending on a shared interface.
|
||||
|
||||
## 1.0.0 - 2021-12-10
|
||||
Initial Release
|
||||
|
||||
[Unreleased]: https://github.com/beste/clock/compare/1.0.0...main
|
||||
|
||||
@@ -15,6 +15,7 @@ A collection of Clock implementations.
|
||||
- [`UTCClock`](#utcclock) - The clock that you should™ use
|
||||
- [`FrozenClock`](#frozenclock) - A clock that stopped moving (perfect for tests)
|
||||
- [`MinuteClock`](#minuteclock) - Who cares about seconds or even less?
|
||||
- [`WrappingClock`](#wrappingclock) - Allows wrapping a non-clock with a `now()` method in a clock
|
||||
- [Running Tests](#running-tests)
|
||||
|
||||
## Installation
|
||||
@@ -136,7 +137,42 @@ printf("For %s, the minute clock still returns %s\n",
|
||||
$frozenClock->now()->format('H:i:s'),
|
||||
$clock->now()->format('H:i:s')
|
||||
);
|
||||
```
|
||||
|
||||
### `WrappingClock`
|
||||
|
||||
If you already have an object with a `now()` method returning a `DateTimeImmutable` object, you can wrap it
|
||||
in a `WrappingClock` to make it a "real" Clock.
|
||||
|
||||
as a "real" clock.
|
||||
|
||||
```php
|
||||
# examples/wrapping_clock.php
|
||||
|
||||
use Beste\Clock\WrappingClock;
|
||||
|
||||
// Create a frozen $now so that we can test the wrapping clock.
|
||||
$now = new DateTimeImmutable('2012-04-24 12:00:00');
|
||||
|
||||
// Create an object that is NOT a clock, but has a now() method returning the frozen $now.
|
||||
$clock = new class($now) {
|
||||
private \DateTimeImmutable $now;
|
||||
|
||||
public function __construct(\DateTimeImmutable $now)
|
||||
{
|
||||
$this->now = $now;
|
||||
}
|
||||
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
return $this->now;
|
||||
}
|
||||
};
|
||||
|
||||
// We can now wrap the object in a clock.
|
||||
$wrappedClock = WrappingClock::wrapping($clock);
|
||||
|
||||
assert($now->format(DATE_ATOM) === $wrappedClock->now()->format(DATE_ATOM));
|
||||
```
|
||||
|
||||
## Running tests
|
||||
|
||||
+6
-3
@@ -11,7 +11,8 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "~7.4.0 || ~8.0.0 || ~8.1.0"
|
||||
"php": "~7.4.0 || ~8.0.0 || ~8.1.0",
|
||||
"stella-maris/clock": "^0.1.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
@@ -27,7 +28,6 @@
|
||||
"Beste\\Clock\\": "src/Clock"
|
||||
},
|
||||
"files": [
|
||||
"src/psr-polyfill.php",
|
||||
"src/Clock.php"
|
||||
]
|
||||
},
|
||||
@@ -40,7 +40,10 @@
|
||||
"psr/clock-implementation": "1.0"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"phpstan/extension-installer": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Beste\Clock\WrappingClock;
|
||||
|
||||
// Create a frozen $now so that we can test the wrapping clock.
|
||||
$now = new DateTimeImmutable('2012-04-24 12:00:00');
|
||||
|
||||
// Create an object that is NOT a clock, but has a now() method returning the frozen $now.
|
||||
$clock = new class($now) {
|
||||
private \DateTimeImmutable $now;
|
||||
|
||||
public function __construct(\DateTimeImmutable $now)
|
||||
{
|
||||
$this->now = $now;
|
||||
}
|
||||
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
return $this->now;
|
||||
}
|
||||
};
|
||||
|
||||
// We can now wrap the object in a clock.
|
||||
$wrappedClock = WrappingClock::wrapping($clock);
|
||||
|
||||
assert($now->format(DATE_ATOM) === $wrappedClock->now()->format(DATE_ATOM));
|
||||
@@ -7,5 +7,3 @@ parameters:
|
||||
|
||||
tmpDir: .build/phpstan/
|
||||
|
||||
bootstrapFiles:
|
||||
- ./src/psr-polyfill.php
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Beste;
|
||||
|
||||
use Psr\Clock\ClockInterface;
|
||||
use StellaMaris\Clock\ClockInterface;
|
||||
|
||||
interface Clock extends ClockInterface
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Beste\Clock;
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use StellaMaris\Clock\ClockInterface;
|
||||
|
||||
final class FrozenClock implements Clock
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use StellaMaris\Clock\ClockInterface;
|
||||
|
||||
final class MinuteClock implements Clock
|
||||
{
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock;
|
||||
|
||||
use Beste\Clock;
|
||||
use DateTimeImmutable;
|
||||
use StellaMaris\Clock\ClockInterface;
|
||||
|
||||
final class WrappingClock implements Clock
|
||||
{
|
||||
private ClockInterface $wrappedClock;
|
||||
|
||||
private function __construct(ClockInterface $wrappedClock)
|
||||
{
|
||||
$this->wrappedClock = $wrappedClock;
|
||||
}
|
||||
|
||||
public static function wrapping(object $clock): self
|
||||
{
|
||||
if ($clock instanceof ClockInterface) {
|
||||
return new self($clock);
|
||||
}
|
||||
|
||||
if (!method_exists($clock, 'now')) {
|
||||
throw new \InvalidArgumentException('$clock must implement StellaMaris\Clock\ClockInterface or have a now() method');
|
||||
}
|
||||
|
||||
if (!($clock->now() instanceof DateTimeImmutable)) {
|
||||
throw new \InvalidArgumentException('$clock->now() must return a DateTimeImmutable');
|
||||
}
|
||||
|
||||
$wrappedClock = new class($clock) implements ClockInterface {
|
||||
private object $clock;
|
||||
|
||||
public function __construct(object $clock)
|
||||
{
|
||||
$this->clock = $clock;
|
||||
}
|
||||
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
assert(method_exists($this->clock, 'now'));
|
||||
|
||||
$now = $this->clock->now();
|
||||
|
||||
assert($now instanceof \DateTimeImmutable);
|
||||
|
||||
return $now;
|
||||
}
|
||||
};
|
||||
|
||||
return new self($wrappedClock);
|
||||
}
|
||||
|
||||
public function now(): DateTimeImmutable
|
||||
{
|
||||
return $this->wrappedClock->now();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Psr\Clock;
|
||||
|
||||
if (class_exists('\Psr\Clock\ClockInterface')) {
|
||||
return;
|
||||
}
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface ClockInterface
|
||||
{
|
||||
/**
|
||||
* Returns the current time as a DateTimeImmutable Object
|
||||
*/
|
||||
public function now(): DateTimeImmutable;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Beste\Clock\Tests;
|
||||
use Beste\Clock\FrozenClock;
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use StellaMaris\Clock\ClockInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Beste\Clock\Tests;
|
||||
use Beste\Clock\MinuteClock;
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use StellaMaris\Clock\ClockInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Beste\Clock\Tests;
|
||||
|
||||
use Beste\Clock\FrozenClock;
|
||||
use Beste\Clock\WrappingClock;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversDefaultClass \Beste\Clock\WrappingClock
|
||||
*/
|
||||
final class WrappingClockTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @covers ::__construct
|
||||
* @covers ::create
|
||||
* @covers ::now
|
||||
*/
|
||||
public function itWrapsAClockInterface(): void
|
||||
{
|
||||
$clock = FrozenClock::fromUTC();
|
||||
|
||||
$wrappedClock = WrappingClock::wrapping($clock);
|
||||
|
||||
self::assertSame(
|
||||
$clock->now()->format(DATE_ATOM),
|
||||
$wrappedClock->now()->format(DATE_ATOM)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @covers ::__construct
|
||||
* @covers ::create
|
||||
* @covers ::now
|
||||
*/
|
||||
public function itWrapsAnObjectWithANowMethod(): void
|
||||
{
|
||||
$now = FrozenClock::fromUTC()->now();
|
||||
|
||||
$clock = new class($now) {
|
||||
private \DateTimeImmutable $now;
|
||||
|
||||
public function __construct(\DateTimeImmutable $now)
|
||||
{
|
||||
$this->now = $now;
|
||||
}
|
||||
|
||||
public function now(): \DateTimeImmutable
|
||||
{
|
||||
return $this->now;
|
||||
}
|
||||
};
|
||||
|
||||
$wrappedClock = WrappingClock::wrapping($clock);
|
||||
|
||||
self::assertSame(
|
||||
$now->format(DATE_ATOM),
|
||||
$wrappedClock->now()->format(DATE_ATOM)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @covers ::create
|
||||
*/
|
||||
public function itRejectsObjectsWithANowMethodReturningANonDateTimeImmutable(): void
|
||||
{
|
||||
$clock = new class() {
|
||||
public function now(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
};
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('$clock->now() must return a DateTimeImmutable');
|
||||
|
||||
WrappingClock::wrapping($clock);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user