Skip to content

Commit 15e082d

Browse files
committed
feature #49594 [Serializer] Groups annotation/attribute on class (Brajk19)
This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [Serializer] Groups annotation/attribute on class | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | | License | MIT | Doc PR | TODO This change adds option to use `Groups` attribute on class. Doing that will add specified group to each property. Example, this: ```php class MyEntity { #[Groups('group1')] private $foo; #[Groups('group1')] private $bar; // getters and setters... } ``` can be replaced with this ```php #[Groups('group1')] class MyEntity { private $foo; private $bar; // getters and setters... } ``` It also works with promoted properties. This: ```php class View { public function __construct( #[Groups('group1')] public readonly string $foo, #[Groups('group1')] public readonly string $bar ){ } } ``` can be replaced with this: ```php #[Groups('group1')] class View { public function __construct( public readonly string $foo, public readonly string $bar ){ } } ``` Commits ------- ef2c30c [Serializer] Groups annotation/attribute on class
2 parents 46386c2 + ef2c30c commit 15e082d

File tree

7 files changed

+171
-2
lines changed

7 files changed

+171
-2
lines changed

src/Symfony/Component/Serializer/Annotation/Groups.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
*
1919
* @Annotation
2020
* @NamedArgumentConstructor
21-
* @Target({"PROPERTY", "METHOD"})
21+
* @Target({"PROPERTY", "METHOD", "CLASS"})
2222
*
2323
* @author Kévin Dunglas <dunglas@gmail.com>
2424
*/
25-
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
25+
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_CLASS)]
2626
class Groups
2727
{
2828
/**

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Deprecate Doctrine annotations support in favor of native attributes
88
* Deprecate passing an annotation reader to the constructor of `AnnotationLoader`
9+
* Allow the `Groups` attribute/annotation on classes
910

1011
6.3
1112
---

src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
5656
$reflectionClass = $classMetadata->getReflectionClass();
5757
$className = $reflectionClass->name;
5858
$loaded = false;
59+
$classGroups = [];
5960

6061
$attributesMetadata = $classMetadata->getAttributesMetadata();
6162

@@ -65,6 +66,11 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
6566
$annotation->getTypeProperty(),
6667
$annotation->getMapping()
6768
));
69+
continue;
70+
}
71+
72+
if ($annotation instanceof Groups) {
73+
$classGroups = $annotation->getGroups();
6874
}
6975
}
7076

@@ -75,6 +81,10 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
7581
}
7682

7783
if ($property->getDeclaringClass()->name === $className) {
84+
foreach ($classGroups as $group) {
85+
$attributesMetadata[$property->name]->addGroup($group);
86+
}
87+
7888
foreach ($this->loadAnnotations($property) as $annotation) {
7989
if ($annotation instanceof Groups) {
8090
foreach ($annotation->getGroups() as $group) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Fixtures\Annotations;
13+
14+
use Symfony\Component\Serializer\Annotation\Groups;
15+
16+
/**
17+
* @Groups({"a"})
18+
*/
19+
class GroupClassDummy
20+
{
21+
/**
22+
* @Groups({"b"})
23+
*/
24+
private $foo;
25+
26+
/**
27+
* @Groups({"c", "d"})
28+
*/
29+
private $bar;
30+
31+
private $baz;
32+
33+
public function getFoo()
34+
{
35+
return $this->foo;
36+
}
37+
38+
public function setFoo($foo): void
39+
{
40+
$this->foo = $foo;
41+
}
42+
43+
public function getBar()
44+
{
45+
return $this->bar;
46+
}
47+
48+
public function setBar($bar): void
49+
{
50+
$this->bar = $bar;
51+
}
52+
53+
public function getBaz()
54+
{
55+
return $this->baz;
56+
}
57+
58+
public function setBaz($baz): void
59+
{
60+
$this->baz = $baz;
61+
}
62+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Fixtures\Attributes;
13+
14+
use Symfony\Component\Serializer\Annotation\Groups;
15+
16+
#[Groups('a')]
17+
class GroupClassDummy
18+
{
19+
#[Groups('b')]
20+
private $foo;
21+
22+
#[Groups(['c', 'd'])]
23+
private $bar;
24+
25+
private $baz;
26+
27+
public function getFoo()
28+
{
29+
return $this->foo;
30+
}
31+
32+
public function setFoo($foo): void
33+
{
34+
$this->foo = $foo;
35+
}
36+
37+
public function getBar()
38+
{
39+
return $this->bar;
40+
}
41+
42+
public function setBar($bar): void
43+
{
44+
$this->bar = $bar;
45+
}
46+
47+
public function getBaz()
48+
{
49+
return $this->baz;
50+
}
51+
52+
public function setBaz($baz): void
53+
{
54+
$this->baz = $baz;
55+
}
56+
}

src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTestCase.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,24 @@ public function testIgnoreGetterWithRequiredParameterIfIgnoreAnnotationIsNotUsed
192192
self::assertArrayHasKey('extraValue2', $attributes);
193193
}
194194

195+
public function testLoadGroupsOnClass()
196+
{
197+
$classMetadata = new ClassMetadata($this->getNamespace().'\GroupClassDummy');
198+
$this->loader->loadClassMetadata($classMetadata);
199+
200+
$attributesMetadata = $classMetadata->getAttributesMetadata();
201+
202+
self::assertCount(3, $classMetadata->getAttributesMetadata());
203+
204+
self::assertArrayHasKey('foo', $attributesMetadata);
205+
self::assertArrayHasKey('bar', $attributesMetadata);
206+
self::assertArrayHasKey('baz', $attributesMetadata);
207+
208+
self::assertSame(['a', 'b'], $attributesMetadata['foo']->getGroups());
209+
self::assertSame(['a', 'c', 'd'], $attributesMetadata['bar']->getGroups());
210+
self::assertSame(['a'], $attributesMetadata['baz']->getGroups());
211+
}
212+
195213
abstract protected function createLoader(): AnnotationLoader;
196214

197215
abstract protected function getNamespace(): string;

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,28 @@ public function testNoCollectDenormalizationErrorsWithWrongEnumOnConstructor()
12781278
}
12791279
}
12801280

1281+
public function testGroupsOnClassSerialization()
1282+
{
1283+
$obj = new Fixtures\Attributes\GroupClassDummy();
1284+
$obj->setFoo('foo');
1285+
$obj->setBar('bar');
1286+
$obj->setBaz('baz');
1287+
1288+
$serializer = new Serializer(
1289+
[
1290+
new ObjectNormalizer(),
1291+
],
1292+
[
1293+
'json' => new JsonEncoder(),
1294+
]
1295+
);
1296+
1297+
$this->assertSame(
1298+
'{"foo":"foo","bar":"bar","baz":"baz"}',
1299+
$serializer->serialize($obj, 'json', ['groups' => ['a']])
1300+
);
1301+
}
1302+
12811303
public static function provideCollectDenormalizationErrors(): array
12821304
{
12831305
return [

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy