From ab729b1353524bae60a23dda5828058a2e701be2 Mon Sep 17 00:00:00 2001 From: valtzu Date: Sun, 23 Mar 2025 14:08:49 +0200 Subject: [PATCH] Add `LockKeyNormalizer` --- .../FrameworkExtension.php | 6 +++ .../FrameworkBundle/Resources/config/lock.php | 4 ++ src/Symfony/Component/Lock/CHANGELOG.md | 1 + .../Lock/Serializer/LockKeyNormalizer.php | 53 +++++++++++++++++++ .../Serializer/LockKeyNormalizerTest.php | 38 +++++++++++++ src/Symfony/Component/Lock/composer.json | 3 +- 6 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Lock/Serializer/LockKeyNormalizer.php create mode 100644 src/Symfony/Component/Lock/Tests/Serializer/LockKeyNormalizerTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index e2d0888dbd7e6..d99837a2b3d15 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -108,6 +108,7 @@ use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\PersistingStoreInterface; +use Symfony\Component\Lock\Serializer\LockKeyNormalizer; use Symfony\Component\Lock\Store\StoreFactory; use Symfony\Component\Mailer\Bridge as MailerBridge; use Symfony\Component\Mailer\Command\MailerTestCommand; @@ -2128,6 +2129,11 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont { $loader->load('lock.php'); + // BC layer Lock < 7.3 + if (!interface_exists(DenormalizerInterface::class) || !class_exists(LockKeyNormalizer::class)) { + $container->removeDefinition('serializer.normalizer.lock_key'); + } + foreach ($config['resources'] as $resourceName => $resourceStores) { if (0 === \count($resourceStores)) { continue; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/lock.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/lock.php index 4e14636211c2d..2dd64af772eb3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/lock.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/lock.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\Component\Lock\LockFactory; +use Symfony\Component\Lock\Serializer\LockKeyNormalizer; use Symfony\Component\Lock\Store\CombinedStore; use Symfony\Component\Lock\Strategy\ConsensusStrategy; @@ -26,5 +27,8 @@ ->args([abstract_arg('Store')]) ->call('setLogger', [service('logger')->ignoreOnInvalid()]) ->tag('monolog.logger', ['channel' => 'lock']) + + ->set('serializer.normalizer.lock_key', LockKeyNormalizer::class) + ->tag('serializer.normalizer', ['built_in' => true, 'priority' => -880]) ; }; diff --git a/src/Symfony/Component/Lock/CHANGELOG.md b/src/Symfony/Component/Lock/CHANGELOG.md index 1ea898d7ee96d..38a14d5fc171b 100644 --- a/src/Symfony/Component/Lock/CHANGELOG.md +++ b/src/Symfony/Component/Lock/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add support for `valkey:` / `valkeys:` schemes + * Add `LockKeyNormalizer` 7.2 --- diff --git a/src/Symfony/Component/Lock/Serializer/LockKeyNormalizer.php b/src/Symfony/Component/Lock/Serializer/LockKeyNormalizer.php new file mode 100644 index 0000000000000..d60e477c93275 --- /dev/null +++ b/src/Symfony/Component/Lock/Serializer/LockKeyNormalizer.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Lock\Serializer; + +use Symfony\Component\Lock\Key; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +class LockKeyNormalizer implements NormalizerInterface, DenormalizerInterface +{ + public function getSupportedTypes(?string $format): array + { + return [Key::class => true]; + } + + /** + * @param Key $data + */ + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + return (fn () => array_intersect_key(get_object_vars($this), array_flip($this->__sleep())))->bindTo($data, Key::class)(); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof Key; + } + + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): Key + { + $key = (new \ReflectionClass(Key::class))->newInstanceWithoutConstructor(); + $setter = (fn ($field) => $this->$field = $data[$field])->bindTo($key, Key::class); + foreach ($key->__sleep() as $serializedField) { + $setter($serializedField); + } + + return $key; + } + + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool + { + return Key::class === $type; + } +} diff --git a/src/Symfony/Component/Lock/Tests/Serializer/LockKeyNormalizerTest.php b/src/Symfony/Component/Lock/Tests/Serializer/LockKeyNormalizerTest.php new file mode 100644 index 0000000000000..94d6683b8a11b --- /dev/null +++ b/src/Symfony/Component/Lock/Tests/Serializer/LockKeyNormalizerTest.php @@ -0,0 +1,38 @@ +normalizer = new LockKeyNormalizer(); + } + + public function testNormalizeAndDenormalize() + { + $key = new Key(__METHOD__); + $key->reduceLifetime(1); + $key->setState('foo', 'bar'); + + $copy = $this->normalizer->denormalize($this->normalizer->normalize($key), Key::class); + $this->assertSame($key->getState('foo'), $copy->getState('foo')); + $this->assertEqualsWithDelta($key->getRemainingLifetime(), $copy->getRemainingLifetime(), 0.001); + } + + public function testNormalizingUnserializableLockThrows() + { + $key = new Key(__METHOD__); + $key->markUnserializable(); + + $this->expectException(UnserializableKeyException::class); + $this->normalizer->normalize($key); + } +} diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index 61f53e06f268e..bf11d1a3c1e16 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -21,7 +21,8 @@ }, "require-dev": { "doctrine/dbal": "^3.6|^4", - "predis/predis": "^1.1|^2.0" + "predis/predis": "^1.1|^2.0", + "symfony/serializer": "^6.4|^7.0" }, "conflict": { "doctrine/dbal": "<3.6",