diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 085ceb5dafabb..62c19e9ee75d7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -934,6 +934,7 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode) ->end() ->end() ->end() + ->scalarNode('default_version')->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index e929724c7fd86..700eb4da3ca98 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1598,6 +1598,12 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $defaultContext += ['max_depth_handler' => new Reference($config['max_depth_handler'])]; $container->getDefinition('serializer.normalizer.object')->replaceArgument(6, $defaultContext); } + + if (isset($config['default_version']) && $config['default_version']) { + $defaultContext = $container->getDefinition('serializer.normalizer.object')->getArgument(6); + $defaultContext += ['version' => $config['default_version']]; + $container->getDefinition('serializer.normalizer.object')->replaceArgument(6, $defaultContext); + } } private function registerPropertyInfoConfiguration(ContainerBuilder $container, PhpFileLoader $loader) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 08cea8ecee7ab..a54d5fc981fe3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -251,6 +251,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php index 647044e613798..91f522fb1eae8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php @@ -67,6 +67,7 @@ 'name_converter' => 'serializer.name_converter.camel_case_to_snake_case', 'circular_reference_handler' => 'my.circular.reference.handler', 'max_depth_handler' => 'my.max.depth.handler', + 'default_version' => '1.0.0', ], 'property_info' => true, 'ide' => 'file%%link%%format', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index 9207066f1c183..5ceccf58e9b47 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -33,7 +33,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 2206585863baa..390aaaca73df4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -55,6 +55,7 @@ framework: name_converter: serializer.name_converter.camel_case_to_snake_case circular_reference_handler: my.circular.reference.handler max_depth_handler: my.max.depth.handler + default_version: 1.0.0 property_info: ~ ide: file%%link%%format request: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 99054524d004c..f013178fea31a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -1108,6 +1108,8 @@ public function testSerializerEnabled() $this->assertArrayHasKey('circular_reference_handler', $container->getDefinition('serializer.normalizer.object')->getArgument(6)); $this->assertArrayHasKey('max_depth_handler', $container->getDefinition('serializer.normalizer.object')->getArgument(6)); $this->assertEquals($container->getDefinition('serializer.normalizer.object')->getArgument(6)['max_depth_handler'], new Reference('my.max.depth.handler')); + $this->assertArrayHasKey('version', $container->getDefinition('serializer.normalizer.object')->getArgument(6)); + $this->assertEquals($container->getDefinition('serializer.normalizer.object')->getArgument(6)['version'], '1.0.0'); } public function testRegisterSerializerExtractor() diff --git a/src/Symfony/Component/Serializer/Annotation/Since.php b/src/Symfony/Component/Serializer/Annotation/Since.php new file mode 100644 index 0000000000000..7117e9ccef50a --- /dev/null +++ b/src/Symfony/Component/Serializer/Annotation/Since.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Annotation; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; + +/** + * Annotation class for @Since(). + * + * @Annotation + * @Target({"PROPERTY", "METHOD"}) + * + * @author Arnaud Tarroux + */ +class Since +{ + /** + * @var string + */ + private $version; + + public function __construct(array $data) + { + if (!isset($data['value'])) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" should be set.', static::class)); + } + + if (!\is_string($data['value']) || empty($data['value'])) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be a non-empty string.', static::class)); + } + + $this->version = $data['value']; + } + + public function getVersion(): string + { + return $this->version; + } +} diff --git a/src/Symfony/Component/Serializer/Annotation/Until.php b/src/Symfony/Component/Serializer/Annotation/Until.php new file mode 100644 index 0000000000000..16f1616addfe5 --- /dev/null +++ b/src/Symfony/Component/Serializer/Annotation/Until.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Annotation; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; + +/** + * Annotation class for @Until(). + * + * @Annotation + * @Target({"PROPERTY", "METHOD"}) + * + * @author Arnaud Tarroux + */ +class Until +{ + /** + * @var string + */ + private $version; + + public function __construct(array $data) + { + if (!isset($data['value'])) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" should be set.', static::class)); + } + + if (!\is_string($data['value']) || empty($data['value'])) { + throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be a non-empty string.', static::class)); + } + + $this->version = $data['value']; + } + + public function getVersion(): string + { + return $this->version; + } +} diff --git a/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php b/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php index 732e0bd5908cc..fd3ff0d5ca614 100644 --- a/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php +++ b/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php @@ -59,6 +59,24 @@ class AttributeMetadata implements AttributeMetadataInterface */ public $ignore = false; + /** + * @var string|null + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getSince()} instead. + */ + public $since; + + /** + * @var string|null + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getUntil()} instead. + */ + public $until; + public function __construct(string $name) { $this->name = $name; @@ -162,6 +180,38 @@ public function merge(AttributeMetadataInterface $attributeMetadata) } } + /** + * {@inheritdoc} + */ + public function setSince(string $version) + { + $this->since = $version; + } + + /** + * {@inheritdoc} + */ + public function getSince(): ?string + { + return $this->since; + } + + /** + * {@inheritdoc} + */ + public function setUntil(string $version) + { + $this->until = $version; + } + + /** + * {@inheritdoc} + */ + public function getUntil(): ?string + { + return $this->until; + } + /** * Returns the names of the properties that should be serialized. * @@ -169,6 +219,6 @@ public function merge(AttributeMetadataInterface $attributeMetadata) */ public function __sleep() { - return ['name', 'groups', 'maxDepth', 'serializedName', 'ignore']; + return ['name', 'groups', 'maxDepth', 'serializedName', 'ignore', 'since', 'until']; } } diff --git a/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php b/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php index 9e78cf0d31743..00f8608fd73c5 100644 --- a/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php +++ b/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php @@ -75,4 +75,24 @@ public function isIgnored(): bool; * Merges an {@see AttributeMetadataInterface} with in the current one. */ public function merge(self $attributeMetadata); + + /** + * Sets the version number from which the attribute must be serialized. + */ + public function setSince(string $version); + + /** + * Gets the version number from which the attribute must be serialized. + */ + public function getSince(): ?string; + + /** + * Sets the version number after which the attribute must not be serialized. + */ + public function setUntil(string $version); + + /** + * Gets the version number after which the attribute must not be serialized. + */ + public function getUntil(): ?string; } diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php index 978fe659bbbce..7883be8200c4e 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php @@ -17,6 +17,8 @@ use Symfony\Component\Serializer\Annotation\Ignore; use Symfony\Component\Serializer\Annotation\MaxDepth; use Symfony\Component\Serializer\Annotation\SerializedName; +use Symfony\Component\Serializer\Annotation\Since; +use Symfony\Component\Serializer\Annotation\Until; use Symfony\Component\Serializer\Exception\MappingException; use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping; @@ -74,6 +76,10 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata) $attributesMetadata[$property->name]->setSerializedName($annotation->getSerializedName()); } elseif ($annotation instanceof Ignore) { $attributesMetadata[$property->name]->setIgnore(true); + } elseif ($annotation instanceof Since) { + $attributesMetadata[$property->name]->setSince($annotation->getVersion()); + } elseif ($annotation instanceof Until) { + $attributesMetadata[$property->name]->setUntil($annotation->getVersion()); } $loaded = true; @@ -121,6 +127,18 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata) $attributeMetadata->setSerializedName($annotation->getSerializedName()); } elseif ($annotation instanceof Ignore) { $attributeMetadata->setIgnore(true); + } elseif ($annotation instanceof Since) { + if (!$accessorOrMutator) { + throw new MappingException(sprintf('Since on "%s::%s" cannot be added. Since can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name)); + } + + $attributeMetadata->setSince($annotation->getVersion()); + } elseif ($annotation instanceof Until) { + if (!$accessorOrMutator) { + throw new MappingException(sprintf('Until on "%s::%s" cannot be added. Until can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name)); + } + + $attributeMetadata->setUntil($annotation->getVersion()); } $loaded = true; diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php index 696007afb83ad..ed4fe080fd6bd 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php @@ -74,6 +74,14 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata) if (isset($attribute['ignore'])) { $attributeMetadata->setIgnore((bool) $attribute['ignore']); } + + if (isset($attribute['since'])) { + $attributeMetadata->setSince((string) $attribute['since']); + } + + if (isset($attribute['until'])) { + $attributeMetadata->setUntil((string) $attribute['until']); + } } if (isset($xml->{'discriminator-map'})) { diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php index ff50e622eeadf..997f81ae65044 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php @@ -101,6 +101,14 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata) $attributeMetadata->setIgnore($data['ignore']); } + + if (isset($data['since'])) { + $attributeMetadata->setSince((string) $data['since']); + } + + if (isset($data['until'])) { + $attributeMetadata->setUntil((string) $data['until']); + } } } diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd b/src/Symfony/Component/Serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd index b427a36e368c1..b5065c6b7b63a 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd +++ b/src/Symfony/Component/Serializer/Mapping/Loader/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd @@ -79,6 +79,20 @@ + + + + + + + + + + + + + + diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 4a03ab851a3a2..1a91a9d0a33d2 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -251,7 +251,8 @@ protected function getAllowedAttributes($classOrObject, array $context, bool $at if ( !$ignore && (false === $groups || array_intersect(array_merge($attributeMetadata->getGroups(), ['*']), $groups)) && - $this->isAllowedAttribute($classOrObject, $name = $attributeMetadata->getName(), null, $context) + $this->isAllowedAttribute($classOrObject, $name = $attributeMetadata->getName(), null, $context) && + $this->attributeAllowedWithVersion($context, $attributeMetadata->getSince(), $attributeMetadata->getUntil()) ) { $allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata; } @@ -447,4 +448,25 @@ protected function createChildContext(array $parentContext, string $attribute, ? return $parentContext; } + + /** + * @internal + */ + private function attributeAllowedWithVersion(array $context, ?string $sinceVersion, ?string $untilVersion) + { + if (!isset($context['version']) && !isset($this->defaultContext['version'])) { + return true; + } + + $version = $context['version'] ?? $this->defaultContext['version']; + if (null !== $sinceVersion && version_compare($version, $sinceVersion, '<')) { + return false; + } + + if (null !== $untilVersion && version_compare($version, $untilVersion, '>=')) { + return false; + } + + return true; + } } diff --git a/src/Symfony/Component/Serializer/Tests/Annotation/SinceTest.php b/src/Symfony/Component/Serializer/Tests/Annotation/SinceTest.php new file mode 100644 index 0000000000000..8fa8cf8c5339f --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Annotation/SinceTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Annotation; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Annotation\Since; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; + +/** + * @author Arnaud Tarroux + */ +class SinceTest extends TestCase +{ + public function testNotSetVersionParameter() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'Parameter of annotation "Symfony\Component\Serializer\Annotation\Since" should be set.' + ); + new Since([]); + } + + public function provideInvalidValues() + { + return [ + [''], + [0], + ]; + } + + /** + * @dataProvider provideInvalidValues + */ + public function testNotAStringVersionParameter($value) + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'Parameter of annotation "Symfony\Component\Serializer\Annotation\Since" must be a non-empty string.' + ); + new Since(['value' => $value]); + } + + public function testVersionParameters() + { + $since = new Since(['value' => '1.1.2']); + $this->assertSame('1.1.2', $since->getVersion()); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Annotation/UntilTest.php b/src/Symfony/Component/Serializer/Tests/Annotation/UntilTest.php new file mode 100644 index 0000000000000..9021a23b56f4c --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Annotation/UntilTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Annotation; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Annotation\Until; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; + +/** + * @author Arnaud Tarroux + */ +class UntilTest extends TestCase +{ + public function testNotSetVersionParameter() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'Parameter of annotation "Symfony\Component\Serializer\Annotation\Until" should be set.' + ); + new Until([]); + } + + public function provideInvalidValues() + { + return [ + [''], + [0], + ]; + } + + /** + * @dataProvider provideInvalidValues + */ + public function testNotAStringVersionParameter($value) + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'Parameter of annotation "Symfony\Component\Serializer\Annotation\Until" must be a non-empty string.' + ); + new Until(['value' => $value]); + } + + public function testVersionParameters() + { + $since = new Until(['value' => '1.1.2']); + $this->assertSame('1.1.2', $since->getVersion()); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/VersioningDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/VersioningDummy.php new file mode 100644 index 0000000000000..b07bfe3ab9394 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/VersioningDummy.php @@ -0,0 +1,38 @@ +foo; + } + + /** + * @Until("1.3.0") + */ + public function getUsername() + { + return $this->username; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.xml b/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.xml index 257d838b4965e..cf93a19afc2f8 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.xml +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.xml @@ -39,4 +39,8 @@ + + + + diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.yml b/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.yml index 4d98c73b04c16..91719d8eeb4c3 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.yml +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/serialization.yml @@ -30,3 +30,9 @@ ignore: true ignored2: ignore: true + +'Symfony\Component\Serializer\Tests\Fixtures\VersionDummy': + attributes: + foo: + since: '1.0.0' + until: '1.1.9' diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php index 9c5a9943e31ef..3e3299250e25b 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php @@ -20,8 +20,8 @@ use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummy; use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild; use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild; -use Symfony\Component\Serializer\Tests\Fixtures\IgnoreDummy; use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyThirdChild; +use Symfony\Component\Serializer\Tests\Fixtures\IgnoreDummy; use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; /** @@ -118,4 +118,17 @@ public function testLoadIgnore() $this->assertTrue($attributesMetadata['ignored1']->isIgnored()); $this->assertTrue($attributesMetadata['ignored2']->isIgnored()); } + + public function testLoadVersion() + { + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\VersioningDummy'); + $this->loader->loadClassMetadata($classMetadata); + + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + $this->assertSame('1.0.0', $attributesMetadata['foo']->getSince()); + $this->assertSame('1.1.2', $attributesMetadata['bar']->getSince()); + $this->assertSame('1.1.9', $attributesMetadata['foo']->getUntil()); + $this->assertSame('1.3.0', $attributesMetadata['username']->getUntil()); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php index 4d30c8e2cbfe9..b71fbfd27a44e 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php @@ -103,4 +103,15 @@ public function testLoadIgnore() $this->assertTrue($attributesMetadata['ignored1']->isIgnored()); $this->assertTrue($attributesMetadata['ignored2']->isIgnored()); } + + public function testVersion() + { + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\VersionDummy'); + $this->loader->loadClassMetadata($classMetadata); + + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + $this->assertSame('1.2.0', $attributesMetadata['foo']->getSince()); + $this->assertSame('1.9.1', $attributesMetadata['foo']->getUntil()); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php index 6d2ff5c0bdb8e..32d5d217b5f89 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php @@ -125,4 +125,15 @@ public function testLoadInvalidIgnore() (new YamlFileLoader(__DIR__.'/../../Fixtures/invalid-ignore.yml'))->loadClassMetadata(new ClassMetadata(IgnoreDummy::class)); } + + public function testVersion() + { + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\VersionDummy'); + $this->loader->loadClassMetadata($classMetadata); + + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + $this->assertSame('1.0.0', $attributesMetadata['foo']->getSince()); + $this->assertSame('1.1.9', $attributesMetadata['foo']->getUntil()); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index 082b427ab7caa..3f308591e946c 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -190,4 +190,42 @@ public function testIgnore() $this->assertSame([], $normalizer->normalize($dummy)); } + + public function testObjectWithVersioning() + { + $classMetadata = new ClassMetadata('c'); + + $a = new AttributeMetadata('a'); + $a->setSince('1.8.0'); + $a->addGroup('test'); + $classMetadata->addAttributeMetadata($a); + + $b = new AttributeMetadata('b'); + $b->setUntil('2.1.0'); + $b->addGroup('test'); + $classMetadata->addAttributeMetadata($b); + + $c = new AttributeMetadata('c'); + $c->setSince('1.8.0'); + $c->setUntil('2.0.0'); + $c->addGroup('test'); + $classMetadata->addAttributeMetadata($c); + + $this->classMetadata->method('getMetadataFor')->willReturn($classMetadata); + + $result = $this->normalizer->getAllowedAttributes('c', [ + AbstractNormalizer::GROUPS => ['test'], 'version' => '1.8.0', + ], true); + $this->assertSame(['a', 'b', 'c'], $result); + + $result = $this->normalizer->getAllowedAttributes('c', [ + AbstractNormalizer::GROUPS => ['test'], 'version' => '1.7.0', + ], true); + $this->assertSame(['b'], $result); + + $result = $this->normalizer->getAllowedAttributes('c', [ + AbstractNormalizer::GROUPS => ['test'], 'version' => '2.3.0', + ], true); + $this->assertSame(['a'], $result); + } }