Skip to content

Commit c490e4d

Browse files
mbabkerfranmomu
authored andcommitted
Add support for providing a PSR-20 clock to event adapters which create new DateTimeInterface objects
1 parent 91dd468 commit c490e4d

File tree

11 files changed

+129
-17
lines changed

11 files changed

+129
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ a release.
2121
### Added
2222
- SoftDeleteable: `Gedmo\SoftDeleteable\Event\PreSoftDeleteEventArgs` and
2323
`Gedmo\SoftDeleteable\Event\PostSoftDeleteEventArgs` classes.
24+
- Add support for injecting a `psr/clock` implementation into event adapters
25+
that create new `DateTimeInterface` objects (SoftDeleteable and Timestampable)
2426

2527
### Changed
2628
- Make doctrine/annotations an optional dependency.

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"doctrine/event-manager": "^1.2 || ^2.0",
4949
"doctrine/persistence": "^2.2 || ^3.0",
5050
"psr/cache": "^1 || ^2 || ^3",
51+
"psr/clock": "^1",
5152
"symfony/cache": "^5.4 || ^6.0 || ^7.0"
5253
},
5354
"require-dev": {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Doctrine Behavioral Extensions package.
5+
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace Gedmo\Mapping\Event;
11+
12+
use Psr\Clock\ClockInterface;
13+
14+
/**
15+
* Doctrine event adapter supporting a PSR-20 {@see ClockInterface}.
16+
*/
17+
interface ClockAwareAdapterInterface
18+
{
19+
public function setClock(ClockInterface $clock): void;
20+
}

src/Mapping/MappedEventSubscriber.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626
use Gedmo\Exception\InvalidArgumentException;
2727
use Gedmo\Mapping\Driver\AttributeReader;
2828
use Gedmo\Mapping\Event\AdapterInterface;
29+
use Gedmo\Mapping\Event\ClockAwareAdapterInterface;
2930
use Gedmo\ReferenceIntegrity\Mapping\Validator as ReferenceIntegrityValidator;
3031
use Gedmo\Uploadable\FilenameGenerator\FilenameGeneratorInterface;
3132
use Gedmo\Uploadable\Mapping\Validator as MappingValidator;
3233
use Psr\Cache\CacheItemPoolInterface;
34+
use Psr\Clock\ClockInterface;
3335
use Symfony\Component\Cache\Adapter\ArrayAdapter;
3436

3537
/**
@@ -95,6 +97,8 @@ abstract class MappedEventSubscriber implements EventSubscriber
9597
*/
9698
private $cacheItemPool;
9799

100+
private ?ClockInterface $clock = null;
101+
98102
public function __construct()
99103
{
100104
$parts = explode('\\', $this->getNamespace());
@@ -224,6 +228,11 @@ final public function setCacheItemPool(CacheItemPoolInterface $cacheItemPool): v
224228
$this->cacheItemPool = $cacheItemPool;
225229
}
226230

231+
final public function setClock(ClockInterface $clock): void
232+
{
233+
$this->clock = $clock;
234+
}
235+
227236
/**
228237
* Scans the objects for extended annotations
229238
* event subscribers must subscribe to loadClassMetadata event
@@ -267,6 +276,10 @@ protected function getEventAdapter(EventArgs $args)
267276
$adapterClass = 'Gedmo\\Mapping\\Event\\Adapter\\'.$m[1];
268277
}
269278
$this->adapters[$m[1]] = new $adapterClass();
279+
280+
if ($this->adapters[$m[1]] instanceof ClockAwareAdapterInterface && $this->clock instanceof ClockInterface) {
281+
$this->adapters[$m[1]]->setClock($this->clock);
282+
}
270283
}
271284
$this->adapters[$m[1]]->setEventArgs($args);
272285

src/SoftDeleteable/Mapping/Event/Adapter/ODM.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,34 @@
1111

1212
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
1313
use Gedmo\Mapping\Event\Adapter\ODM as BaseAdapterODM;
14+
use Gedmo\Mapping\Event\ClockAwareAdapterInterface;
1415
use Gedmo\SoftDeleteable\Mapping\Event\SoftDeleteableAdapter;
16+
use Psr\Clock\ClockInterface;
1517

1618
/**
1719
* Doctrine event adapter for ORM adapted
1820
* for SoftDeleteable behavior.
1921
*
2022
* @author David Buchmann <[email protected]>
2123
*/
22-
final class ODM extends BaseAdapterODM implements SoftDeleteableAdapter
24+
final class ODM extends BaseAdapterODM implements SoftDeleteableAdapter, ClockAwareAdapterInterface
2325
{
26+
/**
27+
* @var ClockInterface|null
28+
*/
29+
private ?ClockInterface $clock = null;
30+
31+
public function setClock(ClockInterface $clock): void
32+
{
33+
$this->clock = $clock;
34+
}
35+
2436
/**
2537
* @param ClassMetadata $meta
2638
*/
2739
public function getDateValue($meta, $field)
2840
{
29-
$datetime = new \DateTime();
41+
$datetime = $this->clock instanceof ClockInterface ? $this->clock->now() : new \DateTimeImmutable();
3042
$mapping = $meta->getFieldMapping($field);
3143
$type = $mapping['type'] ?? null;
3244

@@ -35,9 +47,9 @@ public function getDateValue($meta, $field)
3547
}
3648

3749
if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
38-
return \DateTimeImmutable::createFromMutable($datetime);
50+
return $datetime;
3951
}
4052

41-
return $datetime;
53+
return \DateTime::createFromImmutable($datetime);
4254
}
4355
}

