From 438e8f0fdb953a928d76d5a14376da177c605230 Mon Sep 17 00:00:00 2001 From: Jan Lam Date: Thu, 11 Jun 2026 15:47:34 +0200 Subject: [PATCH 1/6] Support the Revision attribute, dropping PHP<8.3 support --- .github/workflows/main.yaml | 2 +- composer.json | 2 +- src/Attributes/Revision.php | 14 ++++ src/Listener/RevisionListener.php | 66 +++++++++++++---- src/Resolver/RevisionResolver.php | 17 ++--- src/Resolver/RevisionResolverInterface.php | 9 +-- src/Revision.php | 2 + test/Listener/EntityWithAttribute.php | 31 ++++++++ test/Listener/RevisionListenerTest.php | 82 ++++++++++++++++++++-- 9 files changed, 191 insertions(+), 34 deletions(-) create mode 100644 src/Attributes/Revision.php create mode 100644 test/Listener/EntityWithAttribute.php diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index f925e3c..b7896e1 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['8.3', '8.4'] name: PHP ${{ matrix.php-versions }} steps: - uses: actions/checkout@v2 diff --git a/composer.json b/composer.json index 7978623..7836754 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "license": "MIT", "minimum-stability": "stable", "require": { - "php": "^7.3|^8.0", + "php": "^8.3", "doctrine/orm": "^2.4.0", "hostnet/entity-tracker-component": "^1.2.0||^2.0.0", "psr/log": "^1.0.0|^2.0.0|^3.0.0" diff --git a/src/Attributes/Revision.php b/src/Attributes/Revision.php new file mode 100644 index 0000000..b84d3f0 --- /dev/null +++ b/src/Attributes/Revision.php @@ -0,0 +1,14 @@ +revision = $this->factory->createRevision(new \DateTime()); @@ -74,10 +81,8 @@ public function preFlush(PreFlushEventArgs $event) * in the same flush if they use @Revision. This method * can safely be overwritten if you prefer a Revision * per Request. - * - * @param PreFlushEventArgs $event */ - public function postFlush(PostFlushEventArgs $event) + public function postFlush(PostFlushEventArgs $event): void { $this->revision = null; } @@ -85,7 +90,7 @@ public function postFlush(PostFlushEventArgs $event) /** * @param EntityChangedEvent $event */ - public function entityChanged(EntityChangedEvent $event) + public function entityChanged(EntityChangedEvent $event): void { if (!$this->shouldBePersisted($event)) { return; @@ -112,15 +117,12 @@ public function entityChanged(EntityChangedEvent $event) * * @param EntityChangedEvent $event */ - private function shouldBePersisted(EntityChangedEvent $event) + private function shouldBePersisted(EntityChangedEvent $event): bool { - if (!($entity = $event->getCurrentEntity()) instanceof RevisionableInterface) { - return false; - } - - $em = $event->getEntityManager(); + $entity = $event->getCurrentEntity(); + $em = $event->getEntityManager(); - if (null === $this->resolver->getRevisionAnnotation($em, $entity)) { + if (!$this->isRevision($em, $entity)) { return false; } @@ -133,4 +135,42 @@ private function shouldBePersisted(EntityChangedEvent $event) return true; } + + private function isRevision($em, $entity): bool + { + $class = get_class($entity); + if (array_key_exists($class, $this->is_revision_cache)) { + return $this->is_revision_cache[$class]; + } + + if (!($entity instanceof RevisionableInterface)) { + $this->is_revision_cache[$class] = false; + + return false; + } + + if (null !== $this->resolver->getRevisionAnnotation($em, $entity)) { + $this->is_revision_cache[$class] = true; + + return true; + } + + if ($this->hasRevisionAttribute($entity)) { + $this->is_revision_cache[$class] = true; + + return true; + } + + $this->is_revision_cache[$class] = false; + + return false; + } + + private function hasRevisionAttribute($entity): bool + { + $reflection = new \ReflectionClass($entity); + $attributes = $reflection->getAttributes(Revision::class); + + return !empty($attributes); + } } diff --git a/src/Resolver/RevisionResolver.php b/src/Resolver/RevisionResolver.php index 1a76c2b..a15dd06 100644 --- a/src/Resolver/RevisionResolver.php +++ b/src/Resolver/RevisionResolver.php @@ -7,23 +7,16 @@ namespace Hostnet\Component\EntityRevision\Resolver; use Doctrine\ORM\EntityManagerInterface; +use Hostnet\Component\EntityRevision\Revision; use Hostnet\Component\EntityTracker\Provider\EntityAnnotationMetadataProvider; class RevisionResolver implements RevisionResolverInterface { - /** - * @var string - */ - private $annotation = 'Hostnet\Component\EntityRevision\Revision'; - /** * @var EntityAnnotationMetadataProvider */ private $provider; - /** - * @param EntityMetadataProvider $provider - */ public function __construct(EntityAnnotationMetadataProvider $provider) { $this->provider = $provider; @@ -31,16 +24,18 @@ public function __construct(EntityAnnotationMetadataProvider $provider) /** * @see \Hostnet\Component\EntityRevision\Resolver\RevisionResolverInterface::getRevisionAnnotation() + * + * @deprecated Please use the Revision attribute instead */ - public function getRevisionAnnotation(EntityManagerInterface $em, $entity) + public function getRevisionAnnotation(EntityManagerInterface $em, $entity): ?Revision { - return $this->provider->getAnnotationFromEntity($em, $entity, $this->annotation); + return $this->provider->getAnnotationFromEntity($em, $entity, Revision::class); } /** * @see \Hostnet\Component\EntityRevision\Resolver\RevisionResolverInterface::getRevisionableFields() */ - public function getRevisionableFields(EntityManagerInterface $em, $entity) + public function getRevisionableFields(EntityManagerInterface $em, $entity): array { $metadata = $em->getClassMetadata(get_class($entity)); return array_merge($metadata->getFieldNames(), $metadata->getAssociationNames()); diff --git a/src/Resolver/RevisionResolverInterface.php b/src/Resolver/RevisionResolverInterface.php index 3b49a84..0ea8ef1 100644 --- a/src/Resolver/RevisionResolverInterface.php +++ b/src/Resolver/RevisionResolverInterface.php @@ -7,6 +7,7 @@ namespace Hostnet\Component\EntityRevision\Resolver; use Doctrine\ORM\EntityManagerInterface; +use Hostnet\Component\EntityRevision\Revision; interface RevisionResolverInterface { @@ -15,12 +16,12 @@ interface RevisionResolverInterface * * @return string[] */ - public function getRevisionableFields(EntityManagerInterface $em, $entity); + public function getRevisionableFields(EntityManagerInterface $em, $entity): array; /** - * Return the revision annotation + * Return the revision annotation or null * - * @return Mutation + * @deprecated */ - public function getRevisionAnnotation(EntityManagerInterface $em, $entity); + public function getRevisionAnnotation(EntityManagerInterface $em, $entity): ?Revision; } diff --git a/src/Revision.php b/src/Revision.php index 5b5e50a..7cba5f1 100644 --- a/src/Revision.php +++ b/src/Revision.php @@ -11,6 +11,8 @@ /** * @Annotation * @Target({"CLASS"}) + * + * @deprecated Please use the attribute instead */ class Revision extends Tracked { diff --git a/test/Listener/EntityWithAttribute.php b/test/Listener/EntityWithAttribute.php new file mode 100644 index 0000000..1b42cca --- /dev/null +++ b/test/Listener/EntityWithAttribute.php @@ -0,0 +1,31 @@ +call_count++; + } + + public function getRevision(): void + { + } + + public function getCallCount(): int + { + return $this->call_count; + } +} diff --git a/test/Listener/RevisionListenerTest.php b/test/Listener/RevisionListenerTest.php index 1d47730..290c170 100644 --- a/test/Listener/RevisionListenerTest.php +++ b/test/Listener/RevisionListenerTest.php @@ -12,7 +12,6 @@ use Hostnet\Component\EntityRevision\Resolver\RevisionResolverInterface; use Hostnet\Component\EntityRevision\Revision; use Hostnet\Component\EntityRevision\RevisionableInterface; -use Hostnet\Component\EntityRevision\RevisionInterface; use Hostnet\Component\EntityTracker\Event\EntityChangedEvent; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -25,8 +24,8 @@ class RevisionListenerTest extends TestCase private $em; private $factory; private $entity; - private $revision; private $resolver; + private $logger; public function setUp(): void { @@ -34,7 +33,6 @@ public function setUp(): void $this->factory = $this->createMock(RevisionFactoryInterface::class); $this->resolver = $this->createMock(RevisionResolverInterface::class); $this->entity = $this->createMock(RevisionableInterface::class); - $this->revision = $this->createMock(RevisionInterface::class); $this->logger = $this->createMock(LoggerInterface::class); } @@ -121,7 +119,7 @@ public function testOnEntityChangedNoTrackedMutations(): void $listener->entityChanged($event); } - public function testOnEntityChangedNoRevision(): void + public function testOnEntityChangedNoRevisionPresentOnFlush(): void { $history = new Revision(); @@ -191,4 +189,80 @@ public function testOnEntityChanged(): void $listener->entityChanged($event); $listener->entityChanged($event); } + + public function testOnEntityChangedInterfaceOnlyNoAnnotationNoAttribute(): void + { + $this->resolver + ->expects($this->any()) + ->method('getRevisionAnnotation') + ->willReturn(null); + + $this->resolver + ->expects($this->never()) + ->method('getRevisionableFields'); + + $this->factory + ->expects($this->never()) + ->method('createRevision'); + + $this->em + ->expects($this->never()) + ->method('persist'); + + $this->entity + ->expects($this->never()) + ->method('setRevision'); + + $event = new EntityChangedEvent($this->em, $this->entity, $this->entity, ['something']); + $doctrine_event = $this + ->getMockBuilder('Doctrine\ORM\Event\PostFlushEventArgs') + ->disableOriginalConstructor() + ->getMock(); + + $listener = new RevisionListener($this->resolver, $this->factory); + $listener->entityChanged($event); + $listener->postFlush($doctrine_event); + } + + public function testOnEntityChangedAttribute(): void + { + $r1 = $this->createMock('Hostnet\Component\EntityRevision\RevisionInterface'); + $r2 = $this->createMock('Hostnet\Component\EntityRevision\RevisionInterface'); + + $this->resolver + ->expects($this->any()) + ->method('getRevisionAnnotation') + ->willReturn(null); + + $this->resolver + ->expects($this->any()) + ->method('getRevisionableFields') + ->willReturn(['something']); + + $this->factory + ->expects($this->exactly(2)) + ->method('createRevision') + ->willReturnOnConsecutiveCalls($r1, $r2); + + $this->em + ->expects($this->any()) + ->method('persist') + ->withConsecutive([$this->identicalTo($r1)], [$this->identicalTo($r2)]); + + $entity = new EntityWithAttribute(); + + $event = new EntityChangedEvent($this->em, $entity, $entity, ['something']); + $doctrine_event = $this + ->getMockBuilder('Doctrine\ORM\Event\PostFlushEventArgs') + ->disableOriginalConstructor() + ->getMock(); + + $listener = new RevisionListener($this->resolver, $this->factory); + $listener->entityChanged($event); + $listener->postFlush($doctrine_event); + $listener->entityChanged($event); + $listener->entityChanged($event); + + self::assertSame(3, $entity->getCallCount()); + } } From b082b0b838ce1e5d21b6bcce6ee0058e8e6b08a1 Mon Sep 17 00:00:00 2001 From: Jan Lam Date: Thu, 11 Jun 2026 16:04:36 +0200 Subject: [PATCH 2/6] Add testcase showing missing dependency --- test/Attributes/RevisionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/Attributes/RevisionTest.php diff --git a/test/Attributes/RevisionTest.php b/test/Attributes/RevisionTest.php new file mode 100644 index 0000000..e19a15e --- /dev/null +++ b/test/Attributes/RevisionTest.php @@ -0,0 +1,19 @@ + Date: Tue, 16 Jun 2026 16:10:55 +0200 Subject: [PATCH 3/6] Support Doctrine proxy objects --- composer.json | 3 +- src/Listener/RevisionListener.php | 84 +++++++--------------- src/Resolver/RevisionResolver.php | 12 +++- src/Resolver/RevisionResolverInterface.php | 10 ++- test/Listener/RevisionListenerTest.php | 16 +++-- test/Resolver/RevisionResolverTest.php | 20 +++++- 6 files changed, 74 insertions(+), 71 deletions(-) diff --git a/composer.json b/composer.json index 7836754..d22e548 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ "php": "^8.3", "doctrine/orm": "^2.4.0", "hostnet/entity-tracker-component": "^1.2.0||^2.0.0", - "psr/log": "^1.0.0|^2.0.0|^3.0.0" + "psr/log": "^1.0.0|^2.0.0|^3.0.0", + "symfony/cache": "^6.4|^7.4" }, "require-dev": { "hostnet/phpcs-tool": "^9.1.0", diff --git a/src/Listener/RevisionListener.php b/src/Listener/RevisionListener.php index a497211..392abe4 100644 --- a/src/Listener/RevisionListener.php +++ b/src/Listener/RevisionListener.php @@ -8,55 +8,28 @@ use Doctrine\ORM\Event\PostFlushEventArgs; use Doctrine\ORM\Event\PreFlushEventArgs; -use Hostnet\Component\EntityRevision\Attributes\Revision; use Hostnet\Component\EntityRevision\Factory\RevisionFactoryInterface; use Hostnet\Component\EntityRevision\Resolver\RevisionResolverInterface; use Hostnet\Component\EntityRevision\RevisionableInterface; use Hostnet\Component\EntityRevision\RevisionInterface; use Hostnet\Component\EntityTracker\Event\EntityChangedEvent; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; +use Symfony\Component\Cache\Adapter\ArrayAdapter; class RevisionListener { - /** - * @var RevisionResolverInterface - */ - private $resolver; - - /** - * @var RevisionFactoryInterface - */ - private $factory; - - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var RevisionInterface - */ - private $revision; - - /** - * Caches the class names to prevent iterating over attribute and annotations again on the next entity. - */ - private array $is_revision_cache = []; + private ?RevisionInterface $revision = null; - /** - * @param RevisionResolverInterface $resolver - * @param RevisionFactoryInterface $factory - * @param LoggerInterface $logger - */ public function __construct( - RevisionResolverInterface $resolver, - RevisionFactoryInterface $factory, - LoggerInterface $logger = null + private RevisionResolverInterface $resolver, + private RevisionFactoryInterface $factory, + private ?LoggerInterface $logger = null, + private ?CacheItemPoolInterface $is_revision_cache = new ArrayAdapter() ) { - $this->resolver = $resolver; - $this->factory = $factory; - $this->logger = $logger ?: new NullLogger(); + $this->logger = $logger ?: new NullLogger(); } /** @@ -65,7 +38,8 @@ public function __construct( * Used to group all entities to the same revision * in the same flush if they use @Revision * - * @deprecated functionality was moved to entityChanged and postFlush + * @deprecated functionality was moved to entityChanged and postFlush, will be removed when removing + * doctrine/annotations. * @param PreFlushEventArgs $event */ public function preFlush(PreFlushEventArgs $event): void @@ -138,39 +112,33 @@ private function shouldBePersisted(EntityChangedEvent $event): bool private function isRevision($em, $entity): bool { - $class = get_class($entity); - if (array_key_exists($class, $this->is_revision_cache)) { - return $this->is_revision_cache[$class]; + $cache_key = base64_encode('REVISION-' . get_class($entity)); + $cached_item = $this->is_revision_cache->getItem($cache_key); + + if ($cached_item->isHit()) { + return $cached_item->get(); } if (!($entity instanceof RevisionableInterface)) { - $this->is_revision_cache[$class] = false; - - return false; + return $this->save($cached_item, false); } - if (null !== $this->resolver->getRevisionAnnotation($em, $entity)) { - $this->is_revision_cache[$class] = true; - - return true; + if (null !== $this->resolver->getRevisionAttribute($em, $entity)) { + return $this->save($cached_item, true); } - if ($this->hasRevisionAttribute($entity)) { - $this->is_revision_cache[$class] = true; - - return true; + if (null !== $this->resolver->getRevisionAnnotation($em, $entity)) { + return $this->save($cached_item, true); } - $this->is_revision_cache[$class] = false; - - return false; + return $this->save($cached_item, false); } - private function hasRevisionAttribute($entity): bool + private function save(CacheItemInterface $item, bool $value): bool { - $reflection = new \ReflectionClass($entity); - $attributes = $reflection->getAttributes(Revision::class); + $item->set($value); + $this->is_revision_cache->save($item); - return !empty($attributes); + return $value; } } diff --git a/src/Resolver/RevisionResolver.php b/src/Resolver/RevisionResolver.php index a15dd06..0431be0 100644 --- a/src/Resolver/RevisionResolver.php +++ b/src/Resolver/RevisionResolver.php @@ -7,7 +7,8 @@ namespace Hostnet\Component\EntityRevision\Resolver; use Doctrine\ORM\EntityManagerInterface; -use Hostnet\Component\EntityRevision\Revision; +use Hostnet\Component\EntityRevision\Attributes\Revision; +use Hostnet\Component\EntityRevision\Revision as RevisionAnnotation; use Hostnet\Component\EntityTracker\Provider\EntityAnnotationMetadataProvider; class RevisionResolver implements RevisionResolverInterface @@ -27,9 +28,14 @@ public function __construct(EntityAnnotationMetadataProvider $provider) * * @deprecated Please use the Revision attribute instead */ - public function getRevisionAnnotation(EntityManagerInterface $em, $entity): ?Revision + public function getRevisionAnnotation(EntityManagerInterface $em, $entity): ?RevisionAnnotation { - return $this->provider->getAnnotationFromEntity($em, $entity, Revision::class); + return $this->provider->getAnnotationFromEntity($em, $entity, RevisionAnnotation::class); + } + + public function getRevisionAttribute(EntityManagerInterface $em, $entity): ?Revision + { + return $this->provider->getAttributeFromEntity(Revision::class, $em, $entity); } /** diff --git a/src/Resolver/RevisionResolverInterface.php b/src/Resolver/RevisionResolverInterface.php index 0ea8ef1..2b29250 100644 --- a/src/Resolver/RevisionResolverInterface.php +++ b/src/Resolver/RevisionResolverInterface.php @@ -7,7 +7,8 @@ namespace Hostnet\Component\EntityRevision\Resolver; use Doctrine\ORM\EntityManagerInterface; -use Hostnet\Component\EntityRevision\Revision; +use Hostnet\Component\EntityRevision\Attributes\Revision; +use Hostnet\Component\EntityRevision\Revision as RevisionAnnotation; interface RevisionResolverInterface { @@ -23,5 +24,10 @@ public function getRevisionableFields(EntityManagerInterface $em, $entity): arra * * @deprecated */ - public function getRevisionAnnotation(EntityManagerInterface $em, $entity): ?Revision; + public function getRevisionAnnotation(EntityManagerInterface $em, $entity): ?RevisionAnnotation; + + /** + * Return the revision attribute or null + */ + public function getRevisionAttribute(EntityManagerInterface $em, $entity): ?Revision; } diff --git a/test/Listener/RevisionListenerTest.php b/test/Listener/RevisionListenerTest.php index 290c170..46b063f 100644 --- a/test/Listener/RevisionListenerTest.php +++ b/test/Listener/RevisionListenerTest.php @@ -8,9 +8,10 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Event\PreFlushEventArgs; +use Hostnet\Component\EntityRevision\Attributes\Revision; use Hostnet\Component\EntityRevision\Factory\RevisionFactoryInterface; use Hostnet\Component\EntityRevision\Resolver\RevisionResolverInterface; -use Hostnet\Component\EntityRevision\Revision; +use Hostnet\Component\EntityRevision\Revision as RevisionAnnotation; use Hostnet\Component\EntityRevision\RevisionableInterface; use Hostnet\Component\EntityTracker\Event\EntityChangedEvent; use PHPUnit\Framework\TestCase; @@ -78,7 +79,7 @@ public function testOnEntityChangedNoRevisionFields(): void $this->resolver ->expects($this->once()) ->method('getRevisionAnnotation') - ->willReturn(new Revision()); + ->willReturn(new RevisionAnnotation()); $this->resolver ->expects($this->once()) @@ -99,7 +100,7 @@ public function testOnEntityChangedNoTrackedMutations(): void $this->resolver ->expects($this->exactly(2)) ->method('getRevisionAnnotation') - ->willReturn(new Revision()); + ->willReturn(new RevisionAnnotation()); $this->resolver ->expects($this->exactly(2)) @@ -121,7 +122,7 @@ public function testOnEntityChangedNoTrackedMutations(): void public function testOnEntityChangedNoRevisionPresentOnFlush(): void { - $history = new Revision(); + $history = new RevisionAnnotation(); $this->resolver ->expects($this->once()) @@ -151,7 +152,7 @@ public function testOnEntityChanged(): void $r1 = $this->createMock('Hostnet\Component\EntityRevision\RevisionInterface'); $r2 = $this->createMock('Hostnet\Component\EntityRevision\RevisionInterface'); - $history = new Revision(); + $history = new RevisionAnnotation(); $this->resolver ->expects($this->any()) ->method('getRevisionAnnotation') @@ -234,6 +235,11 @@ public function testOnEntityChangedAttribute(): void ->method('getRevisionAnnotation') ->willReturn(null); + $this->resolver + ->expects($this->once()) + ->method('getRevisionAttribute') + ->willReturn(new Revision()); + $this->resolver ->expects($this->any()) ->method('getRevisionableFields') diff --git a/test/Resolver/RevisionResolverTest.php b/test/Resolver/RevisionResolverTest.php index 6bab4e0..9c3a04e 100644 --- a/test/Resolver/RevisionResolverTest.php +++ b/test/Resolver/RevisionResolverTest.php @@ -8,7 +8,8 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; -use Hostnet\Component\EntityRevision\Revision; +use Hostnet\Component\EntityRevision\Attributes\Revision; +use Hostnet\Component\EntityRevision\Revision as RevisionAnnotation; use Hostnet\Component\EntityTracker\Provider\EntityAnnotationMetadataProvider; use PHPUnit\Framework\TestCase; @@ -43,7 +44,7 @@ public function testGetRevisionAnnotation(): void $this->provider ->expects($this->once()) ->method('getAnnotationFromEntity') - ->with($this->em, $entity, Revision::class); + ->with($this->em, $entity, RevisionAnnotation::class); $this->resolver->getRevisionAnnotation($this->em, $entity); } @@ -63,4 +64,19 @@ public function testGetRevisionableFields(): void $this->assertEquals(['id', 'test'], $this->resolver->getRevisionableFields($this->em, $entity)); } + + public function testGetRevisionAttribute(): void + { + $entity = new \stdClass(); + + $attribute = new Revision(); + + $this->provider + ->expects($this->once()) + ->method('getAttributeFromEntity') + ->with(Revision::class, $this->em, $entity) + ->willReturn($attribute); + + self::assertSame($attribute, $this->resolver->getRevisionAttribute($this->em, $entity)); + } } From 2cf740b34ff9c000a9ae873f80380f37b22fa96b Mon Sep 17 00:00:00 2001 From: Jan Lam Date: Wed, 17 Jun 2026 11:21:54 +0200 Subject: [PATCH 4/6] Update entity-tracker-component --- composer.json | 2 +- src/Resolver/RevisionResolver.php | 10 ++-------- src/RevisionInterface.php | 3 +++ src/RevisionableInterface.php | 3 +++ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index d22e548..183437a 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "require": { "php": "^8.3", "doctrine/orm": "^2.4.0", - "hostnet/entity-tracker-component": "^1.2.0||^2.0.0", + "hostnet/entity-tracker-component": "^2.3.0", "psr/log": "^1.0.0|^2.0.0|^3.0.0", "symfony/cache": "^6.4|^7.4" }, diff --git a/src/Resolver/RevisionResolver.php b/src/Resolver/RevisionResolver.php index 0431be0..d14bcef 100644 --- a/src/Resolver/RevisionResolver.php +++ b/src/Resolver/RevisionResolver.php @@ -9,18 +9,12 @@ use Doctrine\ORM\EntityManagerInterface; use Hostnet\Component\EntityRevision\Attributes\Revision; use Hostnet\Component\EntityRevision\Revision as RevisionAnnotation; -use Hostnet\Component\EntityTracker\Provider\EntityAnnotationMetadataProvider; +use Hostnet\Component\EntityTracker\Provider\EntityMetadataProvider; class RevisionResolver implements RevisionResolverInterface { - /** - * @var EntityAnnotationMetadataProvider - */ - private $provider; - - public function __construct(EntityAnnotationMetadataProvider $provider) + public function __construct(private EntityMetadataProvider $provider) { - $this->provider = $provider; } /** diff --git a/src/RevisionInterface.php b/src/RevisionInterface.php index ea857c3..b110a10 100644 --- a/src/RevisionInterface.php +++ b/src/RevisionInterface.php @@ -6,6 +6,9 @@ namespace Hostnet\Component\EntityRevision; +/** + * @TODO: add returntypehints on next BC break, when removing doctrine/annotation support + */ interface RevisionInterface { /** diff --git a/src/RevisionableInterface.php b/src/RevisionableInterface.php index 0499a9f..ac0ec86 100644 --- a/src/RevisionableInterface.php +++ b/src/RevisionableInterface.php @@ -6,6 +6,9 @@ namespace Hostnet\Component\EntityRevision; +/** + * @TODO: add returntypehints on next BC break, when removing doctrine/annotation support + */ interface RevisionableInterface { /** From 33fedb47d17f30aaf3d4fa2745cf5aa911920dc3 Mon Sep 17 00:00:00 2001 From: Jan Lam Date: Wed, 17 Jun 2026 11:28:27 +0200 Subject: [PATCH 5/6] Remove unnecessary test class --- test/Listener/EntityWithAttribute.php | 31 -------------------------- test/Listener/RevisionListenerTest.php | 9 ++++---- 2 files changed, 5 insertions(+), 35 deletions(-) delete mode 100644 test/Listener/EntityWithAttribute.php diff --git a/test/Listener/EntityWithAttribute.php b/test/Listener/EntityWithAttribute.php deleted file mode 100644 index 1b42cca..0000000 --- a/test/Listener/EntityWithAttribute.php +++ /dev/null @@ -1,31 +0,0 @@ -call_count++; - } - - public function getRevision(): void - { - } - - public function getCallCount(): int - { - return $this->call_count; - } -} diff --git a/test/Listener/RevisionListenerTest.php b/test/Listener/RevisionListenerTest.php index 46b063f..871a3f4 100644 --- a/test/Listener/RevisionListenerTest.php +++ b/test/Listener/RevisionListenerTest.php @@ -255,9 +255,12 @@ public function testOnEntityChangedAttribute(): void ->method('persist') ->withConsecutive([$this->identicalTo($r1)], [$this->identicalTo($r2)]); - $entity = new EntityWithAttribute(); + $this->entity + ->expects($this->exactly(3)) + ->method('setRevision') + ->withConsecutive([$this->identicalTo($r1)], [$this->identicalTo($r2)], [$this->identicalTo($r2)]); - $event = new EntityChangedEvent($this->em, $entity, $entity, ['something']); + $event = new EntityChangedEvent($this->em, $this->entity, $this->entity, ['something']); $doctrine_event = $this ->getMockBuilder('Doctrine\ORM\Event\PostFlushEventArgs') ->disableOriginalConstructor() @@ -268,7 +271,5 @@ public function testOnEntityChangedAttribute(): void $listener->postFlush($doctrine_event); $listener->entityChanged($event); $listener->entityChanged($event); - - self::assertSame(3, $entity->getCallCount()); } } From 071af31a7dabac5070cd403d834782513d20c450 Mon Sep 17 00:00:00 2001 From: Jan Lam Date: Wed, 17 Jun 2026 14:22:01 +0200 Subject: [PATCH 6/6] Update constructor defaults --- src/Listener/RevisionListener.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Listener/RevisionListener.php b/src/Listener/RevisionListener.php index 392abe4..003c881 100644 --- a/src/Listener/RevisionListener.php +++ b/src/Listener/RevisionListener.php @@ -26,10 +26,9 @@ class RevisionListener public function __construct( private RevisionResolverInterface $resolver, private RevisionFactoryInterface $factory, - private ?LoggerInterface $logger = null, + private ?LoggerInterface $logger = new NullLogger(), private ?CacheItemPoolInterface $is_revision_cache = new ArrayAdapter() ) { - $this->logger = $logger ?: new NullLogger(); } /**