Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Serializer] Deprecate annotations in favor of attributes #50983

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions UPGRADE-6.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@ Security
* `UserValueResolver` no longer implements `ArgumentValueResolverInterface`
* Make `PersistentToken` immutable
* Deprecate accepting only `DateTime` for `TokenProviderInterface::updateToken()`, use `DateTimeInterface` instead

Serializer
----------

* Deprecate Doctrine annotations support in favor of native attributes
* Deprecate passing an annotation reader to the constructor of `AnnotationLoader`
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
*/
class SerializerModelFixture
{
/**
* @Groups({"read"})
*/
#[Groups(['read'])]
public $name = 'howdy';

public $title = 'fixture';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace Symfony\Bridge\Twig\Tests\Extension;

use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\SerializerExtension;
use Symfony\Bridge\Twig\Extension\SerializerRuntime;
Expand Down Expand Up @@ -50,7 +49,7 @@ public static function serializerDataProvider(): \Generator

private function getTwig(string $template): Environment
{
$meta = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$meta = new ClassMetadataFactory(new AnnotationLoader());
$runtime = new SerializerRuntime(new Serializer([new ObjectNormalizer($meta)], [new JsonEncoder(), new YamlEncoder()]));

$mockRuntimeLoader = $this->createMock(RuntimeLoaderInterface::class);
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bridge/Twig/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"twig/twig": "^2.13|^3.0.4"
},
"require-dev": {
"doctrine/annotations": "^1.12|^2",
"egulias/email-validator": "^2.1.10|^3|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
Expand Down Expand Up @@ -62,6 +61,7 @@
"symfony/http-foundation": "<5.4",
"symfony/http-kernel": "<6.2",
"symfony/mime": "<6.2",
"symfony/serializer": "<6.2",
"symfony/translation": "<5.4",
"symfony/workflow": "<5.4"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

namespace Symfony\Component\PropertyInfo\Tests\Extractor;

use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor;
use Symfony\Component\PropertyInfo\Tests\Fixtures\AdderRemoverDummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy;
use Symfony\Component\PropertyInfo\Tests\Fixtures\IgnorePropertyDummy;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
Expand All @@ -24,22 +24,19 @@
*/
class SerializerExtractorTest extends TestCase
{
/**
* @var SerializerExtractor
*/
private $extractor;
private SerializerExtractor $extractor;

protected function setUp(): void
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader());
$this->extractor = new SerializerExtractor($classMetadataFactory);
}

public function testGetProperties()
{
$this->assertEquals(
['collection'],
$this->extractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', ['serializer_groups' => ['a']])
$this->extractor->getProperties(Dummy::class, ['serializer_groups' => ['a']])
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class Dummy extends ParentDummy

/**
* @var \DateTimeImmutable[]
* @Groups({"a", "b"})
*/
#[Groups(['a', 'b'])]
public $collection;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,9 @@
*/
class IgnorePropertyDummy
{
/**
* @Groups({"a"})
*/
#[Groups(['a'])]
public $visibleProperty;

/**
* @Groups({"a"})
* @Ignore
*/
#[Groups(['a']), Ignore]
private $ignoredProperty;
}
6 changes: 3 additions & 3 deletions src/Symfony/Component/PropertyInfo/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
"symfony/cache": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"phpdocumentor/reflection-docblock": "^5.2",
"phpstan/phpdoc-parser": "^1.0",
"doctrine/annotations": "^1.10.4|^2"
"phpstan/phpdoc-parser": "^1.0"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<5.2",
"phpdocumentor/type-resolver": "<1.5.1",
"symfony/dependency-injection": "<5.4"
"symfony/dependency-injection": "<5.4",
"symfony/serializer": "<5.4"
},
"autoload": {
"psr-4": { "Symfony\\Component\\PropertyInfo\\": "" },
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

6.4
---

* Deprecate Doctrine annotations support in favor of native attributes
* Deprecate passing an annotation reader to the constructor of `AnnotationLoader`

6.3
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class AnnotationLoader implements LoaderInterface
public function __construct(
private readonly ?Reader $reader = null,
) {
if ($reader) {
trigger_deprecation('symfony/validator', '6.4', 'Passing a "%s" instance as argument 1 to "%s()" is deprecated, pass null or omit the parameter instead.', get_debug_type($reader), __METHOD__);
}
}

public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
Expand Down Expand Up @@ -163,10 +166,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool
return $loaded;
}

/**
* @param \ReflectionClass|\ReflectionMethod|\ReflectionProperty $reflector
*/
public function loadAnnotations(object $reflector): iterable
public function loadAnnotations(\ReflectionMethod|\ReflectionClass|\ReflectionProperty $reflector): iterable
{
foreach ($reflector->getAttributes() as $attribute) {
if ($this->isKnownAttribute($attribute->getName())) {
Expand All @@ -193,13 +193,13 @@ public function loadAnnotations(object $reflector): iterable
}

if ($reflector instanceof \ReflectionClass) {
yield from $this->reader->getClassAnnotations($reflector);
yield from $this->getClassAnnotations($reflector);
}
if ($reflector instanceof \ReflectionMethod) {
yield from $this->reader->getMethodAnnotations($reflector);
yield from $this->getMethodAnnotations($reflector);
}
if ($reflector instanceof \ReflectionProperty) {
yield from $this->reader->getPropertyAnnotations($reflector);
yield from $this->getPropertyAnnotations($reflector);
}
}

Expand Down Expand Up @@ -229,4 +229,49 @@ private function isKnownAttribute(string $attributeName): bool

return false;
}

/**
* @return object[]
*/
private function getClassAnnotations(\ReflectionClass $reflector): array
{
if ($annotations = array_filter(
$this->reader->getClassAnnotations($reflector),
fn (object $annotation): bool => $this->isKnownAttribute($annotation::class),
)) {
trigger_deprecation('symfony/serializer', '6.4', 'Class "%s" uses Doctrine Annotations to configure serialization, which is deprecated. Use PHP attributes instead.', $reflector->getName());
}

return $annotations;
}

/**
* @return object[]
*/
private function getMethodAnnotations(\ReflectionMethod $reflector): array
{
if ($annotations = array_filter(
$this->reader->getMethodAnnotations($reflector),
fn (object $annotation): bool => $this->isKnownAttribute($annotation::class),
)) {
trigger_deprecation('symfony/serializer', '6.4', 'Method "%s::%s()" uses Doctrine Annotations to configure serialization, which is deprecated. Use PHP attributes instead.', $reflector->getDeclaringClass()->getName(), $reflector->getName());
}

return $annotations;
}

/**
* @return object[]
*/
private function getPropertyAnnotations(\ReflectionProperty $reflector): array
{
if ($annotations = array_filter(
$this->reader->getPropertyAnnotations($reflector),
fn (object $annotation): bool => $this->isKnownAttribute($annotation::class),
)) {
trigger_deprecation('symfony/serializer', '6.4', 'Property "%s::$%s" uses Doctrine Annotations to configure serialization, which is deprecated. Use PHP attributes instead.', $reflector->getDeclaringClass()->getName(), $reflector->getName());
}

return $annotations;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Tests\Fixtures\ChildOfGroupsAnnotationDummy;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyInterface;
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\GroupDummyInterface;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Tests\Fixtures;
namespace Symfony\Component\Serializer\Tests\Fixtures\Annotations;

use Symfony\Component\Serializer\Annotation\Groups;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Tests\Fixtures\ChildOfGroupsAnnotationDummy;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyInterface;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Tests\Fixtures\Annotations;
namespace Symfony\Component\Serializer\Tests\Fixtures\Attributes;

class GroupDummyChild extends GroupDummy
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
interface GroupDummyInterface
{
#[Groups(['a', 'name_converter'])]
public function getSymfony();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;

/**
* @DiscriminatorMap(typeProperty="type", mapping={
* "one"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne",
* "two"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo"
* })
*
* @author Samuel Roze <samuel.roze@gmail.com>
*/
#[DiscriminatorMap(typeProperty: 'type', mapping: [
'one' => DummyMessageNumberOne::class,
'two' => DummyMessageNumberTwo::class,
])]
interface DummyMessageInterface
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ class DummyMessageNumberOne implements DummyMessageInterface
{
public $one;

/**
* @Groups({"two"})
*/
#[Groups(['two'])]
public $two;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
*/
class OtherSerializedNameDummy
{
/**
* @Groups({"a"})
*/
#[Groups(['a'])]
private $buz;

public function setBuz($buz)
Expand All @@ -34,10 +32,7 @@ public function getBuz()
return $this->buz;
}

/**
* @Groups({"b"})
* @SerializedName("buz")
*/
#[Groups(['b']), SerializedName('buz')]
public function getBuzForExport()
{
return $this->buz.' Rocks';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'Symfony\Component\Serializer\Tests\Fixtures\Annotations\IgnoreDummy':
'Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummy':
attributes:
ignored1:
ignore: foo