src/SoftDeleteable/Mapping/Event/Adapter/ORM.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,28 @@
1313
use Doctrine\DBAL\Types\Types;
1414
use Doctrine\ORM\Mapping\ClassMetadata;
1515
use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
16+
use Gedmo\Mapping\Event\ClockAwareAdapterInterface;
1617
use Gedmo\SoftDeleteable\Mapping\Event\SoftDeleteableAdapter;
18+
use Psr\Clock\ClockInterface;
1719

1820
/**
1921
* Doctrine event adapter for ORM adapted
2022
* for SoftDeleteable behavior.
2123
*
2224
* @author David Buchmann <[email protected]>
2325
*/
24-
final class ORM extends BaseAdapterORM implements SoftDeleteableAdapter
26+
final class ORM extends BaseAdapterORM implements SoftDeleteableAdapter, ClockAwareAdapterInterface
2527
{
28+
/**
29+
* @var ClockInterface|null
30+
*/
31+
private ?ClockInterface $clock = null;
32+
33+
public function setClock(ClockInterface $clock): void
34+
{
35+
$this->clock = $clock;
36+
}
37+
2638
/**
2739
* @param ClassMetadata $meta
2840
*/
@@ -44,17 +56,17 @@ public function getDateValue($meta, $field)
4456
*/
4557
private function getRawDateValue(array $mapping)
4658
{
47-
$datetime = new \DateTime();
59+
$datetime = $this->clock instanceof ClockInterface ? $this->clock->now() : new \DateTimeImmutable();
4860
$type = $mapping['type'] ?? null;
4961

5062
if ('integer' === $type) {
5163
return (int) $datetime->format('U');
5264
}
5365

5466
if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
55-
return \DateTimeImmutable::createFromMutable($datetime);
67+
return $datetime;
5668
}
5769

58-
return $datetime;
70+
return \DateTime::createFromImmutable($datetime);
5971
}
6072
}

src/Timestampable/Mapping/Event/Adapter/ODM.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,34 @@
1111

1212
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
1313
use Gedmo\Mapping\Event\Adapter\ODM as BaseAdapterODM;
14+
use Gedmo\Mapping\Event\ClockAwareAdapterInterface;
1415
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;
16+
use Psr\Clock\ClockInterface;
1517

1618
/**
1719
* Doctrine event adapter for ODM adapted
1820
* for Timestampable behavior
1921
*
2022
* @author Gediminas Morkevicius <[email protected]>
2123
*/
22-
final class ODM extends BaseAdapterODM implements TimestampableAdapter
24+
final class ODM extends BaseAdapterODM implements TimestampableAdapter, ClockAwareAdapterInterface
2325
{
26+
/**
27+
* @var ClockInterface|null
28+
*/
29+
private ?ClockInterface $clock = null;
30+
31+
public function setClock(ClockInterface $clock): void
32+
{
33+
$this->clock = $clock;
34+
}
35+
2436
/**
2537
* @param ClassMetadata $meta
2638
*/
2739
public function getDateValue($meta, $field)
2840
{
29-
$datetime = new \DateTime();
41+
$datetime = $this->clock instanceof ClockInterface ? $this->clock->now() : new \DateTimeImmutable();
3042
$mapping = $meta->getFieldMapping($field);
3143
$type = $mapping['type'] ?? null;
3244

@@ -35,9 +47,9 @@ public function getDateValue($meta, $field)
3547
}
3648

3749
if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
38-
return \DateTimeImmutable::createFromMutable($datetime);
50+
return $datetime;
3951
}
4052

