From ef2c30cab1d8e501ad4c42c4cc105e451648a293 Mon Sep 17 00:00:00 2001 From: Brajk19 Date: Fri, 3 Mar 2023 21:44:53 +0100 Subject: [PATCH] [Serializer] Groups annotation/attribute on class --- .../Serializer/Annotation/Groups.php | 4 +- src/Symfony/Component/Serializer/CHANGELOG.md | 1 + .../Mapping/Loader/AnnotationLoader.php | 10 +++ .../Fixtures/Annotations/GroupClassDummy.php | 62 +++++++++++++++++++ .../Fixtures/Attributes/GroupClassDummy.php | 56 +++++++++++++++++ .../Loader/AnnotationLoaderTestCase.php | 18 ++++++ .../Serializer/Tests/SerializerTest.php | 22 +++++++ 7 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/Annotations/GroupClassDummy.php create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/Attributes/GroupClassDummy.php diff --git a/src/Symfony/Component/Serializer/Annotation/Groups.php b/src/Symfony/Component/Serializer/Annotation/Groups.php index 5b16f567c3547..f1ea6f76b9bc3 100644 --- a/src/Symfony/Component/Serializer/Annotation/Groups.php +++ b/src/Symfony/Component/Serializer/Annotation/Groups.php @@ -18,11 +18,11 @@ * * @Annotation * @NamedArgumentConstructor - * @Target({"PROPERTY", "METHOD"}) + * @Target({"PROPERTY", "METHOD", "CLASS"}) * * @author Kévin Dunglas */ -#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_CLASS)] class Groups { /** diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 4ab3defddc1bb..0fb810b06bcb9 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Deprecate Doctrine annotations support in favor of native attributes * Deprecate passing an annotation reader to the constructor of `AnnotationLoader` + * Allow the `Groups` attribute/annotation on classes 6.3 --- diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php index 94d0f45dcb1f7..fdeda08b2be39 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php @@ -56,6 +56,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool $reflectionClass = $classMetadata->getReflectionClass(); $className = $reflectionClass->name; $loaded = false; + $classGroups = []; $attributesMetadata = $classMetadata->getAttributesMetadata(); @@ -65,6 +66,11 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool $annotation->getTypeProperty(), $annotation->getMapping() )); + continue; + } + + if ($annotation instanceof Groups) { + $classGroups = $annotation->getGroups(); } } @@ -75,6 +81,10 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool } if ($property->getDeclaringClass()->name === $className) { + foreach ($classGroups as $group) { + $attributesMetadata[$property->name]->addGroup($group); + } + foreach ($this->loadAnnotations($property) as $annotation) { if ($annotation instanceof Groups) { foreach ($annotation->getGroups() as $group) { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/Annotations/GroupClassDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Annotations/GroupClassDummy.php new file mode 100644 index 0000000000000..e977326132259 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Annotations/GroupClassDummy.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures\Annotations; + +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * @Groups({"a"}) + */ +class GroupClassDummy +{ + /** + * @Groups({"b"}) + */ + private $foo; + + /** + * @Groups({"c", "d"}) + */ + private $bar; + + private $baz; + + public function getFoo() + { + return $this->foo; + } + + public function setFoo($foo): void + { + $this->foo = $foo; + } + + public function getBar() + { + return $this->bar; + } + + public function setBar($bar): void + { + $this->bar = $bar; + } + + public function getBaz() + { + return $this->baz; + } + + public function setBaz($baz): void + { + $this->baz = $baz; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/Attributes/GroupClassDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Attributes/GroupClassDummy.php new file mode 100644 index 0000000000000..68289a9a854be --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Attributes/GroupClassDummy.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures\Attributes; + +use Symfony\Component\Serializer\Annotation\Groups; + +#[Groups('a')] +class GroupClassDummy +{ + #[Groups('b')] + private $foo; + + #[Groups(['c', 'd'])] + private $bar; + + private $baz; + + public function getFoo() + { + return $this->foo; + } + + public function setFoo($foo): void + { + $this->foo = $foo; + } + + public function getBar() + { + return $this->bar; + } + + public function setBar($bar): void + { + $this->bar = $bar; + } + + public function getBaz() + { + return $this->baz; + } + + public function setBaz($baz): void + { + $this->baz = $baz; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTestCase.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTestCase.php index 40d5e3cfee5de..69b486177712c 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTestCase.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTestCase.php @@ -192,6 +192,24 @@ public function testIgnoreGetterWithRequiredParameterIfIgnoreAnnotationIsNotUsed self::assertArrayHasKey('extraValue2', $attributes); } + public function testLoadGroupsOnClass() + { + $classMetadata = new ClassMetadata($this->getNamespace().'\GroupClassDummy'); + $this->loader->loadClassMetadata($classMetadata); + + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + self::assertCount(3, $classMetadata->getAttributesMetadata()); + + self::assertArrayHasKey('foo', $attributesMetadata); + self::assertArrayHasKey('bar', $attributesMetadata); + self::assertArrayHasKey('baz', $attributesMetadata); + + self::assertSame(['a', 'b'], $attributesMetadata['foo']->getGroups()); + self::assertSame(['a', 'c', 'd'], $attributesMetadata['bar']->getGroups()); + self::assertSame(['a'], $attributesMetadata['baz']->getGroups()); + } + abstract protected function createLoader(): AnnotationLoader; abstract protected function getNamespace(): string; diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 8c5c89a674d24..a50662a24a512 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -1278,6 +1278,28 @@ public function testNoCollectDenormalizationErrorsWithWrongEnumOnConstructor() } } + public function testGroupsOnClassSerialization() + { + $obj = new Fixtures\Attributes\GroupClassDummy(); + $obj->setFoo('foo'); + $obj->setBar('bar'); + $obj->setBaz('baz'); + + $serializer = new Serializer( + [ + new ObjectNormalizer(), + ], + [ + 'json' => new JsonEncoder(), + ] + ); + + $this->assertSame( + '{"foo":"foo","bar":"bar","baz":"baz"}', + $serializer->serialize($obj, 'json', ['groups' => ['a']]) + ); + } + public static function provideCollectDenormalizationErrors(): array { return [