diff --git a/src/Symfony/Component/Serializer/Annotation/Context.php b/src/Symfony/Component/Serializer/Annotation/Context.php index e3878c7be599..a83c8f079c76 100644 --- a/src/Symfony/Component/Serializer/Annotation/Context.php +++ b/src/Symfony/Component/Serializer/Annotation/Context.php @@ -22,7 +22,7 @@ * * @author Maxime Steinhausser */ -#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Context { private array $groups; diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 17221fe61c03..b206bbe10e19 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 6.4 --- + * Allow `Context` attribute to target classes * 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 diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php index fdeda08b2be3..db9612a0bd58 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php @@ -57,6 +57,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool $className = $reflectionClass->name; $loaded = false; $classGroups = []; + $classContextAnnotation = null; $attributesMetadata = $classMetadata->getAttributesMetadata(); @@ -71,6 +72,12 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool if ($annotation instanceof Groups) { $classGroups = $annotation->getGroups(); + + continue; + } + + if ($annotation instanceof Context) { + $classContextAnnotation = $annotation; } } @@ -81,6 +88,10 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool } if ($property->getDeclaringClass()->name === $className) { + if ($classContextAnnotation) { + $this->setAttributeContextsForGroups($classContextAnnotation, $attributesMetadata[$property->name]); + } + foreach ($classGroups as $group) { $attributesMetadata[$property->name]->addGroup($group); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ContextMetadataTestTrait.php b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ContextMetadataTestTrait.php index 8886e667ee93..7375b530dfb2 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ContextMetadataTestTrait.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ContextMetadataTestTrait.php @@ -82,6 +82,7 @@ public function contextMetadataDummyProvider(): array return [ [ContextMetadataDummy::class], [ContextChildMetadataDummy::class], + [ClassAndPropertyContextMetadataDummy::class], ]; } @@ -100,7 +101,7 @@ public function testContextDenormalizeWithNameConverter() class ContextMetadataDummy { /** - * @var \DateTime + * @var \DateTimeImmutable */ #[Groups(['extended', 'simple'])] #[Context([DateTimeNormalizer::FORMAT_KEY => \DateTimeInterface::RFC3339])] @@ -118,7 +119,7 @@ class ContextMetadataDummy class ContextChildMetadataDummy { /** - * @var \DateTime + * @var \DateTimeImmutable */ #[Groups(['extended', 'simple'])] #[DummyContextChild([DateTimeNormalizer::FORMAT_KEY => \DateTimeInterface::RFC3339])] @@ -133,10 +134,28 @@ class ContextChildMetadataDummy public $date; } +#[Context(context: [DateTimeNormalizer::FORMAT_KEY => \DateTimeInterface::RFC3339])] +#[Context( + context: [DateTimeNormalizer::FORMAT_KEY => \DateTimeInterface::RFC3339_EXTENDED], + groups: ['extended'], +)] +class ClassAndPropertyContextMetadataDummy +{ + /** + * @var \DateTimeImmutable + */ + #[Groups(['extended', 'simple'])] + #[Context( + denormalizationContext: [DateTimeNormalizer::FORMAT_KEY => 'd/m/Y'], + groups: ['simple'], + )] + public $date; +} + class ContextMetadataNamingDummy { /** - * @var \DateTime + * @var \DateTimeImmutable */ #[Context([DateTimeNormalizer::FORMAT_KEY => 'd/m/Y'])] public $createdAt; diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/DummyContextChild.php b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/DummyContextChild.php index f66ef702a565..25f85d61fec1 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/DummyContextChild.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/DummyContextChild.php @@ -13,7 +13,7 @@ use Symfony\Component\Serializer\Annotation\Context; -#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)] +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)] class DummyContextChild extends Context { } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index f92a502418fc..63b5c971145e 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -1477,12 +1477,12 @@ public function __construct($value) class DummyUnionType { /** - * @var \DateTime|bool|null + * @var \DateTimeImmutable|bool|null */ public $changed = false; /** - * @param \DateTime|bool|null + * @param \DateTimeImmutable|bool|null * * @return $this */