41-
return $datetime;
53+
return \DateTime::createFromImmutable($datetime);
4254
}
4355
}

src/Timestampable/Mapping/Event/Adapter/ORM.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,28 @@
1313
use Doctrine\DBAL\Types\Types;
1414
use Doctrine\ORM\Mapping\ClassMetadata;
1515
use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
16+
use Gedmo\Mapping\Event\ClockAwareAdapterInterface;
1617
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;
18+
use Psr\Clock\ClockInterface;
1719

1820
/**
1921
* Doctrine event adapter for ORM adapted
2022
* for Timestampable behavior
2123
*
2224
* @author Gediminas Morkevicius <[email protected]>
2325
*/
24-
final class ORM extends BaseAdapterORM implements TimestampableAdapter
26+
final class ORM extends BaseAdapterORM implements TimestampableAdapter, ClockAwareAdapterInterface
2527
{
28+
/**
29+
* @var ClockInterface|null
30+
*/
31+
private ?ClockInterface $clock = null;
32+
33+
public function setClock(ClockInterface $clock): void
34+
{
35+
$this->clock = $clock;
36+
}
37+
2638
/**
2739
* @param ClassMetadata $meta
2840
*/
@@ -44,17 +56,17 @@ public function getDateValue($meta, $field)
4456
*/
4557
private function getRawDateValue(array $mapping)
4658
{
47-
$datetime = new \DateTime();
59+
$datetime = $this->clock instanceof ClockInterface ? $this->clock->now() : new \DateTimeImmutable();
4860
$type = $mapping['type'] ?? null;
4961

5062
if ('integer' === $type) {
5163
return (int) $datetime->format('U');
5264
}
5365

5466
if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
55-
return \DateTimeImmutable::createFromMutable($datetime);
67+
return $datetime;
5668
}
5769

58-
return $datetime;
70+
return \DateTime::createFromImmutable($datetime);
5971
}
6072
}

tests/Gedmo/Clock.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Doctrine Behavioral Extensions package.
7+
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Gedmo\Tests;
13+
14+
use Psr\Clock\ClockInterface;
15+
16+
final class Clock implements ClockInterface
17+
{
18+
public function now(): \DateTimeImmutable
19+
{
20+
return new \DateTimeImmutable();
21+
}
22+
}

tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter;
1818
use Gedmo\SoftDeleteable\Query\TreeWalker\SoftDeleteableWalker;
1919
use Gedmo\SoftDeleteable\SoftDeleteableListener;
20+
use Gedmo\Tests\Clock;
2021
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Article;
2122
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Child;
2223
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Comment;
@@ -62,6 +63,7 @@ protected function setUp(): void
6263

6364
$evm = new EventManager();
6465
$this->softDeleteableListener = new SoftDeleteableListener();
66+
$this->softDeleteableListener->setClock(new Clock());
6567
$evm->addEventSubscriber($this->softDeleteableListener);
6668
$config = $this->getDefaultConfiguration();
6769
$config->addFilter(self::SOFT_DELETEABLE_FILTER_NAME, SoftDeleteableFilter::class);

tests/Gedmo/Timestampable/TimestampableTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Doctrine\Common\EventManager;
1515
use Doctrine\Persistence\Proxy;
16+
use Gedmo\Tests\Clock;
1617
use Gedmo\Tests\Timestampable\Fixture\Article;
1718
use Gedmo\Tests\Timestampable\Fixture\Author;
1819
use Gedmo\Tests\Timestampable\Fixture\Comment;
@@ -35,8 +36,11 @@ protected function setUp(): void
3536
{
3637
parent::setUp();
3738

39+
$listener = new TimestampableListener();
40+
$listener->setClock(new Clock());
41+
3842
$evm = new EventManager();
39-
$evm->addEventSubscriber(new TimestampableListener());
43+
$evm->addEventSubscriber($listener);
4044

4145
$this->getDefaultMockSqliteEntityManager($evm);
4246
}

0 commit comments

Comments
 (0)