From 2a6b400d1720f69a3930974a16af1ede9b98538b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Mon, 13 Apr 2026 12:25:19 +0200 Subject: [PATCH 1/3] Cleanup after Symfony 7.4 upgrade --- .../IbexaMessengerExtension.php | 19 +-- .../Resources/config/services/buses.yaml | 3 +- .../services/serializer/normalizers.yaml | 7 +- .../Normalizer/DeduplicateStampNormalizer.php | 85 ------------- .../Normalizer/LockKeyNormalizer.php | 68 ---------- src/bundle/Serializer/SerializerFactory.php | 1 - .../DeduplicateStampNormalizerTest.php | 117 ------------------ .../Normalizer/LockKeyNormalizerTest.php | 111 ----------------- 8 files changed, 6 insertions(+), 405 deletions(-) delete mode 100644 src/bundle/Serializer/Normalizer/DeduplicateStampNormalizer.php delete mode 100644 src/bundle/Serializer/Normalizer/LockKeyNormalizer.php delete mode 100644 tests/bundle/Serializer/Normalizer/DeduplicateStampNormalizerTest.php delete mode 100644 tests/bundle/Serializer/Normalizer/LockKeyNormalizerTest.php diff --git a/src/bundle/DependencyInjection/IbexaMessengerExtension.php b/src/bundle/DependencyInjection/IbexaMessengerExtension.php index edc738d..d16d8df 100644 --- a/src/bundle/DependencyInjection/IbexaMessengerExtension.php +++ b/src/bundle/DependencyInjection/IbexaMessengerExtension.php @@ -8,9 +8,7 @@ namespace Ibexa\Bundle\Messenger\DependencyInjection; -use Ibexa\Bundle\Messenger\Middleware\DeduplicateMiddleware; use Ibexa\Bundle\Messenger\Middleware\SudoMiddleware; -use Ibexa\Bundle\Messenger\Serializer\Normalizer\LockKeyNormalizer; use Ibexa\Contracts\Messenger\Transport\MessageProviderInterface; use LogicException; use Symfony\Component\Config\FileLocator; @@ -21,7 +19,6 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension; use Symfony\Component\Lock\PersistingStoreInterface; -use Symfony\Component\Lock\Serializer\LockNormalizer as SymfonyLockNormalizer; use Symfony\Component\Lock\Store\StoreFactory; use Symfony\Component\Stopwatch\Stopwatch; @@ -57,7 +54,6 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container $loader->load('services.yaml'); $this->configureLockStorage($mergedConfig['deduplication_lock_storage'], $container); - $this->configureLockNormalizerBackport($container); $this->registerMessengerConfiguration($mergedConfig, $container); if ($this->shouldLoadTestServices($container)) { @@ -124,7 +120,7 @@ private function registerMessengerConfiguration( ]; if ($mergedConfig['deduplication_lock_storage']['enabled'] === true) { - $middleware[] = ['id' => DeduplicateMiddleware::class]; + $middleware[] = ['id' => 'ibexa.messenger.middleware.deduplicate_middleware']; } $middleware = array_merge( @@ -147,7 +143,7 @@ private function registerMessengerConfiguration( private function configureLockStorage(array $lockStorageConfig, ContainerBuilder $container): void { if ($lockStorageConfig['enabled'] === false) { - $container->removeDefinition(DeduplicateMiddleware::class); + $container->removeDefinition('ibexa.messenger.middleware.deduplicate_middleware'); $container->removeDefinition('ibexa.messenger.lock_factory'); $container->removeDefinition('ibexa.messenger.lock_store.dbal'); @@ -193,15 +189,4 @@ private function configureLockStorage(array $lockStorageConfig, ContainerBuilder $lockStorageType, )); } - - private function configureLockNormalizerBackport(ContainerBuilder $container): void - { - // Symfony 7.4 contains proper implementation - if (class_exists(SymfonyLockNormalizer::class)) { - $container->removeDefinition(LockKeyNormalizer::class); - $definition = new Definition(SymfonyLockNormalizer::class); - $definition->addTag('ibexa.messenger.serializer.normalizer', ['priority' => -60]); - $container->setDefinition('ibexa.messenger.lock_normalizer', $definition); - } - } } diff --git a/src/bundle/Resources/config/services/buses.yaml b/src/bundle/Resources/config/services/buses.yaml index e001225..2520f8e 100644 --- a/src/bundle/Resources/config/services/buses.yaml +++ b/src/bundle/Resources/config/services/buses.yaml @@ -25,7 +25,8 @@ services: Ibexa\Bundle\Messenger\Middleware\SudoMiddleware: ~ - Ibexa\Bundle\Messenger\Middleware\DeduplicateMiddleware: + ibexa.messenger.middleware.deduplicate_middleware: + class: Symfony\Component\Messenger\Middleware\DeduplicateMiddleware arguments: - '@ibexa.messenger.lock_factory' diff --git a/src/bundle/Resources/config/services/serializer/normalizers.yaml b/src/bundle/Resources/config/services/serializer/normalizers.yaml index 4e4096b..faee30f 100644 --- a/src/bundle/Resources/config/services/serializer/normalizers.yaml +++ b/src/bundle/Resources/config/services/serializer/normalizers.yaml @@ -4,11 +4,8 @@ services: autoconfigure: false public: false - Ibexa\Bundle\Messenger\Serializer\Normalizer\DeduplicateStampNormalizer: - tags: - - { name: ibexa.messenger.serializer.normalizer, priority: -60 } - - Ibexa\Bundle\Messenger\Serializer\Normalizer\LockKeyNormalizer: + ibexa.messenger.serializer.normalizer.lock_key_normalizer: + class: Symfony\Component\Lock\Serializer\LockKeyNormalizer tags: - { name: ibexa.messenger.serializer.normalizer, priority: -60 } diff --git a/src/bundle/Serializer/Normalizer/DeduplicateStampNormalizer.php b/src/bundle/Serializer/Normalizer/DeduplicateStampNormalizer.php deleted file mode 100644 index 9de9cf2..0000000 --- a/src/bundle/Serializer/Normalizer/DeduplicateStampNormalizer.php +++ /dev/null @@ -1,85 +0,0 @@ - true, - ]; - } - - /** - * @phpstan-param TData $data - */ - public function denormalize($data, string $type, ?string $format = null, array $context = []): DeduplicateStamp - { - $stamp = (new ReflectionClass(DeduplicateStamp::class))->newInstanceWithoutConstructor(); - - $key = $this->denormalizer->denormalize($data['key'], Key::class, $format, $context); - - Closure::bind(function () use ($data, $key): void { - $this->key = $key; - $this->ttl = $data['ttl'] ?? 300.0; - $this->onlyDeduplicateInQueue = $data['only_deduplicate_in_queue'] ?? false; - }, $stamp, DeduplicateStamp::class)(); - - return $stamp; - } - - public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool - { - return $type === DeduplicateStamp::class; - } - - /** - * @phpstan-return TData - */ - public function normalize(mixed $object, ?string $format = null, array $context = []): array - { - assert($object instanceof DeduplicateStamp); - - return [ - 'key' => $this->normalizer->normalize($object->getKey(), $format, $context), - 'ttl' => $object->getTtl(), - 'only_deduplicate_in_queue' => $object->onlyDeduplicateInQueue(), - ]; - } - - public function supportsNormalization($data, ?string $format = null, array $context = []): bool - { - return $data instanceof DeduplicateStamp; - } -} diff --git a/src/bundle/Serializer/Normalizer/LockKeyNormalizer.php b/src/bundle/Serializer/Normalizer/LockKeyNormalizer.php deleted file mode 100644 index c198981..0000000 --- a/src/bundle/Serializer/Normalizer/LockKeyNormalizer.php +++ /dev/null @@ -1,68 +0,0 @@ - true, - ]; - } - - /** - * @return array - */ - public function normalize($data, ?string $format = null, array $context = []): array - { - assert($data instanceof Key); - - return $data->__serialize(); - } - - public function supportsNormalization($data, ?string $format = null, array $context = []): bool - { - return $data instanceof Key; - } - - /** - * @throws \ReflectionException - */ - public function denormalize($data, string $type, ?string $format = null, array $context = []): Key - { - $key = (new ReflectionClass(Key::class))->newInstanceWithoutConstructor(); - $setter = Closure::bind( - function (string $field) use ($data): void { - $this->$field = $data[$field]; - }, - $key, - Key::class, - ); - foreach (['resource', 'expiringTime', 'state'] as $serializedField) { - $setter($serializedField); - } - - return $key; - } - - public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool - { - return $type === Key::class; - } -} diff --git a/src/bundle/Serializer/SerializerFactory.php b/src/bundle/Serializer/SerializerFactory.php index 223c33e..6eaa181 100644 --- a/src/bundle/Serializer/SerializerFactory.php +++ b/src/bundle/Serializer/SerializerFactory.php @@ -8,7 +8,6 @@ namespace Ibexa\Bundle\Messenger\Serializer; -use function Ibexa\PolyfillPhp82\iterator_to_array; use Symfony\Component\Messenger\Transport\Serialization\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; diff --git a/tests/bundle/Serializer/Normalizer/DeduplicateStampNormalizerTest.php b/tests/bundle/Serializer/Normalizer/DeduplicateStampNormalizerTest.php deleted file mode 100644 index b8ee204..0000000 --- a/tests/bundle/Serializer/Normalizer/DeduplicateStampNormalizerTest.php +++ /dev/null @@ -1,117 +0,0 @@ -normalizer = new DeduplicateStampNormalizer(); - $this->subNormalizer = $this->createMock(NormalizerInterface::class); - $this->subDenormalizer = $this->createMock(DenormalizerInterface::class); - - $this->normalizer->setNormalizer($this->subNormalizer); - $this->normalizer->setDenormalizer($this->subDenormalizer); - } - - /** - * @dataProvider provideForTest - * - * @param array{ - * key: \ArrayObject, - * ttl: float, - * only_deduplicate_in_queue: bool, - * } $expected - */ - public function testNormalize(DeduplicateStamp $stamp, array $expected): void - { - $this->subDenormalizer->expects(self::never())->method(self::anything()); - - $this->subNormalizer->expects(self::once()) - ->method('normalize') - ->with(self::isInstanceOf(Key::class)) - ->willReturn($expected['key']); - - $normalized = $this->normalizer->normalize($stamp); - - self::assertSame($expected, $normalized); - } - - /** - * @dataProvider provideForTest - * - * @param array{ - * key: \ArrayObject, - * ttl: float, - * only_deduplicate_in_queue: bool, - * } $data - */ - public function testDenormalize(DeduplicateStamp $expectedStamp, array $data): void - { - $this->subNormalizer->expects(self::never())->method(self::anything()); - - $this->subDenormalizer - ->expects(self::once()) - ->method('denormalize') - ->with(self::identicalTo($data['key']), Key::class) - ->willReturn($expectedStamp->getKey()); - - $denormalized = $this->normalizer->denormalize($data, DeduplicateStamp::class); - - self::assertSame($expectedStamp->getKey(), $denormalized->getKey()); - self::assertSame($expectedStamp->getTtl(), $denormalized->getTtl()); - self::assertSame($expectedStamp->onlyDeduplicateInQueue(), $denormalized->onlyDeduplicateInQueue()); - } - - /** - * @return iterable, - * ttl: float, - * only_deduplicate_in_queue: bool, - * }, - * }> - */ - public static function provideForTest(): iterable - { - yield [ - new DeduplicateStamp('foo_key'), - [ - 'key' => new \ArrayObject(), - 'ttl' => 300.0, - 'only_deduplicate_in_queue' => false, - ], - ]; - - yield [ - new DeduplicateStamp('foo_key', 600.0, true), - [ - 'key' => new \ArrayObject(), - 'ttl' => 600.0, - 'only_deduplicate_in_queue' => true, - ], - ]; - } -} diff --git a/tests/bundle/Serializer/Normalizer/LockKeyNormalizerTest.php b/tests/bundle/Serializer/Normalizer/LockKeyNormalizerTest.php deleted file mode 100644 index cfb186b..0000000 --- a/tests/bundle/Serializer/Normalizer/LockKeyNormalizerTest.php +++ /dev/null @@ -1,111 +0,0 @@ -normalizer = new LockKeyNormalizer(); - } - - /** - * @dataProvider provideForTest - * - * @param array{ - * resource: string, - * expiringTime: float|null, - * state: array, - * } $expected - */ - public function testNormalize(Key $data, array $expected): void - { - $normalized = $this->normalizer->normalize($data); - - self::assertSame($expected, $normalized); - } - - /** - * @dataProvider provideForTest - * - * @param array{ - * resource: string, - * expiringTime: float|null, - * state: array, - * } $data - */ - public function testDenormalize(Key $expectedKey, array $data): void - { - $denormalized = $this->normalizer->denormalize($data, Key::class); - - self::assertSame($data['resource'], (string)$denormalized); - - if ($data['expiringTime'] === null) { - self::assertNull($denormalized->getRemainingLifetime()); - } else { - // Some time will pass - self::assertNotNull($denormalized->getRemainingLifetime()); - self::assertLessThan($data['expiringTime'], $denormalized->getRemainingLifetime()); - } - self::assertFalse($denormalized->hasState('_non_existent_state_')); - - foreach ($data['state'] as $key => $value) { - self::assertTrue($denormalized->hasState($key)); - self::assertSame($value, $denormalized->getState($key)); - } - } - - /** - * @return iterable, - * }, - * }> - */ - public static function provideForTest(): iterable - { - $currentTime = time(); - $key = new Key('bar'); - \Closure::bind(function () use ($currentTime): void { - $this->expiringTime = $currentTime + 300; - }, $key, Key::class)(); - - yield [ - $key, - [ - 'resource' => 'bar', - 'expiringTime' => (float)($currentTime + 300), - 'state' => [], - ], - ]; - - $key = new Key('foo'); - $key->setState('foo', 'bar'); - - yield [ - $key, - [ - 'resource' => 'foo', - 'expiringTime' => null, - 'state' => [ - 'foo' => 'bar', - ], - ], - ]; - } -} From b65a5b51a6d7f8273813301c8a2f161c7b1fb0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Mon, 13 Apr 2026 14:54:31 +0200 Subject: [PATCH 2/3] Cleanup after Symfony 7.4 upgrade --- phpstan-baseline.neon | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0f1ee82..777d5d5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -48,24 +48,6 @@ parameters: count: 1 path: src/bundle/Lock/Store/DoctrineDbalStore.php - - - message: '#^Parameter \#1 \$data \(array\{key\: mixed, ttl\?\: float\|null, only_deduplicate_in_queue\?\: bool\|null\}\) of method Ibexa\\Bundle\\Messenger\\Serializer\\Normalizer\\DeduplicateStampNormalizer\:\:denormalize\(\) should be contravariant with parameter \$data \(mixed\) of method Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface\:\:denormalize\(\)$#' - identifier: method.childParameterType - count: 1 - path: src/bundle/Serializer/Normalizer/DeduplicateStampNormalizer.php - - - - message: '#^Cannot access offset string on mixed\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: src/bundle/Serializer/Normalizer/LockKeyNormalizer.php - - - - message: '#^Variable property access on Symfony\\Component\\Lock\\Key\.$#' - identifier: property.dynamicName - count: 1 - path: src/bundle/Serializer/Normalizer/LockKeyNormalizer.php - - message: '#^Method Ibexa\\Bundle\\Messenger\\Transport\\Sender\\SendersLocator\:\:listTypes\(\) should return array\ but returns array\.$#' identifier: return.type From 0604e40d87037e3a131aac222b9d5ed23bbf7460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Mon, 13 Apr 2026 15:22:21 +0200 Subject: [PATCH 3/3] Cleanup after Symfony 7.4 upgrade --- .../Middleware/DeduplicateMiddleware.php | 65 ------------------- .../IbexaMessengerExtensionTest.php | 5 +- 2 files changed, 2 insertions(+), 68 deletions(-) delete mode 100644 src/bundle/Middleware/DeduplicateMiddleware.php diff --git a/src/bundle/Middleware/DeduplicateMiddleware.php b/src/bundle/Middleware/DeduplicateMiddleware.php deleted file mode 100644 index f32204f..0000000 --- a/src/bundle/Middleware/DeduplicateMiddleware.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * - * Original code: https://github.com/symfony/symfony/blob/7.3/src/Symfony/Component/Messenger/Middleware/DeduplicateMiddleware.php - */ -final class DeduplicateMiddleware implements MiddlewareInterface -{ - private LockFactory $lockFactory; - - public function __construct(LockFactory $lockFactory) - { - $this->lockFactory = $lockFactory; - } - - public function handle(Envelope $envelope, StackInterface $stack): Envelope - { - $deduplicateStamp = $envelope->last(DeduplicateStamp::class); - if ($deduplicateStamp === null) { - return $stack->next()->handle($envelope, $stack); - } - - $receivedStamp = $envelope->last(ReceivedStamp::class); - if ($receivedStamp === null) { - $lock = $this->lockFactory->createLockFromKey( - $deduplicateStamp->getKey(), - $deduplicateStamp->getTtl(), - false, - ); - - if (!$lock->acquire()) { - return $envelope; - } - } elseif ($deduplicateStamp->onlyDeduplicateInQueue()) { - $this->lockFactory->createLockFromKey($deduplicateStamp->getKey())->release(); - } - - try { - $envelope = $stack->next()->handle($envelope, $stack); - } finally { - $receivedStamp = $envelope->last(ReceivedStamp::class); - if ($receivedStamp !== null && !$deduplicateStamp->onlyDeduplicateInQueue()) { - $this->lockFactory->createLockFromKey($deduplicateStamp->getKey())->release(); - } - } - - return $envelope; - } -} diff --git a/tests/bundle/DependencyInjection/IbexaMessengerExtensionTest.php b/tests/bundle/DependencyInjection/IbexaMessengerExtensionTest.php index ebd8ce5..ca23142 100644 --- a/tests/bundle/DependencyInjection/IbexaMessengerExtensionTest.php +++ b/tests/bundle/DependencyInjection/IbexaMessengerExtensionTest.php @@ -9,7 +9,6 @@ namespace Ibexa\Tests\Bundle\Messenger\DependencyInjection; use Ibexa\Bundle\Messenger\DependencyInjection\IbexaMessengerExtension; -use Ibexa\Bundle\Messenger\Middleware\DeduplicateMiddleware; use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase; final class IbexaMessengerExtensionTest extends AbstractExtensionTestCase @@ -33,7 +32,7 @@ public function testConfigurationDefaults(): void { $this->load(); - self::assertTrue($this->container->hasDefinition(DeduplicateMiddleware::class)); + self::assertTrue($this->container->hasDefinition('ibexa.messenger.middleware.deduplicate_middleware')); self::assertTrue($this->container->hasDefinition('ibexa.messenger.lock_factory')); self::assertTrue($this->container->hasDefinition('ibexa.messenger.lock_store.dbal')); } @@ -46,7 +45,7 @@ public function testConfigurationWithDisabledLocks(): void ], ]); - self::assertFalse($this->container->hasDefinition(DeduplicateMiddleware::class)); + self::assertFalse($this->container->hasDefinition('ibexa.messenger.middleware.deduplicate_middleware')); self::assertFalse($this->container->hasDefinition('ibexa.messenger.lock_factory')); self::assertFalse($this->container->hasDefinition('ibexa.messenger.lock_store.dbal')); }