diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 484b1ea99..596977094 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -14,9 +14,8 @@ jobs: strategy: matrix: php-version: - - "7.2" - - "8.0" - - "8.1" + - "7.4" + - "8.2" steps: - name: Checkout code @@ -29,7 +28,7 @@ jobs: - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" - + - name: Run performance benchmarks run: | vendor/bin/phpbench run tests/Benchmark/Performance --report=aggregate diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7156cfb67..4cc603b62 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,8 +15,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" @@ -24,6 +22,10 @@ jobs: dependencies: - "lowest" - "highest" + include: + - php-version: '8.3' + dependencies: 'highest' + composer-stability: 'dev' env: JMS_TESTS_SHOW_DEPRECATIONS: 1 @@ -37,6 +39,13 @@ jobs: with: php-version: ${{ matrix.php-version }} + - name: Composer config + if: ${{ matrix.composer-stability }} + run: composer config minimum-stability ${{ matrix.composer-stability }} + + - name: Uninstall Doctrine ODM + run: composer remove doctrine/phpcr-odm jackalope/jackalope-doctrine-dbal --no-update --dev + - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" with: diff --git a/.github/workflows/coding-standards.yaml b/.github/workflows/coding-standards.yaml index af0b7c184..2a80321cd 100644 --- a/.github/workflows/coding-standards.yaml +++ b/.github/workflows/coding-standards.yaml @@ -14,7 +14,7 @@ jobs: strategy: matrix: php-version: - - "7.2" + - "7.4" steps: - name: "Checkout" diff --git a/.github/workflows/static-analysis.yaml b/.github/workflows/static-analysis.yaml index cbda4cc36..c1d5d635c 100644 --- a/.github/workflows/static-analysis.yaml +++ b/.github/workflows/static-analysis.yaml @@ -38,3 +38,7 @@ jobs: - name: "Run a static analysis with phpstan/phpstan" run: "vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr" + + - name: "Run a static analysis with rector/rector" + run: "vendor/bin/rector --dry-run" + if: ${{ matrix.php-version == 8.2 }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f93b3b59..9f5579068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +New versions can be found on the [realeases page](https://github.com/schmittjoh/serializer/releases) + ## [3.15.0](https://github.com/schmittjoh/serializer/tree/3.15.0) (2021-10-14) **Merged pull requests:** diff --git a/UPGRADING.md b/UPGRADING.md index 4c5b0c8c5..93ae1ced1 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -5,6 +5,15 @@ Unreleased - Deprecated the `@ReadOnly` annotation due to `readonly` becoming a keyword in PHP 8.1, use the `@ReadOnlyProperty` annotation instead - Doctrine type `decimal` is now correctly mapped to `string` instead of `float` +From 3.x to 3.30.0 +================== + +Starting from this release [doctrine/annotations](https://github.com/doctrine/annotations) is an optional package. +If you still want to use them, please make sure that you require in `composer.json` file. + +We strongly recommend to start using [Attributes](https://www.php.net/manual/en/language.attributes.overview.php) with PHP 8. +You can easily migrate annotations to attributes with [rector](https://github.com/rectorphp/rector) and `Rector\Symfony\Set\SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES` rules. + From 2.x to 3.0.0 ================= diff --git a/composer.json b/composer.json index beaa350cd..08406fc41 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,13 @@ "name": "jms/serializer", "type": "library", "description": "Library for (de-)serializing data of any complexity; supports XML, and JSON.", - "keywords": ["serialization", "deserialization", "json", "jaxb", "xml"], + "keywords": [ + "serialization", + "deserialization", + "json", + "jaxb", + "xml" + ], "homepage": "http://jmsyst.com/libs/serializer", "license": "MIT", "authors": [ @@ -16,12 +22,11 @@ } ], "require": { - "php": "^7.2||^8.0", - "doctrine/annotations": "^1.13 || ^2.0", - "doctrine/instantiator": "^1.0.3 || ^2.0", + "php": "^7.4 || ^8.0", + "doctrine/instantiator": "^1.3.1 || ^2.0", "doctrine/lexer": "^2.0 || ^3.0", "jms/metadata": "^2.6", - "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" + "phpstan/phpdoc-parser": "^1.20" }, "suggest": { "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", @@ -31,25 +36,27 @@ }, "require-dev": { "ext-pdo_sqlite": "*", - "doctrine/coding-standard": "^9.0", - "doctrine/orm": "~2.1", - "doctrine/persistence": "^1.3.3|^2.0|^3.0", - "doctrine/phpcr-odm": "^1.3|^2.0", - "jackalope/jackalope-doctrine-dbal": "^1.1.5", - "ocramius/proxy-manager": "^1.0|^2.0", + "doctrine/annotations": "^1.14 || ^2.0", + "doctrine/coding-standard": "^12.0", + "doctrine/orm": "^2.14 || ^3.0", + "doctrine/persistence": "^2.5.2 || ^3.0", + "doctrine/phpcr-odm": "^1.5.2 || ^2.0", + "jackalope/jackalope-doctrine-dbal": "^1.3", + "ocramius/proxy-manager": "^1.0 || ^2.0", "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "^1.0.2", - "phpunit/phpunit": "^8.5.21||^9.0||^10.0", - "psr/container": "^1.0|^2.0", - "symfony/dependency-injection": "^3.0|^4.0|^5.0|^6.0", - "symfony/expression-language": "^3.2|^4.0|^5.0|^6.0", - "symfony/filesystem": "^3.0|^4.0|^5.0|^6.0", - "symfony/form": "^3.0|^4.0|^5.0|^6.0", - "symfony/translation": "^3.0|^4.0|^5.0|^6.0", - "symfony/uid": "^5.1|^6.0", - "symfony/validator": "^3.1.9|^4.0|^5.0|^6.0", - "symfony/yaml": "^3.3|^4.0|^5.0|^6.0", - "twig/twig": "~1.34|~2.4|^3.0" + "phpstan/phpstan": "^1.10.57", + "phpunit/phpunit": "^9.0 || ^10.0 || ^11.0", + "psr/container": "^1.0 || ^2.0", + "rector/rector": "^1.0.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/expression-language": "^5.4 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0", + "symfony/translation": "^5.4 || ^6.0 || ^7.0", + "symfony/uid": "^5.4 || ^6.0 || ^7.0", + "symfony/validator": "^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0", + "twig/twig": "^1.34 || ^2.4 || ^3.0" }, "autoload": { "psr-4": { diff --git a/doc/reference/annotations.rst b/doc/reference/annotations.rst index 0cb5e385a..180120708 100644 --- a/doc/reference/annotations.rst +++ b/doc/reference/annotations.rst @@ -1,96 +1,168 @@ -Annotations -=========== +Attributes and annotations +========================== -@ExclusionPolicy -~~~~~~~~~~~~~~~~ -This annotation can be defined on a class to indicate the exclusion strategy +PHP 8 support +~~~~~~~~~~~~~~~ +JMS serializer now supports PHP 8 attributes, with a few caveats: +- Due to the missing support for nested attributes, the syntax for a few attributes has changed +(see the ``VirtualProperty`` ``options`` syntax here below) +- There is an edge case when setting this exact serialization group ``#[Groups(['value' => 'any value here'])]``. +(when there is only one item in th serialization groups array and has as key ``value`` the attribute will not work as expected, +please use the alternative syntax ``#[Groups(groups: ['value' => 'any value here'])]`` that works with no issues), + +Converting your annotations to attributes +----------------------------------------- + +Example: + +.. code-block :: php + + /** + * @VirtualProperty( + * "classlow", + * exp="object.getVirtualValue(1)", + * options={@Until("8")} + * ) + * @VirtualProperty( + * "classhigh", + * exp="object.getVirtualValue(8)", + * options={@Since("6")} + * ) + */ + #[VirtualProperty('classlow', exp: 'object.getVirtualValue(1)', options: [[Until::class, ['8']]])] + #[VirtualProperty('classhigh', exp: 'object.getVirtualValue(8)', options: [[Since::class, ['6']]])] + class ObjectWithVersionedVirtualProperties + { + /** + * @Groups({"versions"}) + * @VirtualProperty + * @SerializedName("low") + * @Until("8") + */ + #[Groups(['versions'])] + #[VirtualProperty] + #[SerializedName('low')] + #[Until('8')] + public function getVirtualLowValue() + { + return 1; + } + ... + +To automate migration of Annotations to Attributes you can use `rector/rector` with following config: + +.. code-block :: php + + paths([ + __DIR__ . '/src', + ]); + $rectorConfig->sets([ + JMSSetList::ANNOTATIONS_TO_ATTRIBUTES, + LevelSetList::UP_TO_PHP_80, + ]); + }; + + + +#[ExclusionPolicy] +~~~~~~~~~~~~~~~~~~ +This attribute can be defined on a class to indicate the exclusion strategy that should be used for the class. +----------+----------------------------------------------------------------+ | Policy | Description | +==========+================================================================+ | all | all properties are excluded by default; only properties marked | -| | with @Expose will be serialized/unserialized | +| | with #Expose will be serialized/unserialized | +----------+----------------------------------------------------------------+ | none | no properties are excluded by default; all properties except | -| | those marked with @Exclude will be serialized/unserialized | +| | those marked with #Exclude will be serialized/unserialized | +----------+----------------------------------------------------------------+ -@Exclude -~~~~~~~~ -This annotation can be defined on a property or a class to indicate that the property or class +#[Exclude] +~~~~~~~~~~ +This attribute can be defined on a property or a class to indicate that the property or class should not be serialized/unserialized. Works only in combination with NoneExclusionPolicy. If the ``ExpressionLanguageExclusionStrategy`` exclusion strategy is enabled, it will -be possible to use ``@Exclude(if="expression")`` to exclude dynamically a property +be possible to use ``#[Exclude(if:"expression")]`` to exclude dynamically a property or an object if used on class level. -@Expose -~~~~~~~ -This annotation can be defined on a property to indicate that the property should +#[Expose] +~~~~~~~~~ +This attribute can be defined on a property to indicate that the property should be serialized/unserialized. Works only in combination with AllExclusionPolicy. If the ``ExpressionLanguageExclusionStrategy`` exclusion strategy is enabled, will -be possible to use ``@Expose(if="expression")`` to expose dynamically a property. +be possible to use ``#Expose[if:"expression"]`` to expose dynamically a property. -@SkipWhenEmpty -~~~~~~~~~~~~~~ -This annotation can be defined on a property to indicate that the property should +#[SkipWhenEmpty] +~~~~~~~~~~~~~~~~ +This attribute can be defined on a property to indicate that the property should not be serialized if the result will be "empty". Works option works only when serializing. -@SerializedName -~~~~~~~~~~~~~~~ -This annotation can be defined on a property to define the serialized name for a +#[SerializedName] +~~~~~~~~~~~~~~~~~ +This attribute can be defined on a property to define the serialized name for a property. If this is not defined, the property will be translated from camel-case to a lower-cased underscored name, e.g. camelCase -> camel_case. -Note that this annotation is not used when you're using any other naming +Note that this attribute is not used when you're using any other naming strategy than the default configuration (which includes the -``SerializedNameAnnotationStrategy``). In order to re-enable the annotation, you -will need to wrap your custom strategy with the ``SerializedNameAnnotationStrategy``. +``SerializedNameattributeStrategy``). In order to re-enable the attribute, you +will need to wrap your custom strategy with the ``SerializedNameattributeStrategy``. .. code-block :: php setPropertyNamingStrategy( - new \JMS\Serializer\Naming\SerializedNameAnnotationStrategy( + new \JMS\Serializer\Naming\SerializedNameattributeStrategy( new \JMS\Serializer\Naming\IdenticalPropertyNamingStrategy() ) ) ->build(); -@Since -~~~~~~ -This annotation can be defined on a property to specify starting from which +#[Since] +~~~~~~~~ +This attribute can be defined on a property to specify starting from which version this property is available. If an earlier version is serialized, then this property is excluded automatically. The version must be in a format that is understood by PHP's ``version_compare`` function. -@Until -~~~~~~ -This annotation can be defined on a property to specify until which version this +#[Until] +~~~~~~~~ +This attribute can be defined on a property to specify until which version this property was available. If a later version is serialized, then this property is excluded automatically. The version must be in a format that is understood by PHP's ``version_compare`` function. -@Groups -~~~~~~~ -This annotation can be defined on a property to specify if the property +#[Groups] +~~~~~~~~~ +This attribute can be defined on a property to specify if the property should be serialized when only serializing specific groups (see :doc:`../cookbook/exclusion_strategies`). -@MaxDepth -~~~~~~~~~ -This annotation can be defined on a property to limit the depth to which the +#[MaxDepth] +~~~~~~~~~~~ +This attribute can be defined on a property to limit the depth to which the content will be serialized. It is very useful when a property will contain a large object graph. -@AccessType -~~~~~~~~~~~ -This annotation can be defined on a property, or a class to specify in which way +#[AccessType] +~~~~~~~~~~~~~ +This attribute can be defined on a property, or a class to specify in which way the properties should be accessed. By default, the serializer will retrieve, or set the value via reflection, but you may change this to use a public method instead: @@ -99,7 +171,7 @@ set the value via reflection, but you may change this to use a public method ins lastName; } - public function getFirstName() + public function getFirstName(): string { return $this->firstName; } @@ -259,14 +312,14 @@ In this example: - ``firstName`` is exposed using the ``object.getFirstName()`` expression (``exp`` can contain any valid symfony expression). -``@VirtualProperty()`` can also have an optional property ``name``, used to define the internal property name +``#[VirtualProperty]`` can also have an optional property ``name``, used to define the internal property name (for sorting proposes as example). When not specified, it defaults to the method name with the "get" prefix removed. .. note :: This only works for serialization and is completely ignored during deserialization. -In PHP 8, due to the missing support for nested annotations, in the options array you need to pass an array with the class name and an array with the arguments for its constructor. +In PHP 8, due to the missing support for nested attributes, in the options array you need to pass an array with the class name and an array with the arguments for its constructor. .. code-block :: php @@ -282,64 +335,60 @@ In PHP 8, due to the missing support for nested annotations, in the options arra { ... -@Inline -~~~~~~~ -This annotation can be defined on a property to indicate that the data of the property +#[Inline] +~~~~~~~~~ +This attribute can be defined on a property to indicate that the data of the property should be inlined. **Note**: AccessorOrder will be using the name of the property to determine the order. -@ReadOnlyProperty -~~~~~~~~~~~~~~~~~ -This annotation can be defined on a property to indicate that the data of the property +#[ReadOnlyProperty] +~~~~~~~~~~~~~~~~~~~ +This attribute can be defined on a property to indicate that the data of the property is read only and cannot be set during deserialization. -A property can be marked as non read only with ``@ReadOnlyProperty(false)`` annotation +A property can be marked as non read only with ``#[ReadOnlyProperty(readOnly: false)]`` attribute (useful when a class is marked as read only). -@PreSerialize -~~~~~~~~~~~~~ -This annotation can be defined on a method which is supposed to be called before +#[PreSerialize] +~~~~~~~~~~~~~~~ +This attribute can be defined on a method which is supposed to be called before the serialization of the object starts. -@PostSerialize -~~~~~~~~~~~~~~ -This annotation can be defined on a method which is then called directly after the +#[PostSerialize] +~~~~~~~~~~~~~~~~ +This attribute can be defined on a method which is then called directly after the object has been serialized. -@PostDeserialize -~~~~~~~~~~~~~~~~ -This annotation can be defined on a method which is supposed to be called after +#[PostDeserialize] +~~~~~~~~~~~~~~~~~~ +This attribute can be defined on a method which is supposed to be called after the object has been deserialized. -@Discriminator -~~~~~~~~~~~~~~ - -.. versionadded : 0.12 +#[Discriminator] +~~~~~~~~~~~~~~~~ - @Discriminator was added +This attribute allows serialization/deserialization of relations which are polymorphic, but +where a common base class exists. The ``#[Discriminator]`` attribute has to be applied +to the least super type: -This annotation allows serialization/deserialization of relations which are polymorphic, but -where a common base class exists. The ``@Discriminator`` annotation has to be applied -to the least super type:: +.. code-block :: php - /** - * @Discriminator(field = "type", disabled = false, map = {"car": "Car", "moped": "Moped"}, groups={"foo", "bar"}) - */ + #[Serializer\Discriminator(field: 'type', disabled: false, map: ['car' => 'Car', 'moped' => 'Moped'], groups=["foo", "bar"])] abstract class Vehicle { } class Car extends Vehicle { } class Moped extends Vehicle { } - + ... .. note :: `groups` is optional and is used as exclusion policy. -@Type -~~~~~ -This annotation can be defined on a property to specify the type of that property. -For deserialization, this annotation must be defined. -The ``@Type`` annotation can have parameters and parameters can be used by serialization/deserialization +#[Type] +~~~~~~~ +This attribute can be defined on a property to specify the type of that property. +For deserialization, this attribute must be defined. +The ``#[Type]`` attribute can have parameters and parameters can be used by serialization/deserialization handlers to enhance the serialization or deserialization result; for example, you may want to force a certain format to be used for serializing DateTime types and specifying at the same time a different format used when deserializing them. @@ -521,94 +570,74 @@ Examples: class BlogPost { - /** - * @Type("ArrayCollection") - */ + #[Type(name: "ArrayCollection")] private $comments; - /** - * @Type("string") - */ + #[Type(name: "string")] private $title; - /** - * @Type("MyNamespace\Author") - */ + #[Type(name: Author:class)] private $author; - /** - * @Type("DateTime") - */ + #[Type(name: DateTime:class)] private $startAt; - /** - * @Type("DateTime<'Y-m-d'>") - */ + #[Type(name: 'DateTime<'Y-m-d'>')] private $endAt; - /** - * @Type("DateTime<'Y-m-d', '', ['Y-m-d', 'Y/m/d']>") - */ + #[Type(name: 'DateTime<'Y-m-d'>')] + + #[Type(name:"DateTime<'Y-m-d', '', ['Y-m-d', 'Y/m/d']>")] private $publishedAt; - /** - * @Type("DateTimeImmutable") - */ + #[Type(name:'DateTimeImmutable')] private $createdAt; - /** - * @Type("DateTimeImmutable<'Y-m-d'>") - */ + #[Type(name:"DateTimeImmutable<'Y-m-d'>")] private $updatedAt; - /** - * @Type("DateTimeImmutable<'Y-m-d', '', ['Y-m-d', 'Y/m/d']>") - */ + #[Type(name:"DateTimeImmutable<'Y-m-d', '', ['Y-m-d', 'Y/m/d']>")] private $deletedAt; - /** - * @Type("boolean") - */ + #[Type(name:'boolean')] private $published; - /** - * @Type("array") - */ + #[Type(name:'array')] private $keyValueStore; } .. note :: if you are using ``PHP attributes`` with PHP 8.1 you can pass an object which implements ``__toString()`` method as a value for ``#[Type]`` attribute. - + .. code-block :: php - "; - } - } + class BlogPost + { + #[Type(new ArrayOf(Comment::class))] + private $comments; + } + + class ArrayOf implements \Stringable + { + public function __construct(private string $className) {} + + public function __toString(): string + { + return "array<$className>"; + } + } .. _configuration: https://jmsyst.com/bundles/JMSSerializerBundle/master/configuration#configuration-block-2-0 -@XmlRoot -~~~~~~~~ +#[XmlRoot] +~~~~~~~~~~ This allows you to specify the name of the top-level element. .. code-block :: php @@ -617,7 +646,7 @@ This allows you to specify the name of the top-level element. use JMS\Serializer\Annotation\XmlRoot; - /** @XmlRoot("user") */ + #[XmlRoot('user')] class User { private $name = 'Johannes'; @@ -633,12 +662,12 @@ Resulting XML: .. note :: - @XmlRoot only applies to the root element, but is for example not taken into + #[XmlRoot] only applies to the root element, but is for example not taken into account for collections. You can define the entry name for collections using - @XmlList, or @XmlMap. + #[XmlList], or #[XmlMap]. -@XmlAttribute -~~~~~~~~~~~~~ +#[XmlAttribute] +~~~~~~~~~~~~~~~ This allows you to mark properties which should be set as attributes, and not as child elements. @@ -650,7 +679,7 @@ and not as child elements. class User { - /** @XmlAttribute */ + #[XmlAttribute] private $id = 1; private $name = 'Johannes'; } @@ -664,9 +693,9 @@ Resulting XML: -@XmlDiscriminator -~~~~~~~~~~~~~~~~~ -This annotation allows to modify the behaviour of @Discriminator regarding handling of XML. +#[XmlDiscriminator] +~~~~~~~~~~~~~~~~~~~ +This attribute allows to modify the behaviour of ``#[Discriminator]`` regarding handling of XML. Available Options: @@ -690,10 +719,8 @@ Example for "attribute": use JMS\Serializer\Annotation\Discriminator; use JMS\Serializer\Annotation\XmlDiscriminator; - /** - * @Discriminator(field = "type", map = {"car": "Car", "moped": "Moped"}, groups={"foo", "bar"}) - * @XmlDiscriminator(attribute=true) - */ + #[Discriminator(field: 'type', map: ['car' => 'Car', 'moped' => 'Moped'], groups: ['foo', 'bar'])] + #[XmlDiscriminator(attribute: true)] abstract class Vehicle { } class Car extends Vehicle { } @@ -713,12 +740,8 @@ Example for "cdata": use JMS\Serializer\Annotation\Discriminator; use JMS\Serializer\Annotation\XmlDiscriminator; - - - /** - * @Discriminator(field = "type", map = {"car": "Car", "moped": "Moped"}, groups={"foo", "bar"}) - * @XmlDiscriminator(attribute=true) - */ + #[Discriminator(field: 'type', map: ['car' => 'Car', 'moped' => 'Moped'], groups: ['foo', 'bar'])] + #[XmlDiscriminator] abstract class Vehicle { } class Car extends Vehicle { } @@ -729,11 +752,11 @@ Resulting XML: car -@XmlValue -~~~~~~~~~ +#[XmlValue] +~~~~~~~~~~~ This allows you to mark properties which should be set as the value of the current element. Note that this has the limitation that any additional -properties of that object must have the @XmlAttribute annotation. +properties of that object must have the #[XmlAttribute] attribute. XMlValue also has property cdata. Which has the same meaning as the one in XMLElement. @@ -745,26 +768,27 @@ XMLElement. use JMS\Serializer\Annotation\XmlValue; use JMS\Serializer\Annotation\XmlRoot; - /** @XmlRoot("price") */ + #[XmlRoot('price')] class Price { - /** @XmlAttribute */ + #[XmlAttribute] private $currency = 'EUR'; - /** @XmlValue */ + #[XmlValue] private $amount = 1.23; } + Resulting XML: .. code-block :: xml 1.23 -@XmlList -~~~~~~~~ +#[XmlList] +~~~~~~~~~~ This allows you to define several properties of how arrays should be -serialized. This is very similar to @XmlMap, and should be used if the +serialized. This is very similar to #[XmlMap], and should be used if the keys of the array are not important. .. code-block :: php @@ -774,37 +798,24 @@ keys of the array are not important. use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlRoot; - /** @XmlRoot("post") */ + #[XmlRoot('post')] class Post { - /** - * @XmlList(inline = true, entry = "comment") - */ - private $comments = []; - - public function __construct(array $comments) + public function __construct( + #[XmlList(inline: true, entry: 'comment')] + private array $comments + ) { - $this->comments = $comments; } } class Comment { - private $text; - - public function __construct(string $text) + public function __construct(private string $text) { - $this->text = $text; } } - // usage - $post = new Post( - new Comment('Foo'), - new Comment('Bar'), - ); - $xml = $serializer->serialize($post, 'xml'); - Resulting XML: .. code-block :: xml @@ -818,64 +829,59 @@ Resulting XML: -You can also specify the entry tag namespace using the ``namespace`` attribute (``@XmlList(inline = true, entry = "comment", namespace="http://www.example.com/ns")``). +You can also specify the entry tag namespace using the ``namespace`` attribute (``#[XmlList(inline: true, entry: 'comment', namespace: 'http://www.example.com/ns')]``). -@XmlMap -~~~~~~~ -Similar to @XmlList, but the keys of the array are meaningful. +#[XmlMap] +~~~~~~~~~ +Similar to #[XmlList], but the keys of the array are meaningful. -@XmlKeyValuePairs -~~~~~~~~~~~~~~~~~ +#[XmlKeyValuePairs] +~~~~~~~~~~~~~~~~~~~ This allows you to use the keys of an array as xml tags. .. note :: When a key is an invalid xml tag name (e.g. 1_foo) the tag name *entry* will be used instead of the key. -@XmlAttributeMap -~~~~~~~~~~~~~~~~ +#[XmlAttributeMap] +~~~~~~~~~~~~~~~~~~ -This is similar to the @XmlKeyValuePairs, but instead of creating child elements, it creates attributes. +This is similar to the #[XmlKeyValuePairs], but instead of creating child elements, it creates attributes. .. code-block :: php 'firstname', - 'value' => 'Adrien', - ); + #[XmlAttributeMap] + private $id = ['name' => 'firstname', 'value' => 'Adrien']; } + Resulting XML: .. code-block :: xml -@XmlElement -~~~~~~~~~~~ -This annotation can be defined on a property to add additional xml serialization/deserialization properties. +#[XmlElement] +~~~~~~~~~~~~~ +This attribute can be defined on a property to add additional xml serialization/deserialization properties. .. code-block :: php my_id -@XmlNamespace -~~~~~~~~~~~~~ -This annotation allows you to specify Xml namespace/s and prefix used. +#[XmlNamespace] +~~~~~~~~~~~~~~~ +This attribute allows you to specify Xml namespace/s and prefix used. .. code-block :: php -PHP 8 support -~~~~~~~~~~~~~ - -JMS serializer now supports PHP 8 attributes, with a few caveats: -- Due to the missing support for nested annotations, the syntax for a few annotations has changed -(see the ``VirtualProperty`` ``options`` syntax here below) -- There is an edge case when setting this exact serialization group ``#[Groups(['value' => 'any value here'])]``. -(when there is only one item in th serialization groups array and has as key ``value`` the attribute will not work as expected, -please use the alternative syntax ``#[Groups(groups: ['value' => 'any value here'])]`` that works with no issues), - -Converting your annotations to attributes ------------------------------------------ - -Example: - -.. code-block :: php - - /** - * @VirtualProperty( - * "classlow", - * exp="object.getVirtualValue(1)", - * options={@Until("8")} - * ) - * @VirtualProperty( - * "classhigh", - * exp="object.getVirtualValue(8)", - * options={@Since("6")} - * ) - */ - #[VirtualProperty('classlow', exp: 'object.getVirtualValue(1)', options: [[Until::class, ['8']]])] - #[VirtualProperty('classhigh', exp: 'object.getVirtualValue(8)', options: [[Since::class, ['6']]])] - class ObjectWithVersionedVirtualProperties - { - /** - * @Groups({"versions"}) - * @VirtualProperty - * @SerializedName("low") - * @Until("8") - */ - #[Groups(['versions'])] - #[VirtualProperty] - #[SerializedName('low')] - #[Until('8')] - public function getVirtualLowValue() - { - return 1; - } - ... - Enum support -~~~~~~~~~~~~ +~~~~~~~~~~~~~~ Enum support is disabled by default, to enable it run: @@ -994,7 +950,7 @@ Enum support is disabled by default, to enable it run: With the enum support enabled, enums are automatically detected using typed properties typehints. When typed properties are no available (virtual properties as example), it is necessary to explicitly typehint -the underlying type using the ``@Type`` annotation. +the underlying type using the ``#[Type]`` attribute. - If the enum is a ``BackedEnum``, the case value will be used for serialization and deserialization by default; - If the enum is not a ``BackedEnum``, the case name will be used for serialization and deserialization by default; diff --git a/doc/requirements.txt b/doc/requirements.txt index 48cdd9b64..6d5ef871a 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -3,3 +3,4 @@ git+https://github.com/fabpot/sphinx-php.git sphinx_rtd_theme Jinja2<3.0 MarkupSafe<2.1 +alabaster<0.7.14 diff --git a/phpcs.xml.dist b/phpcs.xml.dist index bc27fa482..e2ed35f0c 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -10,7 +10,7 @@ - + src/ tests/ @@ -37,7 +37,6 @@ - @@ -60,6 +59,18 @@ + + + + + + + + + + + + diff --git a/phpstan/ignore-by-php-version.neon.php b/phpstan/ignore-by-php-version.neon.php index a7156b63c..b3ef4e83b 100644 --- a/phpstan/ignore-by-php-version.neon.php +++ b/phpstan/ignore-by-php-version.neon.php @@ -1,5 +1,8 @@ = 80000) { + $includes[] = __DIR__ . '/ignore-missing-attribute.neon'; + if(!class_exists(DataProvider::class)) { + $includes[] = __DIR__ . '/no-phpunit-attributes.neon'; + } +} if (PHP_VERSION_ID >= 80100 && PHP_VERSION_ID < 80200) { $includes[] = __DIR__ . '/php-81.neon'; } -if(!class_exists(Symfony\Component\Uid\UuidV7::class)) { +if(!class_exists(UuidV7::class)) { $includes[] = __DIR__ . '/no-uuid-7.neon'; } + $config = []; $config['includes'] = $includes; $config['parameters']['phpVersion'] = PHP_VERSION_ID; diff --git a/phpstan/ignore-missing-attribute.neon b/phpstan/ignore-missing-attribute.neon new file mode 100644 index 000000000..22b569d97 --- /dev/null +++ b/phpstan/ignore-missing-attribute.neon @@ -0,0 +1,3 @@ +parameters: + ignoreErrors: + - '#^Attribute class JMS\\Serializer\\Tests\\Fixtures\\MissingAttribute does not exist\.$#' diff --git a/phpstan/no-phpunit-attributes.neon b/phpstan/no-phpunit-attributes.neon new file mode 100644 index 000000000..a66b213b9 --- /dev/null +++ b/phpstan/no-phpunit-attributes.neon @@ -0,0 +1,3 @@ +parameters: + ignoreErrors: + - '~Attribute class PHPUnit\\Framework\\Attributes\\.* does not exist~' diff --git a/rector.php b/rector.php new file mode 100644 index 000000000..154c683ee --- /dev/null +++ b/rector.php @@ -0,0 +1,13 @@ +paths([ + __DIR__ . '/src', + ]); + $rectorConfig->phpVersion(74); +}; diff --git a/src/Accessor/DefaultAccessorStrategy.php b/src/Accessor/DefaultAccessorStrategy.php index a3c25a326..ed8d647ce 100644 --- a/src/Accessor/DefaultAccessorStrategy.php +++ b/src/Accessor/DefaultAccessorStrategy.php @@ -86,9 +86,7 @@ public function getValue(object $object, PropertyMetadata $metadata, Serializati $accessor = $this->readAccessors[$metadata->class] ?? null; if (null === $accessor) { - $accessor = \Closure::bind(static function ($o, $name) { - return $o->$name; - }, null, $metadata->class); + $accessor = \Closure::bind(static fn ($o, $name) => $o->$name, null, $metadata->class); $this->readAccessors[$metadata->class] = $accessor; } diff --git a/src/Annotation/AccessType.php b/src/Annotation/AccessType.php index 514a91616..bdcab3800 100644 --- a/src/Annotation/AccessType.php +++ b/src/Annotation/AccessType.php @@ -11,7 +11,7 @@ * @author Johannes M. Schmitt */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY)] -final class AccessType +final class AccessType implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/Accessor.php b/src/Annotation/Accessor.php index da88e782f..d9257db5d 100644 --- a/src/Annotation/Accessor.php +++ b/src/Annotation/Accessor.php @@ -11,7 +11,7 @@ * @author Johannes M. Schmitt */ #[\Attribute(\Attribute::TARGET_PROPERTY)] -final class Accessor +final class Accessor implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/AccessorOrder.php b/src/Annotation/AccessorOrder.php index 392bb72c0..af2b98e7a 100644 --- a/src/Annotation/AccessorOrder.php +++ b/src/Annotation/AccessorOrder.php @@ -13,7 +13,7 @@ * @author Johannes M. Schmitt */ #[\Attribute(\Attribute::TARGET_CLASS)] -final class AccessorOrder +final class AccessorOrder implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/Discriminator.php b/src/Annotation/Discriminator.php index b84a311be..f010036f8 100644 --- a/src/Annotation/Discriminator.php +++ b/src/Annotation/Discriminator.php @@ -9,7 +9,7 @@ * @Target("CLASS") */ #[\Attribute(\Attribute::TARGET_CLASS)] -class Discriminator +class Discriminator implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/Exclude.php b/src/Annotation/Exclude.php index 8660e9a42..c599062a4 100644 --- a/src/Annotation/Exclude.php +++ b/src/Annotation/Exclude.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY", "CLASS", "METHOD", "ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD)] -final class Exclude +final class Exclude implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/ExclusionPolicy.php b/src/Annotation/ExclusionPolicy.php index 90eb1fde5..968ced874 100644 --- a/src/Annotation/ExclusionPolicy.php +++ b/src/Annotation/ExclusionPolicy.php @@ -11,7 +11,7 @@ * @Target("CLASS") */ #[\Attribute(\Attribute::TARGET_CLASS)] -final class ExclusionPolicy +final class ExclusionPolicy implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/Expose.php b/src/Annotation/Expose.php index 3f03743a1..31087c3cd 100644 --- a/src/Annotation/Expose.php +++ b/src/Annotation/Expose.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class Expose +final class Expose implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/Groups.php b/src/Annotation/Groups.php index 740a89bc6..c82388e7a 100644 --- a/src/Annotation/Groups.php +++ b/src/Annotation/Groups.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class Groups +final class Groups implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/Inline.php b/src/Annotation/Inline.php index d3d61e12c..5d2e42404 100644 --- a/src/Annotation/Inline.php +++ b/src/Annotation/Inline.php @@ -9,6 +9,6 @@ * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class Inline +final class Inline implements SerializerAttribute { } diff --git a/src/Annotation/MaxDepth.php b/src/Annotation/MaxDepth.php index 82e7506b7..e459ca983 100644 --- a/src/Annotation/MaxDepth.php +++ b/src/Annotation/MaxDepth.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class MaxDepth +final class MaxDepth implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/PostDeserialize.php b/src/Annotation/PostDeserialize.php index ddfabd411..2e3e8b89f 100644 --- a/src/Annotation/PostDeserialize.php +++ b/src/Annotation/PostDeserialize.php @@ -16,6 +16,6 @@ * @author Johannes M. Schmitt */ #[\Attribute(\Attribute::TARGET_METHOD)] -final class PostDeserialize +final class PostDeserialize implements SerializerAttribute { } diff --git a/src/Annotation/PostSerialize.php b/src/Annotation/PostSerialize.php index 070be6b4b..7efc7ec01 100644 --- a/src/Annotation/PostSerialize.php +++ b/src/Annotation/PostSerialize.php @@ -9,6 +9,6 @@ * @Target("METHOD") */ #[\Attribute(\Attribute::TARGET_METHOD)] -final class PostSerialize +final class PostSerialize implements SerializerAttribute { } diff --git a/src/Annotation/PreSerialize.php b/src/Annotation/PreSerialize.php index b1adf2f79..6b2be0a57 100644 --- a/src/Annotation/PreSerialize.php +++ b/src/Annotation/PreSerialize.php @@ -17,6 +17,6 @@ * @author Johannes M. Schmitt */ #[\Attribute(\Attribute::TARGET_METHOD)] -final class PreSerialize +final class PreSerialize implements SerializerAttribute { } diff --git a/src/Annotation/ReadOnly.php b/src/Annotation/ReadOnly.php index 23bff2630..b5344e10e 100644 --- a/src/Annotation/ReadOnly.php +++ b/src/Annotation/ReadOnly.php @@ -2,4 +2,6 @@ declare(strict_types=1); -class_alias('JMS\Serializer\Annotation\DeprecatedReadOnly', 'JMS\Serializer\Annotation\ReadOnly'); +use JMS\Serializer\Annotation\DeprecatedReadOnly; + +class_alias(DeprecatedReadOnly::class, 'JMS\Serializer\Annotation\ReadOnly'); diff --git a/src/Annotation/ReadOnlyProperty.php b/src/Annotation/ReadOnlyProperty.php index d748b68c8..4df6b3e1b 100644 --- a/src/Annotation/ReadOnlyProperty.php +++ b/src/Annotation/ReadOnlyProperty.php @@ -11,7 +11,7 @@ * @final */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY)] -/* final */ class ReadOnlyProperty +/* final */ class ReadOnlyProperty implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/SerializedName.php b/src/Annotation/SerializedName.php index f2b5a6446..de2a34f4f 100644 --- a/src/Annotation/SerializedName.php +++ b/src/Annotation/SerializedName.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY","METHOD", "ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class SerializedName +final class SerializedName implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/SerializerAttribute.php b/src/Annotation/SerializerAttribute.php new file mode 100644 index 000000000..e314de16d --- /dev/null +++ b/src/Annotation/SerializerAttribute.php @@ -0,0 +1,12 @@ + */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] -final class VirtualProperty +final class VirtualProperty implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlAttribute.php b/src/Annotation/XmlAttribute.php index 31fc46376..724b5cfa8 100644 --- a/src/Annotation/XmlAttribute.php +++ b/src/Annotation/XmlAttribute.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class XmlAttribute +final class XmlAttribute implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlAttributeMap.php b/src/Annotation/XmlAttributeMap.php index bde6d013b..65370c0be 100644 --- a/src/Annotation/XmlAttributeMap.php +++ b/src/Annotation/XmlAttributeMap.php @@ -9,6 +9,6 @@ * @Target({"PROPERTY", "METHOD"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class XmlAttributeMap +final class XmlAttributeMap implements SerializerAttribute { } diff --git a/src/Annotation/XmlCollection.php b/src/Annotation/XmlCollection.php index e34ff58a0..99d3133a5 100644 --- a/src/Annotation/XmlCollection.php +++ b/src/Annotation/XmlCollection.php @@ -4,7 +4,7 @@ namespace JMS\Serializer\Annotation; -abstract class XmlCollection +abstract class XmlCollection implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlDiscriminator.php b/src/Annotation/XmlDiscriminator.php index bcb0e7950..bfd6fba48 100644 --- a/src/Annotation/XmlDiscriminator.php +++ b/src/Annotation/XmlDiscriminator.php @@ -9,7 +9,7 @@ * @Target("CLASS") */ #[\Attribute(\Attribute::TARGET_CLASS)] -class XmlDiscriminator +class XmlDiscriminator implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlElement.php b/src/Annotation/XmlElement.php index bbf198283..7dcb8edf8 100644 --- a/src/Annotation/XmlElement.php +++ b/src/Annotation/XmlElement.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class XmlElement +final class XmlElement implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlKeyValuePairs.php b/src/Annotation/XmlKeyValuePairs.php index f3a135033..38e3a645b 100644 --- a/src/Annotation/XmlKeyValuePairs.php +++ b/src/Annotation/XmlKeyValuePairs.php @@ -9,6 +9,6 @@ * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class XmlKeyValuePairs +final class XmlKeyValuePairs implements SerializerAttribute { } diff --git a/src/Annotation/XmlNamespace.php b/src/Annotation/XmlNamespace.php index 5568aede6..681462cbd 100644 --- a/src/Annotation/XmlNamespace.php +++ b/src/Annotation/XmlNamespace.php @@ -9,7 +9,7 @@ * @Target("CLASS") */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] -final class XmlNamespace +final class XmlNamespace implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlRoot.php b/src/Annotation/XmlRoot.php index 9034d35da..041bd63ad 100644 --- a/src/Annotation/XmlRoot.php +++ b/src/Annotation/XmlRoot.php @@ -9,7 +9,7 @@ * @Target("CLASS") */ #[\Attribute(\Attribute::TARGET_CLASS)] -final class XmlRoot +final class XmlRoot implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Annotation/XmlValue.php b/src/Annotation/XmlValue.php index bb49967f6..12535cdf7 100644 --- a/src/Annotation/XmlValue.php +++ b/src/Annotation/XmlValue.php @@ -9,7 +9,7 @@ * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] -final class XmlValue +final class XmlValue implements SerializerAttribute { use AnnotationUtilsTrait; diff --git a/src/Builder/CallbackDriverFactory.php b/src/Builder/CallbackDriverFactory.php index 1bf2fc913..b35d4f5e1 100644 --- a/src/Builder/CallbackDriverFactory.php +++ b/src/Builder/CallbackDriverFactory.php @@ -12,15 +12,19 @@ final class CallbackDriverFactory implements DriverFactoryInterface { /** * @var callable + * @phpstan-var callable(array $metadataDirs, Reader|null $reader): DriverInterface */ private $callback; + /** + * @phpstan-param callable(array $metadataDirs, Reader|null $reader): DriverInterface $callable + */ public function __construct(callable $callable) { $this->callback = $callable; } - public function createDriver(array $metadataDirs, Reader $reader): DriverInterface + public function createDriver(array $metadataDirs, ?Reader $reader = null): DriverInterface { $driver = \call_user_func($this->callback, $metadataDirs, $reader); if (!$driver instanceof DriverInterface) { diff --git a/src/Builder/DefaultDriverFactory.php b/src/Builder/DefaultDriverFactory.php index e893a9355..74ca1d9ed 100644 --- a/src/Builder/DefaultDriverFactory.php +++ b/src/Builder/DefaultDriverFactory.php @@ -5,11 +5,12 @@ namespace JMS\Serializer\Builder; use Doctrine\Common\Annotations\Reader; +use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Expression\CompilableExpressionEvaluatorInterface; -use JMS\Serializer\Metadata\Driver\AnnotationDriver; -use JMS\Serializer\Metadata\Driver\AttributeDriver; +use JMS\Serializer\Metadata\Driver\AnnotationOrAttributeDriver; use JMS\Serializer\Metadata\Driver\DefaultValuePropertyDriver; use JMS\Serializer\Metadata\Driver\EnumPropertiesDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Metadata\Driver\TypedPropertiesDriver; use JMS\Serializer\Metadata\Driver\XmlDriver; use JMS\Serializer\Metadata\Driver\YamlDriver; @@ -19,6 +20,7 @@ use Metadata\Driver\DriverChain; use Metadata\Driver\DriverInterface; use Metadata\Driver\FileLocator; +use Symfony\Component\Yaml\Yaml; final class DefaultDriverFactory implements DriverFactoryInterface { @@ -54,30 +56,44 @@ public function enableEnumSupport(bool $enableEnumSupport = true): void $this->enableEnumSupport = $enableEnumSupport; } - public function createDriver(array $metadataDirs, Reader $annotationReader): DriverInterface + public function createDriver(array $metadataDirs, ?Reader $annotationReader = null): DriverInterface { - if (PHP_VERSION_ID >= 80000) { - $annotationReader = new AttributeDriver\AttributeReader($annotationReader); + if (PHP_VERSION_ID < 80000 && empty($metadataDirs) && !interface_exists(Reader::class)) { + throw new RuntimeException(sprintf('To use "%s", either a list of metadata directories must be provided, the "doctrine/annotations" package installed, or use PHP 8.0 or later.', self::class)); } - $driver = new AnnotationDriver($annotationReader, $this->propertyNamingStrategy, $this->typeParser); + /* + * Build the sorted list of metadata drivers based on the environment. The final order should be: + * + * - YAML Driver + * - XML Driver + * - Annotations/Attributes Driver + * - Null (Fallback) Driver + */ + $metadataDrivers = []; + + if (PHP_VERSION_ID >= 80000 || $annotationReader instanceof Reader) { + $metadataDrivers[] = new AnnotationOrAttributeDriver($this->propertyNamingStrategy, $this->typeParser, $this->expressionEvaluator, $annotationReader); + } if (!empty($metadataDirs)) { $fileLocator = new FileLocator($metadataDirs); - $driver = new DriverChain([ - new YamlDriver($fileLocator, $this->propertyNamingStrategy, $this->typeParser, $this->expressionEvaluator), - new XmlDriver($fileLocator, $this->propertyNamingStrategy, $this->typeParser, $this->expressionEvaluator), - $driver, - ]); + + array_unshift($metadataDrivers, new XmlDriver($fileLocator, $this->propertyNamingStrategy, $this->typeParser, $this->expressionEvaluator)); + + if (class_exists(Yaml::class)) { + array_unshift($metadataDrivers, new YamlDriver($fileLocator, $this->propertyNamingStrategy, $this->typeParser, $this->expressionEvaluator)); + } } + $driver = new DriverChain($metadataDrivers); + $driver->addDriver(new NullDriver($this->propertyNamingStrategy)); + if ($this->enableEnumSupport) { $driver = new EnumPropertiesDriver($driver); } - if (PHP_VERSION_ID >= 70400) { - $driver = new TypedPropertiesDriver($driver, $this->typeParser); - } + $driver = new TypedPropertiesDriver($driver, $this->typeParser); if (PHP_VERSION_ID >= 80000) { $driver = new DefaultValuePropertyDriver($driver); diff --git a/src/Builder/DocBlockDriverFactory.php b/src/Builder/DocBlockDriverFactory.php index 3188a01db..67f0ec527 100644 --- a/src/Builder/DocBlockDriverFactory.php +++ b/src/Builder/DocBlockDriverFactory.php @@ -26,7 +26,7 @@ public function __construct(DriverFactoryInterface $driverFactoryToDecorate, ?Pa $this->typeParser = $typeParser; } - public function createDriver(array $metadataDirs, Reader $annotationReader): DriverInterface + public function createDriver(array $metadataDirs, ?Reader $annotationReader = null): DriverInterface { $driver = $this->driverFactoryToDecorate->createDriver($metadataDirs, $annotationReader); diff --git a/src/Builder/DriverFactoryInterface.php b/src/Builder/DriverFactoryInterface.php index d7655e115..7bfade916 100644 --- a/src/Builder/DriverFactoryInterface.php +++ b/src/Builder/DriverFactoryInterface.php @@ -9,5 +9,5 @@ interface DriverFactoryInterface { - public function createDriver(array $metadataDirs, Reader $annotationReader): DriverInterface; + public function createDriver(array $metadataDirs, ?Reader $annotationReader = null): DriverInterface; } diff --git a/src/Context.php b/src/Context.php index 63fcfb6f4..ca8472966 100644 --- a/src/Context.php +++ b/src/Context.php @@ -241,9 +241,6 @@ public function getMetadataStack(): \SplStack return $this->metadataStack; } - /** - * @return array - */ public function getCurrentPath(): array { if (!$this->metadataStack) { diff --git a/src/EventDispatcher/PreSerializeEvent.php b/src/EventDispatcher/PreSerializeEvent.php index 2e9a575f5..38f15fce6 100644 --- a/src/EventDispatcher/PreSerializeEvent.php +++ b/src/EventDispatcher/PreSerializeEvent.php @@ -6,9 +6,6 @@ class PreSerializeEvent extends ObjectEvent { - /** - * @param array $params - */ public function setType(string $typeName, array $params = []): void { $this->type = ['name' => $typeName, 'params' => $params]; diff --git a/src/Exception/NonCastableTypeException.php b/src/Exception/NonCastableTypeException.php index 97d0be2a7..7aa297c20 100644 --- a/src/Exception/NonCastableTypeException.php +++ b/src/Exception/NonCastableTypeException.php @@ -22,8 +22,8 @@ public function __construct(string $expectedType, $value) sprintf( 'Cannot convert value of type "%s" to %s', gettype($value), - $expectedType - ) + $expectedType, + ), ); } diff --git a/src/Exception/NonVisitableTypeException.php b/src/Exception/NonVisitableTypeException.php index 53f05ecf0..ee011b728 100644 --- a/src/Exception/NonVisitableTypeException.php +++ b/src/Exception/NonVisitableTypeException.php @@ -20,7 +20,7 @@ public static function fromDataAndType($data, array $type, ?RuntimeException $pr return new self( sprintf('Type %s cannot be visited as %s', get_debug_type($data), $type['name']), 0, - $previous + $previous, ); } } diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php index e71f661ce..a84f5416e 100644 --- a/src/Exception/RuntimeException.php +++ b/src/Exception/RuntimeException.php @@ -16,7 +16,7 @@ public static function noMetadataForProperty(string $class, string $prop): self return new RuntimeException(sprintf( 'You must define a type for %s::$%s.', $class, - $prop + $prop, )); } } diff --git a/src/GraphNavigator/DeserializationGraphNavigator.php b/src/GraphNavigator/DeserializationGraphNavigator.php index 495df3f1f..a29e43c12 100644 --- a/src/GraphNavigator/DeserializationGraphNavigator.php +++ b/src/GraphNavigator/DeserializationGraphNavigator.php @@ -243,7 +243,7 @@ private function resolveMetadata($data, ClassMetadata $metadata): ?ClassMetadata 'The type value "%s" does not exist in the discriminator map of class "%s". Available types: %s', $typeValue, $metadata->name, - implode(', ', array_keys($metadata->discriminatorMap)) + implode(', ', array_keys($metadata->discriminatorMap)), )); } diff --git a/src/GraphNavigator/SerializationGraphNavigator.php b/src/GraphNavigator/SerializationGraphNavigator.php index 975788b73..1de6e3bb7 100644 --- a/src/GraphNavigator/SerializationGraphNavigator.php +++ b/src/GraphNavigator/SerializationGraphNavigator.php @@ -104,6 +104,7 @@ public function initialize(VisitorInterface $visitor, Context $context): void assert($context instanceof SerializationContext); parent::initialize($visitor, $context); + $this->shouldSerializeNull = $context->shouldSerializeNull(); } diff --git a/src/Handler/DateHandler.php b/src/Handler/DateHandler.php index da187b28a..bc8fe94a6 100644 --- a/src/Handler/DateHandler.php +++ b/src/Handler/DateHandler.php @@ -256,7 +256,7 @@ private function parseDateTime($data, array $type, bool $immutable = false): \Da throw new RuntimeException(sprintf( 'Invalid datetime "%s", expected one of the format %s.', $data, - '"' . implode('", "', $formatTried) . '"' + '"' . implode('", "', $formatTried) . '"', )); } @@ -279,9 +279,6 @@ private function parseDateInterval(string $data): \DateInterval return $dateInterval; } - /** - * @param array $type - */ private function getDeserializationFormats(array $type): array { if (isset($type['params'][2])) { @@ -291,9 +288,6 @@ private function getDeserializationFormats(array $type): array return [$this->getFormat($type)]; } - /** - * @param array $type - */ private function getFormat(array $type): string { return $type['params'][0] ?? $this->defaultFormat; diff --git a/src/Handler/EnumHandler.php b/src/Handler/EnumHandler.php index 1adbc051a..44e223bed 100644 --- a/src/Handler/EnumHandler.php +++ b/src/Handler/EnumHandler.php @@ -44,7 +44,7 @@ public function serializeEnum( array $type, SerializationContext $context ) { - if (isset($type['params'][1]) && 'value' === $type['params'][1]) { + if ((isset($type['params'][1]) && 'value' === $type['params'][1]) || (!isset($type['params'][1]) && $enum instanceof \BackedEnum)) { if (!$enum instanceof \BackedEnum) { throw new InvalidMetadataException(sprintf('The type "%s" is not a backed enum, thus you can not use "value" as serialization mode for its value.', get_class($enum))); } diff --git a/src/Handler/FormErrorHandler.php b/src/Handler/FormErrorHandler.php index dde738d0a..c794e2b2f 100644 --- a/src/Handler/FormErrorHandler.php +++ b/src/Handler/FormErrorHandler.php @@ -63,7 +63,7 @@ public function __construct(?object $translator = null, string $translationDomai self::class, TranslatorInterface::class, TranslatorContract::class, - get_class($translator) + get_class($translator), )); } @@ -71,9 +71,6 @@ public function __construct(?object $translator = null, string $translationDomai $this->translationDomain = $translationDomain; } - /** - * @param array $type - */ public function serializeFormToXml(XmlSerializationVisitor $visitor, FormInterface $form, array $type): \DOMElement { $formNode = $visitor->getDocument()->createElement('form'); @@ -98,25 +95,16 @@ public function serializeFormToXml(XmlSerializationVisitor $visitor, FormInterfa return $formNode; } - /** - * @param array $type - */ public function serializeFormToJson(SerializationVisitorInterface $visitor, FormInterface $form, array $type): \ArrayObject { return $this->convertFormToArray($visitor, $form); } - /** - * @param array $type - */ public function serializeFormErrorToXml(XmlSerializationVisitor $visitor, FormError $formError, array $type): \DOMCdataSection { return $visitor->getDocument()->createCDATASection($this->getErrorMessage($formError)); } - /** - * @param array $type - */ public function serializeFormErrorToJson(SerializationVisitorInterface $visitor, FormError $formError, array $type): string { return $this->getErrorMessage($formError); @@ -141,7 +129,7 @@ private function getErrorMessage(FormError $error): ?string private function convertFormToArray(SerializationVisitorInterface $visitor, FormInterface $data): \ArrayObject { - /** @var \ArrayObject{errors?: string[], children?: array} $form */ + /** @var \ArrayObject{errors?:array,children?:array} $form */ $form = new \ArrayObject(); $errors = []; foreach ($data->getErrors() as $error) { diff --git a/src/Handler/LazyHandlerRegistry.php b/src/Handler/LazyHandlerRegistry.php index a569dca43..7914aeaf3 100644 --- a/src/Handler/LazyHandlerRegistry.php +++ b/src/Handler/LazyHandlerRegistry.php @@ -31,6 +31,7 @@ public function __construct($container, array $handlers = []) } parent::__construct($handlers); + $this->container = $container; } @@ -40,6 +41,7 @@ public function __construct($container, array $handlers = []) public function registerHandler(int $direction, string $typeName, string $format, $handler): void { parent::registerHandler($direction, $typeName, $format, $handler); + unset($this->initializedHandlers[$direction][$typeName][$format]); } diff --git a/src/JsonDeserializationStrictVisitor.php b/src/JsonDeserializationStrictVisitor.php index 83299e3c5..3c4e69a85 100644 --- a/src/JsonDeserializationStrictVisitor.php +++ b/src/JsonDeserializationStrictVisitor.php @@ -29,6 +29,7 @@ public function __construct( public function setNavigator(GraphNavigatorInterface $navigator): void { parent::setNavigator($navigator); + $this->wrappedDeserializationVisitor->setNavigator($navigator); } diff --git a/src/JsonDeserializationVisitor.php b/src/JsonDeserializationVisitor.php index 2437521e9..625c8c722 100644 --- a/src/JsonDeserializationVisitor.php +++ b/src/JsonDeserializationVisitor.php @@ -142,7 +142,7 @@ public function visitDiscriminatorMapProperty($data, ClassMetadata $metadata): s throw new LogicException(sprintf( 'The discriminator field name "%s" for base-class "%s" was not found in input data.', $metadata->discriminatorFieldName, - $metadata->name + $metadata->name, )); } diff --git a/src/Metadata/ClassMetadata.php b/src/Metadata/ClassMetadata.php index c8e90b913..660f1e456 100644 --- a/src/Metadata/ClassMetadata.php +++ b/src/Metadata/ClassMetadata.php @@ -185,6 +185,7 @@ public function setAccessorOrder(string $order, array $customOrder = []): void public function addPropertyMetadata(BasePropertyMetadata $metadata): void { parent::addPropertyMetadata($metadata); + $this->sortProperties(); if ($metadata instanceof PropertyMetadata && $metadata->excludeIf) { $this->usingExpression = true; @@ -239,7 +240,7 @@ public function merge(MergeableInterface $object): void 'The discriminator of class "%s" would overwrite the discriminator of the parent class "%s". Please define all possible sub-classes in the discriminator of %s.', $object->name, $this->discriminatorBaseClass, - $this->discriminatorBaseClass + $this->discriminatorBaseClass, )); } elseif (!$this->discriminatorFieldName && $object->discriminatorFieldName) { $this->discriminatorFieldName = $object->discriminatorFieldName; @@ -358,7 +359,7 @@ private function handleDiscriminatorProperty(): void throw new InvalidMetadataException(sprintf( 'The sub-class "%s" is not listed in the discriminator of the base class "%s".', $this->name, - $this->discriminatorBaseClass + $this->discriminatorBaseClass, )); } @@ -372,7 +373,7 @@ private function handleDiscriminatorProperty(): void 'The discriminator field name "%s" of the base-class "%s" conflicts with a regular property of the sub-class "%s".', $this->discriminatorFieldName, $this->discriminatorBaseClass, - $this->name + $this->name, )); } @@ -380,7 +381,7 @@ private function handleDiscriminatorProperty(): void $this->name, $this->discriminatorFieldName, $typeValue, - $this->discriminatorGroups + $this->discriminatorGroups, ); $discriminatorProperty->serializedName = $this->discriminatorFieldName; $discriminatorProperty->xmlAttribute = $this->xmlDiscriminatorAttribute; diff --git a/src/Metadata/Driver/AnnotationDriver.php b/src/Metadata/Driver/AnnotationDriver.php index 86f5a5bf4..942b339ca 100644 --- a/src/Metadata/Driver/AnnotationDriver.php +++ b/src/Metadata/Driver/AnnotationDriver.php @@ -9,6 +9,9 @@ use JMS\Serializer\Naming\PropertyNamingStrategyInterface; use JMS\Serializer\Type\ParserInterface; +/** + * @deprecated + */ class AnnotationDriver extends AnnotationOrAttributeDriver { /** @@ -18,7 +21,7 @@ class AnnotationDriver extends AnnotationOrAttributeDriver public function __construct(Reader $reader, PropertyNamingStrategyInterface $namingStrategy, ?ParserInterface $typeParser = null, ?CompilableExpressionEvaluatorInterface $expressionEvaluator = null) { - parent::__construct($namingStrategy, $typeParser, $expressionEvaluator); + parent::__construct($namingStrategy, $typeParser, $expressionEvaluator, $reader); $this->reader = $reader; } diff --git a/src/Metadata/Driver/AnnotationOrAttributeDriver.php b/src/Metadata/Driver/AnnotationOrAttributeDriver.php index 461d831c1..92becb724 100644 --- a/src/Metadata/Driver/AnnotationOrAttributeDriver.php +++ b/src/Metadata/Driver/AnnotationOrAttributeDriver.php @@ -4,6 +4,7 @@ namespace JMS\Serializer\Metadata\Driver; +use Doctrine\Common\Annotations\Reader; use JMS\Serializer\Annotation\Accessor; use JMS\Serializer\Annotation\AccessorOrder; use JMS\Serializer\Annotation\AccessType; @@ -19,6 +20,7 @@ use JMS\Serializer\Annotation\PreSerialize; use JMS\Serializer\Annotation\ReadOnlyProperty; use JMS\Serializer\Annotation\SerializedName; +use JMS\Serializer\Annotation\SerializerAttribute; use JMS\Serializer\Annotation\Since; use JMS\Serializer\Annotation\SkipWhenEmpty; use JMS\Serializer\Annotation\Type; @@ -47,7 +49,7 @@ use Metadata\Driver\DriverInterface; use Metadata\MethodMetadata; -abstract class AnnotationOrAttributeDriver implements DriverInterface +class AnnotationOrAttributeDriver implements DriverInterface { use ExpressionMetadataTrait; @@ -61,15 +63,23 @@ abstract class AnnotationOrAttributeDriver implements DriverInterface */ private $namingStrategy; - public function __construct(PropertyNamingStrategyInterface $namingStrategy, ?ParserInterface $typeParser = null, ?CompilableExpressionEvaluatorInterface $expressionEvaluator = null) + /** + * @var Reader + */ + private $reader; + + public function __construct(PropertyNamingStrategyInterface $namingStrategy, ?ParserInterface $typeParser = null, ?CompilableExpressionEvaluatorInterface $expressionEvaluator = null, ?Reader $reader = null) { $this->typeParser = $typeParser ?: new Parser(); $this->namingStrategy = $namingStrategy; $this->expressionEvaluator = $expressionEvaluator; + $this->reader = $reader; } public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadata { + $configured = false; + $classMetadata = new ClassMetadata($name = $class->name); $fileResource = $class->getFilename(); @@ -86,6 +96,8 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat $readOnlyClass = false; foreach ($this->getClassAnnotations($class) as $annot) { + $configured = true; + if ($annot instanceof ExclusionPolicy) { $exclusionPolicy = $annot->policy; } elseif ($annot instanceof XmlRoot) { @@ -120,7 +132,7 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat $virtualPropertyMetadata = new ExpressionPropertyMetadata( $name, $annot->name, - $this->parseExpression($annot->exp) + $this->parseExpression($annot->exp), ); $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesAnnotations[] = $annot->options; @@ -135,6 +147,8 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat $methodAnnotations = $this->getMethodAnnotations($method); foreach ($methodAnnotations as $annot) { + $configured = true; + if ($annot instanceof PreSerialize) { $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->name)); continue 2; @@ -174,6 +188,8 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat $propertyAnnotations = $propertiesAnnotations[$propertyKey]; foreach ($propertyAnnotations as $annot) { + $configured = true; + if ($annot instanceof Since) { $propertyMetadata->sinceVersion = $annot->version; } elseif ($annot instanceof Until) { @@ -232,7 +248,7 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat throw new InvalidMetadataException(sprintf( 'Invalid group name "%s" on "%s", did you mean to create multiple groups?', implode(', ', $propertyMetadata->groups), - $propertyMetadata->class . '->' . $propertyMetadata->name + $propertyMetadata->class . '->' . $propertyMetadata->name, )); } } @@ -274,21 +290,74 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat } } + // if (!$configured) { + // return null; + // uncomment the above line afetr a couple of months + // } + return $classMetadata; } /** - * @return list + * @return list */ - abstract protected function getClassAnnotations(\ReflectionClass $class): array; + protected function getClassAnnotations(\ReflectionClass $class): array + { + $annotations = []; + + if (PHP_VERSION_ID >= 80000) { + $annotations = array_map( + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $class->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF), + ); + } + + if (null !== $this->reader) { + $annotations = array_merge($annotations, $this->reader->getClassAnnotations($class)); + } + + return $annotations; + } /** - * @return list + * @return list */ - abstract protected function getMethodAnnotations(\ReflectionMethod $method): array; + protected function getMethodAnnotations(\ReflectionMethod $method): array + { + $annotations = []; + + if (PHP_VERSION_ID >= 80000) { + $annotations = array_map( + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $method->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF), + ); + } + + if (null !== $this->reader) { + $annotations = array_merge($annotations, $this->reader->getMethodAnnotations($method)); + } + + return $annotations; + } /** - * @return list + * @return list */ - abstract protected function getPropertyAnnotations(\ReflectionProperty $property): array; + protected function getPropertyAnnotations(\ReflectionProperty $property): array + { + $annotations = []; + + if (PHP_VERSION_ID >= 80000) { + $annotations = array_map( + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $property->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF), + ); + } + + if (null !== $this->reader) { + $annotations = array_merge($annotations, $this->reader->getPropertyAnnotations($property)); + } + + return $annotations; + } } diff --git a/src/Metadata/Driver/AttributeDriver.php b/src/Metadata/Driver/AttributeDriver.php index 8d794c64b..2c6c1a2c9 100644 --- a/src/Metadata/Driver/AttributeDriver.php +++ b/src/Metadata/Driver/AttributeDriver.php @@ -4,44 +4,40 @@ namespace JMS\Serializer\Metadata\Driver; +use JMS\Serializer\Annotation\SerializerAttribute; + class AttributeDriver extends AnnotationOrAttributeDriver { /** - * @return list + * @return list */ protected function getClassAnnotations(\ReflectionClass $class): array { return array_map( - static function (\ReflectionAttribute $attribute): object { - return $attribute->newInstance(); - }, - $class->getAttributes() + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $class->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF), ); } /** - * @return list + * @return list */ protected function getMethodAnnotations(\ReflectionMethod $method): array { return array_map( - static function (\ReflectionAttribute $attribute): object { - return $attribute->newInstance(); - }, - $method->getAttributes() + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $method->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF), ); } /** - * @return list + * @return list */ protected function getPropertyAnnotations(\ReflectionProperty $property): array { return array_map( - static function (\ReflectionAttribute $attribute): object { - return $attribute->newInstance(); - }, - $property->getAttributes() + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $property->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF), ); } } diff --git a/src/Metadata/Driver/AttributeDriver/AttributeReader.php b/src/Metadata/Driver/AttributeDriver/AttributeReader.php index 454019039..12da20f58 100644 --- a/src/Metadata/Driver/AttributeDriver/AttributeReader.php +++ b/src/Metadata/Driver/AttributeDriver/AttributeReader.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Metadata\Driver\AttributeDriver; use Doctrine\Common\Annotations\Reader; +use JMS\Serializer\Annotation\SerializerAttribute; use ReflectionClass; use ReflectionMethod; use ReflectionProperty; @@ -26,47 +27,50 @@ public function __construct(Reader $reader) public function getClassAnnotations(ReflectionClass $class): array { - $attributes = $class->getAttributes(); + $attributes = $class->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF); return array_merge($this->reader->getClassAnnotations($class), $this->buildAnnotations($attributes)); } public function getClassAnnotation(ReflectionClass $class, $annotationName): ?object { - $attributes = $class->getAttributes($annotationName); + $attributes = $class->getAttributes($annotationName, \ReflectionAttribute::IS_INSTANCEOF); return $this->reader->getClassAnnotation($class, $annotationName) ?? $this->buildAnnotation($attributes); } public function getMethodAnnotations(ReflectionMethod $method): array { - $attributes = $method->getAttributes(); + $attributes = $method->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF); return array_merge($this->reader->getMethodAnnotations($method), $this->buildAnnotations($attributes)); } public function getMethodAnnotation(ReflectionMethod $method, $annotationName): ?object { - $attributes = $method->getAttributes($annotationName); + $attributes = $method->getAttributes($annotationName, \ReflectionAttribute::IS_INSTANCEOF); return $this->reader->getClassAnnotation($method, $annotationName) ?? $this->buildAnnotation($attributes); } public function getPropertyAnnotations(ReflectionProperty $property): array { - $attributes = $property->getAttributes(); + $attributes = $property->getAttributes(SerializerAttribute::class, \ReflectionAttribute::IS_INSTANCEOF); return array_merge($this->reader->getPropertyAnnotations($property), $this->buildAnnotations($attributes)); } public function getPropertyAnnotation(ReflectionProperty $property, $annotationName): ?object { - $attributes = $property->getAttributes($annotationName); + $attributes = $property->getAttributes($annotationName, \ReflectionAttribute::IS_INSTANCEOF); return $this->reader->getClassAnnotation($property, $annotationName) ?? $this->buildAnnotation($attributes); } - private function buildAnnotation(array $attributes): ?object + /** + * @param list<\ReflectionAttribute> $attributes + */ + private function buildAnnotation(array $attributes): ?SerializerAttribute { if (!isset($attributes[0])) { return null; @@ -75,15 +79,14 @@ private function buildAnnotation(array $attributes): ?object return $attributes[0]->newInstance(); } + /** + * @return list + */ private function buildAnnotations(array $attributes): array { - $result = []; - foreach ($attributes as $attribute) { - if (0 === strpos($attribute->getName(), 'JMS\Serializer\Annotation\\')) { - $result[] = $attribute->newInstance(); - } - } - - return $result; + return array_map( + static fn (\ReflectionAttribute $attribute): object => $attribute->newInstance(), + $attributes, + ); } } diff --git a/src/Metadata/Driver/DocBlockDriver.php b/src/Metadata/Driver/DocBlockDriver.php index f7b1f97e3..b8ce046b3 100644 --- a/src/Metadata/Driver/DocBlockDriver.php +++ b/src/Metadata/Driver/DocBlockDriver.php @@ -70,11 +70,11 @@ public function loadMetadataForClass(ReflectionClass $class): ?ClassMetadata try { if ($propertyMetadata instanceof VirtualPropertyMetadata) { $type = $this->docBlockTypeResolver->getMethodDocblockTypeHint( - new ReflectionMethod($propertyMetadata->class, $propertyMetadata->getter) + new ReflectionMethod($propertyMetadata->class, $propertyMetadata->getter), ); } else { $type = $this->docBlockTypeResolver->getPropertyDocblockTypeHint( - new ReflectionProperty($propertyMetadata->class, $propertyMetadata->name) + new ReflectionProperty($propertyMetadata->class, $propertyMetadata->name), ); } diff --git a/src/Metadata/Driver/DocBlockDriver/DocBlockTypeResolver.php b/src/Metadata/Driver/DocBlockDriver/DocBlockTypeResolver.php index 0a3d515e5..d5fad5b64 100644 --- a/src/Metadata/Driver/DocBlockDriver/DocBlockTypeResolver.php +++ b/src/Metadata/Driver/DocBlockDriver/DocBlockTypeResolver.php @@ -26,6 +26,7 @@ final class DocBlockTypeResolver { /** resolve single use statements */ private const SINGLE_USE_STATEMENTS_REGEX = '/^[^\S\r\n]*use[\s]*([^;\n]*)[\s]*;$/m'; + /** resolve group use statements */ private const GROUP_USE_STATEMENTS_REGEX = '/^[^\S\r\n]*use[[\s]*([^;\n]*)[\s]*{([a-zA-Z0-9\s\n\r,]*)};$/m'; private const GLOBAL_NAMESPACE_PREFIX = '\\'; @@ -114,17 +115,13 @@ private function getDocBlocTypeHint($reflector): ?string // Generic array syntax: array | array<\Foo\Bar\Product> | array if ($type instanceof GenericTypeNode) { if ($this->isSimpleType($type->type, 'array')) { - $resolvedTypes = array_map(function (TypeNode $node) use ($reflector) { - return $this->resolveTypeFromTypeNode($node, $reflector); - }, $type->genericTypes); + $resolvedTypes = array_map(fn (TypeNode $node) => $this->resolveTypeFromTypeNode($node, $reflector), $type->genericTypes); return 'array<' . implode(',', $resolvedTypes) . '>'; } if ($this->isSimpleType($type->type, 'list')) { - $resolvedTypes = array_map(function (TypeNode $node) use ($reflector) { - return $this->resolveTypeFromTypeNode($node, $reflector); - }, $type->genericTypes); + $resolvedTypes = array_map(fn (TypeNode $node) => $this->resolveTypeFromTypeNode($node, $reflector), $type->genericTypes); return 'array'; } @@ -193,9 +190,7 @@ private function flattenParamTagValueTypes(string $parameterName, array $varTagV */ private function filterNullFromTypes(array $types): array { - return array_values(array_filter(array_map(function (TypeNode $node) { - return $this->isNullType($node) ? null : $node; - }, $types))); + return array_values(array_filter(array_map(fn (TypeNode $node) => $this->isNullType($node) ? null : $node, $types))); } /** @@ -248,10 +243,6 @@ private function resolveTypeFromTypeNode(TypeNode $typeNode, $reflector): string */ private function expandClassNameUsingUseStatements(string $typeHint, \ReflectionClass $declaringClass, $reflector): string { - if ($this->isClassOrInterface($typeHint)) { - return $typeHint; - } - $expandedClassName = $declaringClass->getNamespaceName() . '\\' . $typeHint; if ($this->isClassOrInterface($expandedClassName)) { return $expandedClassName; @@ -281,6 +272,10 @@ private function expandClassNameUsingUseStatements(string $typeHint, \Reflection } } + if ($this->isClassOrInterface($typeHint)) { + return $typeHint; + } + throw new \InvalidArgumentException(sprintf("Can't use incorrect type %s for collection in %s:%s", $typeHint, $declaringClass->getName(), $reflector->getName())); } @@ -426,9 +421,7 @@ private function getPhpstanType(\ReflectionClass $declaringClass, string $typeHi return sprintf('array<%s>', implode( ',', - array_map(static function (string $type) use ($reflector, $self) { - return $self->resolveType(trim($type), $reflector); - }, $types) + array_map(static fn (string $type) => $self->resolveType(trim($type), $reflector), $types), )); } } diff --git a/src/Metadata/Driver/DoctrineTypeDriver.php b/src/Metadata/Driver/DoctrineTypeDriver.php index 63592e8be..e51f8d5c4 100644 --- a/src/Metadata/Driver/DoctrineTypeDriver.php +++ b/src/Metadata/Driver/DoctrineTypeDriver.php @@ -27,7 +27,7 @@ protected function setDiscriminator(DoctrineClassMetadata $doctrineMetadata, Cla ) { $classMetadata->setDiscriminator( $doctrineMetadata->discriminatorColumn['name'], - $doctrineMetadata->discriminatorMap + $doctrineMetadata->discriminatorMap, ); } } diff --git a/src/Metadata/Driver/NullDriver.php b/src/Metadata/Driver/NullDriver.php index fbbf750f0..30bc387a4 100644 --- a/src/Metadata/Driver/NullDriver.php +++ b/src/Metadata/Driver/NullDriver.php @@ -5,11 +5,23 @@ namespace JMS\Serializer\Metadata\Driver; use JMS\Serializer\Metadata\ClassMetadata; +use JMS\Serializer\Metadata\PropertyMetadata; +use JMS\Serializer\Naming\PropertyNamingStrategyInterface; use Metadata\ClassMetadata as BaseClassMetadata; use Metadata\Driver\DriverInterface; class NullDriver implements DriverInterface { + /** + * @var PropertyNamingStrategyInterface + */ + private $namingStrategy; + + public function __construct(PropertyNamingStrategyInterface $namingStrategy) + { + $this->namingStrategy = $namingStrategy; + } + public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadata { $classMetadata = new ClassMetadata($name = $class->name); @@ -18,6 +30,20 @@ public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadat $classMetadata->fileResources[] = $fileResource; } + foreach ($class->getProperties() as $property) { + if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) { + continue; + } + + $propertyMetadata = new PropertyMetadata($name, $property->getName()); + + if (!$propertyMetadata->serializedName) { + $propertyMetadata->serializedName = $this->namingStrategy->translateName($propertyMetadata); + } + + $classMetadata->addPropertyMetadata($propertyMetadata); + } + return $classMetadata; } } diff --git a/src/Metadata/Driver/TypedPropertiesDriver.php b/src/Metadata/Driver/TypedPropertiesDriver.php index 951199b23..b628ad80a 100644 --- a/src/Metadata/Driver/TypedPropertiesDriver.php +++ b/src/Metadata/Driver/TypedPropertiesDriver.php @@ -74,10 +74,6 @@ public function loadMetadataForClass(ReflectionClass $class): ?ClassMetadata \assert($classMetadata instanceof SerializerClassMetadata); - if (PHP_VERSION_ID <= 70400) { - return $classMetadata; - } - // We base our scan on the internal driver's property list so that we // respect any internal allow/blocklist like in the AnnotationDriver foreach ($classMetadata->propertyMetadata as $propertyMetadata) { diff --git a/src/Metadata/Driver/XmlDriver.php b/src/Metadata/Driver/XmlDriver.php index 2d8cca3e3..a6ba580ec 100644 --- a/src/Metadata/Driver/XmlDriver.php +++ b/src/Metadata/Driver/XmlDriver.php @@ -39,6 +39,7 @@ class XmlDriver extends AbstractFileDriver public function __construct(FileLocatorInterface $locator, PropertyNamingStrategyInterface $namingStrategy, ?ParserInterface $typeParser = null, ?CompilableExpressionEvaluatorInterface $expressionEvaluator = null) { parent::__construct($locator); + $this->typeParser = $typeParser ?? new Parser(); $this->namingStrategy = $namingStrategy; $this->expressionEvaluator = $expressionEvaluator; @@ -154,7 +155,7 @@ protected function loadMetadataFromFile(\ReflectionClass $class, string $path): $virtualPropertyMetadata = new ExpressionPropertyMetadata( $name, (string) $method->attributes()->name, - $this->parseExpression((string) $method->attributes()->expression) + $this->parseExpression((string) $method->attributes()->expression), ); } else { if (!isset($method->attributes()->method)) { @@ -325,7 +326,7 @@ protected function loadMetadataFromFile(\ReflectionClass $class, string $path): $pMetadata->setAccessor( (string) ($pElem->attributes()->{'access-type'} ?: $classAccessType), $getter ? (string) $getter : null, - $setter ? (string) $setter : null + $setter ? (string) $setter : null, ); if (null !== $inline = $pElem->attributes()->inline) { diff --git a/src/Metadata/Driver/YamlDriver.php b/src/Metadata/Driver/YamlDriver.php index 60d52762d..8dd61f10e 100644 --- a/src/Metadata/Driver/YamlDriver.php +++ b/src/Metadata/Driver/YamlDriver.php @@ -74,8 +74,8 @@ public function getAllClassNames(): array throw new RuntimeException( sprintf( 'Locator "%s" must be an instance of "AdvancedFileLocatorInterface".', - get_class($this->locator) - ) + get_class($this->locator), + ), ); } @@ -95,7 +95,7 @@ protected function loadMetadataFromFile(ReflectionClass $class, string $file): ? if (!isset($config[$name = $class->name])) { throw new InvalidMetadataException( - sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file) + sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file), ); } @@ -126,13 +126,13 @@ protected function loadMetadataFromFile(ReflectionClass $class, string $file): ? $virtualPropertyMetadata = new ExpressionPropertyMetadata( $name, $methodName, - $this->parseExpression($propertySettings['exp']) + $this->parseExpression($propertySettings['exp']), ); unset($propertySettings['exp']); } else { if (!$class->hasMethod($methodName)) { throw new InvalidMetadataException( - 'The method ' . $methodName . ' not found in class ' . $class->name + 'The method ' . $methodName . ' not found in class ' . $class->name, ); } @@ -290,7 +290,7 @@ protected function loadMetadataFromFile(ReflectionClass $class, string $file): ? $pMetadata->setAccessor( $pConfig['access_type'] ?? $classAccessType, $pConfig['accessor']['getter'] ?? null, - $pConfig['accessor']['setter'] ?? null + $pConfig['accessor']['setter'] ?? null, ); if (isset($pConfig['inline'])) { @@ -397,7 +397,7 @@ private function addClassProperties(ClassMetadata $metadata, array $config): voi if (!isset($config['discriminator']['map']) || !is_array($config['discriminator']['map'])) { throw new InvalidMetadataException( - 'The "map" attribute must be set, and be an array for discriminators.' + 'The "map" attribute must be set, and be an array for discriminators.', ); } @@ -405,7 +405,7 @@ private function addClassProperties(ClassMetadata $metadata, array $config): voi $metadata->setDiscriminator( $config['discriminator']['field_name'], $config['discriminator']['map'], - $groups + $groups, ); if (isset($config['discriminator']['xml_attribute'])) { @@ -436,8 +436,8 @@ private function getCallbackMetadata(ReflectionClass $class, $config): array throw new InvalidMetadataException( sprintf( 'callback methods expects a string, or an array of strings that represent method names, but got %s.', - json_encode($config['pre_serialize']) - ) + json_encode($config['pre_serialize']), + ), ); } @@ -445,7 +445,7 @@ private function getCallbackMetadata(ReflectionClass $class, $config): array foreach ($config as $name) { if (!$class->hasMethod($name)) { throw new InvalidMetadataException( - sprintf('The method %s does not exist in class %s.', $name, $class->name) + sprintf('The method %s does not exist in class %s.', $name, $class->name), ); } diff --git a/src/Ordering/AlphabeticalPropertyOrderingStrategy.php b/src/Ordering/AlphabeticalPropertyOrderingStrategy.php index 09d8a65a5..68db769c0 100644 --- a/src/Ordering/AlphabeticalPropertyOrderingStrategy.php +++ b/src/Ordering/AlphabeticalPropertyOrderingStrategy.php @@ -15,9 +15,7 @@ public function order(array $properties): array { uasort( $properties, - static function (PropertyMetadata $a, PropertyMetadata $b): int { - return strcmp($a->name, $b->name); - } + static fn (PropertyMetadata $a, PropertyMetadata $b): int => strcmp($a->name, $b->name), ); return $properties; diff --git a/src/Serializer.php b/src/Serializer.php index af0540596..1dc7e6ca8 100644 --- a/src/Serializer.php +++ b/src/Serializer.php @@ -119,8 +119,8 @@ private function getNavigator(int $direction): GraphNavigatorInterface throw new RuntimeException( sprintf( 'Can not find a graph navigator for the direction "%s".', - GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction ? 'serialization' : 'deserialization' - ) + GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction ? 'serialization' : 'deserialization', + ), ); } @@ -138,8 +138,8 @@ private function getVisitor(int $direction, string $format): VisitorInterface sprintf( 'The format "%s" is not supported for %s.', $format, - GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction ? 'serialization' : 'deserialization' - ) + GraphNavigatorInterface::DIRECTION_SERIALIZATION === $direction ? 'serialization' : 'deserialization', + ), ); } @@ -206,7 +206,7 @@ public function toArray($data, ?SerializationContext $context = null, ?string $t throw new RuntimeException(sprintf( 'The input data of type "%s" did not convert to an array, but got a result of type "%s".', \is_object($data) ? \get_class($data) : \gettype($data), - \is_object($result) ? \get_class($result) : \gettype($result) + \is_object($result) ? \get_class($result) : \gettype($result), )); } @@ -239,7 +239,7 @@ private function visit(GraphNavigatorInterface $navigator, VisitorInterface $vis $format, $visitor, $navigator, - $this->factory + $this->factory, ); $visitor->setNavigator($navigator); diff --git a/src/SerializerBuilder.php b/src/SerializerBuilder.php index 2fe6281c4..f5d9c5404 100644 --- a/src/SerializerBuilder.php +++ b/src/SerializerBuilder.php @@ -502,7 +502,7 @@ public function setSerializationContextFactory($serializationContextFactory): se $this->serializationContextFactory = $serializationContextFactory; } elseif (is_callable($serializationContextFactory)) { $this->serializationContextFactory = new CallableSerializationContextFactory( - $serializationContextFactory + $serializationContextFactory, ); } else { throw new InvalidArgumentException('expected SerializationContextFactoryInterface or callable.'); @@ -520,7 +520,7 @@ public function setDeserializationContextFactory($deserializationContextFactory) $this->deserializationContextFactory = $deserializationContextFactory; } elseif (is_callable($deserializationContextFactory)) { $this->deserializationContextFactory = new CallableDeserializationContextFactory( - $deserializationContextFactory + $deserializationContextFactory, ); } else { throw new InvalidArgumentException('expected DeserializationContextFactoryInterface or callable.'); @@ -557,9 +557,8 @@ public function setDocBlockTypeResolver(bool $docBlockTypeResolver): self public function build(): Serializer { $annotationReader = $this->annotationReader; - if (null === $annotationReader) { - $annotationReader = new AnnotationReader(); - $annotationReader = $this->decorateAnnotationReader($annotationReader); + if (null === $annotationReader && class_exists(AnnotationReader::class)) { + $annotationReader = $this->decorateAnnotationReader(new AnnotationReader()); } if (null === $this->driverFactory) { @@ -567,7 +566,7 @@ public function build(): Serializer $this->driverFactory = new DefaultDriverFactory( $this->propertyNamingStrategy, $this->typeParser, - $this->expressionEvaluator instanceof CompilableExpressionEvaluatorInterface ? $this->expressionEvaluator : null + $this->expressionEvaluator instanceof CompilableExpressionEvaluatorInterface ? $this->expressionEvaluator : null, ); $this->driverFactory->enableEnumSupport($this->enableEnumSupport); } @@ -616,7 +615,7 @@ public function build(): Serializer $this->deserializationVisitors, $this->serializationContextFactory, $this->deserializationContextFactory, - $this->typeParser + $this->typeParser, ); } @@ -627,7 +626,7 @@ private function getSerializationNavigatorFactory(MetadataFactoryInterface $meta $this->handlerRegistry, $this->getAccessorStrategy(), $this->eventDispatcher, - $this->expressionEvaluator + $this->expressionEvaluator, ); } @@ -639,7 +638,7 @@ private function getDeserializationNavigatorFactory(MetadataFactoryInterface $me $this->objectConstructor ?: new UnserializeObjectConstructor(), $this->getAccessorStrategy(), $this->eventDispatcher, - $this->expressionEvaluator + $this->expressionEvaluator, ); } diff --git a/src/Twig/SerializerExtension.php b/src/Twig/SerializerExtension.php index 9a45ca36c..d769517f8 100644 --- a/src/Twig/SerializerExtension.php +++ b/src/Twig/SerializerExtension.php @@ -24,6 +24,7 @@ class SerializerExtension extends SerializerBaseExtension public function __construct(SerializerInterface $serializer, string $serializationFunctionsPrefix = '') { $this->serializer = $serializer; + parent::__construct($serializationFunctionsPrefix); } diff --git a/src/Type/Parser.php b/src/Type/Parser.php index ab7d361a7..560345c13 100644 --- a/src/Type/Parser.php +++ b/src/Type/Parser.php @@ -39,7 +39,7 @@ private function visit() if (!$this->lexer->token) { throw new SyntaxError( - 'Syntax error, unexpected end of stream' + 'Syntax error, unexpected end of stream', ); } @@ -66,7 +66,7 @@ private function visit() throw new SyntaxError(sprintf( 'Syntax error, unexpected "%s" (%s)', $this->lexer->token->value, - $this->getConstant($this->lexer->token->type) + $this->getConstant($this->lexer->token->type), )); } @@ -135,7 +135,7 @@ private function match(int $token): void { if (!$this->lexer->lookahead) { throw new SyntaxError( - sprintf('Syntax error, unexpected end of stream, expected %s', $this->getConstant($token)) + sprintf('Syntax error, unexpected end of stream, expected %s', $this->getConstant($token)), ); } @@ -149,7 +149,7 @@ private function match(int $token): void 'Syntax error, unexpected "%s" (%s), expected was %s', $this->lexer->lookahead->value, $this->getConstant($this->lexer->lookahead->type), - $this->getConstant($token) + $this->getConstant($token), )); } diff --git a/src/Visitor/Factory/XmlSerializationVisitorFactory.php b/src/Visitor/Factory/XmlSerializationVisitorFactory.php index 10541a457..be7f0eb05 100644 --- a/src/Visitor/Factory/XmlSerializationVisitorFactory.php +++ b/src/Visitor/Factory/XmlSerializationVisitorFactory.php @@ -44,7 +44,7 @@ public function getVisitor(): SerializationVisitorInterface $this->defaultEncoding, $this->defaultVersion, $this->defaultRootName, - $this->defaultRootNamespace + $this->defaultRootNamespace, ); } diff --git a/src/XmlDeserializationVisitor.php b/src/XmlDeserializationVisitor.php index a2ba33016..1efa3c90c 100644 --- a/src/XmlDeserializationVisitor.php +++ b/src/XmlDeserializationVisitor.php @@ -88,7 +88,7 @@ public function prepare($data) if (!in_array($internalSubset, $this->doctypeAllowList, true)) { throw new InvalidArgumentException(sprintf( 'The document type "%s" is not allowed. If it is safe, you may add it to the allowlist configuration.', - $internalSubset + $internalSubset, )); } } @@ -288,7 +288,7 @@ public function visitDiscriminatorMapProperty($data, ClassMetadata $metadata): s throw new LogicException(sprintf( 'The discriminator field name "%s" for base-class "%s" was not found in input data.', $metadata->discriminatorFieldName, - $metadata->name + $metadata->name, )); } } diff --git a/src/XmlSerializationVisitor.php b/src/XmlSerializationVisitor.php index ffa1e1419..8406d75b4 100644 --- a/src/XmlSerializationVisitor.php +++ b/src/XmlSerializationVisitor.php @@ -318,9 +318,7 @@ public function visitProperty(PropertyMetadata $metadata, $v): void } if ($addEnclosingElement = !$this->isInLineCollection($metadata) && !$metadata->inline) { - $namespace = null !== $metadata->xmlNamespace - ? $metadata->xmlNamespace - : $this->getClassDefaultNamespace($this->objectMetadataStack->top()); + $namespace = $metadata->xmlNamespace ?? $this->getClassDefaultNamespace($this->objectMetadataStack->top()); $element = $this->createElement($metadata->serializedName, $namespace); $this->currentNode->appendChild($element); @@ -401,7 +399,7 @@ public function getResult($node) $this->document->documentElement->setAttributeNS( 'http://www.w3.org/2000/xmlns/', 'xmlns:xsi', - 'http://www.w3.org/2001/XMLSchema-instance' + 'http://www.w3.org/2001/XMLSchema-instance', ); } diff --git a/tests/Benchmark/AbstractSerializationBench.php b/tests/Benchmark/AbstractSerializationBench.php index c0fd5dbf8..8925f5920 100644 --- a/tests/Benchmark/AbstractSerializationBench.php +++ b/tests/Benchmark/AbstractSerializationBench.php @@ -81,7 +81,7 @@ private function createPost() 'FooooooooooooooooooooooBAR', new Author('Foo'), new \DateTime(), - new Publisher('bar') + new Publisher('bar'), ); for ($i = 0; $i < $this->amountOfComments; $i++) { $post->addComment(new Comment(new Author('foo'), 'foobar')); diff --git a/tests/Benchmark/Memory/JsonMultipleRunBench.php b/tests/Benchmark/Memory/JsonMultipleRunBench.php index f6a3e713e..3a637adc4 100644 --- a/tests/Benchmark/Memory/JsonMultipleRunBench.php +++ b/tests/Benchmark/Memory/JsonMultipleRunBench.php @@ -9,6 +9,7 @@ class JsonMultipleRunBench extends JsonSingleRunBench public function __construct() { $this->iterations = 10000; + parent::__construct(); } } diff --git a/tests/Benchmark/Memory/JsonSingleRunBench.php b/tests/Benchmark/Memory/JsonSingleRunBench.php index 91b6f9207..72ac96f54 100644 --- a/tests/Benchmark/Memory/JsonSingleRunBench.php +++ b/tests/Benchmark/Memory/JsonSingleRunBench.php @@ -12,6 +12,7 @@ public function __construct() { $this->amountOfComments = 1; $this->amountOfPosts = 1; + parent::__construct(); } diff --git a/tests/Benchmark/Memory/XmlMutlipleRunBench.php b/tests/Benchmark/Memory/XmlMutlipleRunBench.php index 152f16068..816bd7405 100644 --- a/tests/Benchmark/Memory/XmlMutlipleRunBench.php +++ b/tests/Benchmark/Memory/XmlMutlipleRunBench.php @@ -9,6 +9,7 @@ class XmlMutlipleRunBench extends XmlSingleRunBench public function __construct() { $this->iterations = 10000; + parent::__construct(); } diff --git a/tests/Benchmark/Memory/XmlSingleRunBench.php b/tests/Benchmark/Memory/XmlSingleRunBench.php index 8de6c8f0e..4e1f5df59 100644 --- a/tests/Benchmark/Memory/XmlSingleRunBench.php +++ b/tests/Benchmark/Memory/XmlSingleRunBench.php @@ -12,6 +12,7 @@ public function __construct() { $this->amountOfComments = 1; $this->amountOfPosts = 1; + parent::__construct(); } diff --git a/tests/Deserializer/BaseDeserializationTest.php b/tests/Deserializer/BaseDeserializationTest.php index 8aaf6b71a..736b8ef83 100644 --- a/tests/Deserializer/BaseDeserializationTest.php +++ b/tests/Deserializer/BaseDeserializationTest.php @@ -11,6 +11,7 @@ use JMS\Serializer\Tests\Fixtures\GroupsObject; use JMS\Serializer\Tests\Fixtures\Price; use JMS\Serializer\Tests\Fixtures\Publisher; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class BaseDeserializationTest extends TestCase @@ -18,6 +19,7 @@ class BaseDeserializationTest extends TestCase /** * @dataProvider dataTypeCannotBeCasted */ + #[DataProvider('dataTypeCannotBeCasted')] public function testDeserializationInvalidDataCausesException($data, string $type): void { $serializer = SerializerBuilder::create()->build(); @@ -48,6 +50,7 @@ public static function dataTypeCannotBeCasted(): iterable /** * @dataProvider dataDeserializerGroupExclusion */ + #[DataProvider('dataDeserializerGroupExclusion')] public function testDeserializerGroupExclusion(array $data, array $groups, array $expected): void { $serializer = SerializerBuilder::create()->build(); diff --git a/tests/Exclusion/DisjunctExclusionStrategyTest.php b/tests/Exclusion/DisjunctExclusionStrategyTest.php index 5b25d59d9..4ad965d48 100644 --- a/tests/Exclusion/DisjunctExclusionStrategyTest.php +++ b/tests/Exclusion/DisjunctExclusionStrategyTest.php @@ -25,7 +25,7 @@ public function testShouldSkipClassShortCircuiting() $first->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) - ->will($this->returnValue(true)); + ->willReturn(true); $last->expects($this->never()) ->method('shouldSkipClass'); @@ -46,12 +46,12 @@ public function testShouldSkipClassDisjunctBehavior() $first->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) - ->will($this->returnValue(false)); + ->willReturn(false); $last->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) - ->will($this->returnValue(true)); + ->willReturn(true); self::assertTrue($strat->shouldSkipClass($metadata, $context)); } @@ -69,12 +69,12 @@ public function testShouldSkipClassReturnsFalseIfNoPredicateMatched() $first->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) - ->will($this->returnValue(false)); + ->willReturn(false); $last->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) - ->will($this->returnValue(false)); + ->willReturn(false); self::assertFalse($strat->shouldSkipClass($metadata, $context)); } @@ -92,7 +92,7 @@ public function testShouldSkipPropertyShortCircuiting() $first->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) - ->will($this->returnValue(true)); + ->willReturn(true); $last->expects($this->never()) ->method('shouldSkipProperty'); @@ -113,12 +113,12 @@ public function testShouldSkipPropertyDisjunct() $first->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) - ->will($this->returnValue(false)); + ->willReturn(false); $last->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) - ->will($this->returnValue(true)); + ->willReturn(true); self::assertTrue($strat->shouldSkipProperty($metadata, $context)); } @@ -136,12 +136,12 @@ public function testShouldSkipPropertyReturnsFalseIfNoPredicateMatches() $first->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) - ->will($this->returnValue(false)); + ->willReturn(false); $last->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) - ->will($this->returnValue(false)); + ->willReturn(false); self::assertFalse($strat->shouldSkipProperty($metadata, $context)); } diff --git a/tests/Exclusion/GroupsExclusionStrategyTest.php b/tests/Exclusion/GroupsExclusionStrategyTest.php index 02ea11069..05f4c29d6 100644 --- a/tests/Exclusion/GroupsExclusionStrategyTest.php +++ b/tests/Exclusion/GroupsExclusionStrategyTest.php @@ -7,18 +7,16 @@ use JMS\Serializer\Exclusion\GroupsExclusionStrategy; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\SerializationContext; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class GroupsExclusionStrategyTest extends TestCase { /** - * @param array $propertyGroups - * @param array $groups - * @param bool $exclude - * * @dataProvider getExclusionRules */ - public function testUninitializedContextIsWorking(array $propertyGroups, array $groups, $exclude) + #[DataProvider('getExclusionRules')] + public function testUninitializedContextIsWorking(array $propertyGroups, array $groups, bool $exclude) { $metadata = new StaticPropertyMetadata('stdClass', 'prop', 'propVal'); $metadata->groups = $propertyGroups; @@ -57,6 +55,7 @@ public static function getExclusionRules() /** * @dataProvider getGroupsFor */ + #[DataProvider('getGroupsFor')] public function testGroupsFor(array $groups, array $propsVisited, array $resultingGroups) { $exclusion = new GroupsExclusionStrategy($groups); diff --git a/tests/Fixtures/AuthorDeprecatedReadOnly.php b/tests/Fixtures/AuthorDeprecatedReadOnly.php index 3e31e1dc2..5bab54a6c 100644 --- a/tests/Fixtures/AuthorDeprecatedReadOnly.php +++ b/tests/Fixtures/AuthorDeprecatedReadOnly.php @@ -5,7 +5,7 @@ namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Accessor; -use JMS\Serializer\Annotation\ReadOnly; +use JMS\Serializer\Annotation\DeprecatedReadOnly; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; @@ -22,6 +22,7 @@ class AuthorDeprecatedReadOnly * @JMS\Serializer\Annotation\ReadOnly * @SerializedName("id") */ + #[DeprecatedReadOnly] #[SerializedName(name: 'id')] private $id; diff --git a/tests/Fixtures/AuthorDeprecatedReadOnlyPerClass.php b/tests/Fixtures/AuthorDeprecatedReadOnlyPerClass.php index cff0e6e88..08de1e541 100644 --- a/tests/Fixtures/AuthorDeprecatedReadOnlyPerClass.php +++ b/tests/Fixtures/AuthorDeprecatedReadOnlyPerClass.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Accessor; +use JMS\Serializer\Annotation\DeprecatedReadOnly; use JMS\Serializer\Annotation\ReadOnly; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; @@ -17,12 +18,14 @@ * @ReadOnly */ #[XmlRoot(name: 'author')] +#[DeprecatedReadOnly] class AuthorDeprecatedReadOnlyPerClass { /** * @ReadOnly * @SerializedName("id") */ + #[DeprecatedReadOnly] #[SerializedName(name: 'id')] private $id; @@ -41,6 +44,7 @@ public function __construct($id, $name) #[Type(name: 'string')] #[SerializedName(name: 'full_name')] #[Accessor(getter: 'getName')] + #[DeprecatedReadOnly(readOnly: false)] private $name; public function getId() diff --git a/tests/Fixtures/AuthorList.php b/tests/Fixtures/AuthorList.php index 695beb569..23969b6ff 100644 --- a/tests/Fixtures/AuthorList.php +++ b/tests/Fixtures/AuthorList.php @@ -43,8 +43,7 @@ public function count(): int /** * @see ArrayAccess */ - #[\ReturnTypeWillChange] - public function offsetExists($offset) + public function offsetExists($offset): bool { return isset($this->authors[$offset]); } @@ -52,8 +51,7 @@ public function offsetExists($offset) /** * @see ArrayAccess */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) + public function offsetGet($offset): ?Author { return $this->authors[$offset] ?? null; } @@ -61,8 +59,7 @@ public function offsetGet($offset) /** * @see ArrayAccess */ - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (null === $offset) { $this->authors[] = $value; @@ -74,8 +71,7 @@ public function offsetSet($offset, $value) /** * @see ArrayAccess */ - #[\ReturnTypeWillChange] - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->authors[$offset]); } diff --git a/tests/Fixtures/Discriminator/Serialization/ExtendedUser.php b/tests/Fixtures/Discriminator/Serialization/ExtendedUser.php index e7f4e2a75..bfdbc4ef8 100644 --- a/tests/Fixtures/Discriminator/Serialization/ExtendedUser.php +++ b/tests/Fixtures/Discriminator/Serialization/ExtendedUser.php @@ -20,6 +20,7 @@ class ExtendedUser extends User public function __construct($id, $name, $description, $extendAttribute) { parent::__construct($id, $name, $description); + $this->extendAttribute = $extendAttribute; } } diff --git a/tests/Fixtures/Discriminator/Serialization/User.php b/tests/Fixtures/Discriminator/Serialization/User.php index 89efb92da..9b74931b8 100644 --- a/tests/Fixtures/Discriminator/Serialization/User.php +++ b/tests/Fixtures/Discriminator/Serialization/User.php @@ -38,6 +38,7 @@ class User extends Entity public function __construct(int $id, string $name, string $description) { parent::__construct($id); + $this->name = $name; $this->description = $description; } diff --git a/tests/Fixtures/DocBlockType/Collection/CollectionOfInterfacesFromGlobalNamespace.php b/tests/Fixtures/DocBlockType/Collection/CollectionOfInterfacesFromGlobalNamespace.php index a166a623f..5736da14d 100644 --- a/tests/Fixtures/DocBlockType/Collection/CollectionOfInterfacesFromGlobalNamespace.php +++ b/tests/Fixtures/DocBlockType/Collection/CollectionOfInterfacesFromGlobalNamespace.php @@ -4,11 +4,14 @@ namespace JMS\Serializer\Tests\Fixtures\DocBlockType\Collection; +use JMS\Serializer\Tests\Fixtures\DocBlockType\Collection\Details\ProductColor; + class CollectionOfInterfacesFromGlobalNamespace { /** * phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName - * @var \JMS\Serializer\Tests\Fixtures\DocBlockType\Collection\Details\ProductColor[] + * + * @var ProductColor[] */ public array $productColors; } diff --git a/tests/Fixtures/Doctrine/Embeddable/BlogPostSeo.php b/tests/Fixtures/Doctrine/Embeddable/BlogPostSeo.php index ed24ab396..297c4c927 100644 --- a/tests/Fixtures/Doctrine/Embeddable/BlogPostSeo.php +++ b/tests/Fixtures/Doctrine/Embeddable/BlogPostSeo.php @@ -4,11 +4,13 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\Embeddable; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Embeddable() */ +#[ORM\Embeddable] class BlogPostSeo { /** @@ -16,5 +18,6 @@ class BlogPostSeo * * @var string */ + #[ORM\Column(type: Types::STRING, name: 'meta_title')] private $metaTitle; } diff --git a/tests/Fixtures/Doctrine/Embeddable/BlogPostWithEmbedded.php b/tests/Fixtures/Doctrine/Embeddable/BlogPostWithEmbedded.php index 5f6868603..036276584 100644 --- a/tests/Fixtures/Doctrine/Embeddable/BlogPostWithEmbedded.php +++ b/tests/Fixtures/Doctrine/Embeddable/BlogPostWithEmbedded.php @@ -4,11 +4,13 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\Embeddable; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ +#[ORM\Entity] class BlogPostWithEmbedded { /** @@ -16,10 +18,14 @@ class BlogPostWithEmbedded * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue(strategy: 'AUTO')] protected $id; /** * @ORM\Embedded(class="BlogPostSeo", columnPrefix="seo_") */ + #[ORM\Embedded(class: BlogPostSeo::class, columnPrefix: 'seo_')] private $seo; } diff --git a/tests/Fixtures/Doctrine/Entity/Author.php b/tests/Fixtures/Doctrine/Entity/Author.php index 6d2c4ef78..468cbc013 100644 --- a/tests/Fixtures/Doctrine/Entity/Author.php +++ b/tests/Fixtures/Doctrine/Entity/Author.php @@ -4,18 +4,24 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\Entity; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\SerializedName; /** @ORM\Entity */ +#[ORM\Entity] class Author { /** - * @ORM\Id @ORM\Column(type="integer") + * @ORM\Id + * @ORM\Column(type="integer") * * @Groups({"id_group"}) */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[Groups(groups: ['id_group'])] protected $id; /** @@ -23,6 +29,8 @@ class Author * * @SerializedName("full_name") */ + #[ORM\Column(type: Types::STRING)] + #[SerializedName(name: 'full_name')] private $name; public function __construct($name, $id = null) diff --git a/tests/Fixtures/Doctrine/Entity/AuthorExcludedId.php b/tests/Fixtures/Doctrine/Entity/AuthorExcludedId.php index 8a87003b3..f3617af7d 100644 --- a/tests/Fixtures/Doctrine/Entity/AuthorExcludedId.php +++ b/tests/Fixtures/Doctrine/Entity/AuthorExcludedId.php @@ -4,18 +4,23 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\Entity; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation\Exclude; use JMS\Serializer\Annotation\SerializedName; /** @ORM\Entity */ +#[ORM\Entity] class AuthorExcludedId { /** - * @ORM\Id @ORM\Column(type="integer") + * @ORM\Id + * @ORM\Column(type="integer") * * @Exclude */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] #[Exclude] protected $id; @@ -24,6 +29,7 @@ class AuthorExcludedId * * @SerializedName("full_name") */ + #[ORM\Column(type: Types::STRING)] #[SerializedName(name: 'full_name')] private $name; diff --git a/tests/Fixtures/Doctrine/Entity/BlogPost.php b/tests/Fixtures/Doctrine/Entity/BlogPost.php index 43ffcb5c6..665c72fd4 100644 --- a/tests/Fixtures/Doctrine/Entity/BlogPost.php +++ b/tests/Fixtures/Doctrine/Entity/BlogPost.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\Entity; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Annotation\Groups; @@ -19,17 +20,24 @@ * * @XmlRoot("blog-post") */ +#[ORM\Entity] #[XmlRoot(name: 'blog-post')] class BlogPost { /** - * @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue(strategy="AUTO") + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue(strategy: 'AUTO')] protected $id; /** * @ORM\Column(type="guid") */ + #[ORM\Column(type: Types::GUID)] private $guid; /** @@ -37,12 +45,14 @@ class BlogPost * * @Groups({"comments","post"}) */ + #[ORM\Column(type: Types::STRING)] #[Groups(groups: ['comments', 'post'])] private $title; /** * @ORM\Column(type="some_custom_type") */ + #[ORM\Column(type: 'some_custom_type')] protected $slug; /** @@ -50,6 +60,7 @@ class BlogPost * * @XmlAttribute */ + #[ORM\Column(type: Types::DATETIME_MUTABLE)] #[XmlAttribute] private $createdAt; @@ -64,6 +75,7 @@ class BlogPost * @Groups({"post"}) * @XmlAttribute */ + #[ORM\Column(type: Types::BOOLEAN)] #[Type(name: 'integer')] #[SerializedName(name: 'is_published')] #[Groups(groups: ['post'])] @@ -76,6 +88,7 @@ class BlogPost * @XmlList(inline=true, entry="comment") * @Groups({"comments"}) */ + #[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'blogPost')] #[XmlList(entry: 'comment', inline: true)] #[Groups(groups: ['comments'])] private $comments; @@ -85,13 +98,15 @@ class BlogPost * * @Groups({"post"}) */ + #[ORM\OneToOne(targetEntity: Author::class)] #[Groups(groups: ['post'])] private $author; /** - * @Serializer\Exclude() * @ORM\Column(type="integer") + * @Serializer\Exclude() */ + #[ORM\Column(type: Types::INTEGER)] #[Serializer\Exclude] private $ref; diff --git a/tests/Fixtures/Doctrine/Entity/Comment.php b/tests/Fixtures/Doctrine/Entity/Comment.php index a8fad7e41..7b09e0853 100644 --- a/tests/Fixtures/Doctrine/Entity/Comment.php +++ b/tests/Fixtures/Doctrine/Entity/Comment.php @@ -5,27 +5,35 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\Entity; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; /** @ORM\Entity */ +#[ORM\Entity] class Comment { /** - * @ORM\Id @ORM\Column(type="integer") + * @ORM\Id + * @ORM\Column(type="integer") */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] protected $id; /** - * @ORM\Column(type="Author") + * @ORM\OneToOne(targetEntity="Author") */ + #[ORM\OneToOne(targetEntity: Author::class)] private $author; /** @ORM\ManyToOne(targetEntity="BlogPost") */ + #[ORM\ManyToOne(targetEntity: BlogPost::class)] private $blogPost; /** * @ORM\Column(type="string") */ + #[ORM\Column(type: Types::STRING)] private $text; public function __construct(Author $author, $text) diff --git a/tests/Fixtures/Doctrine/IdentityFields/Server.php b/tests/Fixtures/Doctrine/IdentityFields/Server.php index cdd20f73d..329dd85eb 100644 --- a/tests/Fixtures/Doctrine/IdentityFields/Server.php +++ b/tests/Fixtures/Doctrine/IdentityFields/Server.php @@ -4,10 +4,12 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\IdentityFields; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; /** @ORM\Entity */ +#[ORM\Entity] class Server { /** @@ -18,6 +20,8 @@ class Server * @var string */ #[Serializer\Type(name: 'string')] + #[ORM\Id] + #[ORM\Column(type: Types::STRING, name: 'ip_address')] protected $ipAddress; /** @@ -30,6 +34,8 @@ class Server */ #[Serializer\SerializedName(name: 'server_id_extracted')] #[Serializer\Type(name: 'string')] + #[ORM\Id] + #[ORM\Column(type: Types::STRING, name: 'server_id')] protected $serverId; /** @@ -39,6 +45,7 @@ class Server * @var string */ #[Serializer\Type(name: 'string')] + #[ORM\Column(type: Types::STRING)] private $name; /** diff --git a/tests/Fixtures/Doctrine/PersistendCollection/App.php b/tests/Fixtures/Doctrine/PersistendCollection/App.php index e10cd85b3..dd6a9a86c 100644 --- a/tests/Fixtures/Doctrine/PersistendCollection/App.php +++ b/tests/Fixtures/Doctrine/PersistendCollection/App.php @@ -4,10 +4,12 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\PersistendCollection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; /** @ORM\Entity */ +#[ORM\Entity] class App { /** @@ -18,7 +20,10 @@ class App * * @var string */ + #[Serializer\SerializedName(name: 'id')] #[Serializer\Type(name: 'string')] + #[ORM\Id] + #[ORM\Column(type: Types::STRING, name: 'id')] protected $id; /** @@ -28,13 +33,16 @@ class App * @var string */ #[Serializer\Type(name: 'string')] + #[ORM\Column(type: Types::STRING)] private $name; /** * @ORM\ManyToOne(targetEntity="SmartPhone") + * @Serializer\Type("JMS\Serializer\Tests\Fixtures\Doctrine\PersistendCollection\SmartPhone") * * @var SmartPhone */ + #[ORM\ManyToOne(targetEntity: SmartPhone::class)] #[Serializer\Type(name: SmartPhone::class)] private $smartPhone; diff --git a/tests/Fixtures/Doctrine/PersistendCollection/SmartPhone.php b/tests/Fixtures/Doctrine/PersistendCollection/SmartPhone.php index f6a5911a5..9e68aab4c 100644 --- a/tests/Fixtures/Doctrine/PersistendCollection/SmartPhone.php +++ b/tests/Fixtures/Doctrine/PersistendCollection/SmartPhone.php @@ -7,10 +7,12 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; /** @ORM\Entity */ +#[ORM\Entity] class SmartPhone { /** @@ -21,7 +23,10 @@ class SmartPhone * * @var string */ + #[Serializer\SerializedName(name: 'id')] #[Serializer\Type(name: 'string')] + #[ORM\Id] + #[ORM\Column(type: Types::STRING, name: 'id')] protected $id; /** @@ -31,6 +36,7 @@ class SmartPhone * @var string */ #[Serializer\Type(name: 'string')] + #[ORM\Column(type: Types::STRING)] private $name; /** @@ -40,7 +46,9 @@ class SmartPhone * * @var ArrayCollection */ + #[Serializer\SerializedName(name: 'applications')] #[Serializer\Type(name: 'ArrayCollection')] + #[ORM\OneToMany(targetEntity: App::class, mappedBy: 'smartPhone', cascade: ['persist'], orphanRemoval: true)] private $apps; /** diff --git a/tests/Fixtures/Doctrine/SingleTableInheritance/Clazz.php b/tests/Fixtures/Doctrine/SingleTableInheritance/Clazz.php index 4a994d744..4702053fd 100644 --- a/tests/Fixtures/Doctrine/SingleTableInheritance/Clazz.php +++ b/tests/Fixtures/Doctrine/SingleTableInheritance/Clazz.php @@ -5,20 +5,31 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ +#[ORM\Entity] class Clazz extends AbstractModel { - /** @ORM\Id @ORM\GeneratedValue(strategy = "AUTO") @ORM\Column(type = "integer") */ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue(strategy: 'AUTO')] private $id; /** @ORM\ManyToOne(targetEntity = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Teacher") */ + #[ORM\ManyToOne(targetEntity: Teacher::class)] private $teacher; /** @ORM\ManyToMany(targetEntity = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Student") */ + #[ORM\ManyToMany(targetEntity: Student::class)] private $students; public function __construct(Teacher $teacher, array $students) diff --git a/tests/Fixtures/Doctrine/SingleTableInheritance/Organization.php b/tests/Fixtures/Doctrine/SingleTableInheritance/Organization.php index 0309bead2..f04eae6c5 100644 --- a/tests/Fixtures/Doctrine/SingleTableInheritance/Organization.php +++ b/tests/Fixtures/Doctrine/SingleTableInheritance/Organization.php @@ -4,6 +4,7 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; /** @@ -14,8 +15,19 @@ * "school" = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\School" * }) */ +#[ORM\Entity] +#[ORM\InheritanceType('SINGLE_TABLE')] +#[ORM\DiscriminatorColumn(name: 'type', type: Types::STRING)] +#[ORM\DiscriminatorMap(['school' => School::class])] abstract class Organization { - /** @ORM\Id @ORM\GeneratedValue(strategy = "AUTO") @ORM\Column(type = "integer") */ + /** + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue(strategy: 'AUTO')] private $id; } diff --git a/tests/Fixtures/Doctrine/SingleTableInheritance/Person.php b/tests/Fixtures/Doctrine/SingleTableInheritance/Person.php index 107ad52b5..ea887bb27 100644 --- a/tests/Fixtures/Doctrine/SingleTableInheritance/Person.php +++ b/tests/Fixtures/Doctrine/SingleTableInheritance/Person.php @@ -4,6 +4,7 @@ namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; /** @@ -15,8 +16,19 @@ * "teacher" = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Teacher", * }) */ +#[ORM\Entity] +#[ORM\InheritanceType('SINGLE_TABLE')] +#[ORM\DiscriminatorColumn(name: 'type', type: Types::STRING)] +#[ORM\DiscriminatorMap(['student' => Student::class, 'teacher' => Teacher::class])] abstract class Person extends AbstractModel { - /** @ORM\Id @ORM\GeneratedValue(strategy = "AUTO") @ORM\Column(type = "integer") */ + /** + * @ORM\Id + * @ORM\Column(type = "integer") + * @ORM\GeneratedValue(strategy = "AUTO") + */ + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue(strategy: 'AUTO')] private $id; } diff --git a/tests/Fixtures/Doctrine/SingleTableInheritance/School.php b/tests/Fixtures/Doctrine/SingleTableInheritance/School.php index a74dad85c..c9d163a0d 100644 --- a/tests/Fixtures/Doctrine/SingleTableInheritance/School.php +++ b/tests/Fixtures/Doctrine/SingleTableInheritance/School.php @@ -9,6 +9,7 @@ /** * @ORM\Entity */ +#[ORM\Entity] class School extends Organization { } diff --git a/tests/Fixtures/Doctrine/SingleTableInheritance/Student.php b/tests/Fixtures/Doctrine/SingleTableInheritance/Student.php index 7e6412760..7ef4eba91 100644 --- a/tests/Fixtures/Doctrine/SingleTableInheritance/Student.php +++ b/tests/Fixtures/Doctrine/SingleTableInheritance/Student.php @@ -9,6 +9,7 @@ /** * @ORM\Entity */ +#[ORM\Entity] class Student extends Person { } diff --git a/tests/Fixtures/Doctrine/SingleTableInheritance/Teacher.php b/tests/Fixtures/Doctrine/SingleTableInheritance/Teacher.php index 4f3bd2597..eae0374c1 100644 --- a/tests/Fixtures/Doctrine/SingleTableInheritance/Teacher.php +++ b/tests/Fixtures/Doctrine/SingleTableInheritance/Teacher.php @@ -9,6 +9,7 @@ /** * @ORM\Entity */ +#[ORM\Entity] class Teacher extends Person { } diff --git a/tests/Fixtures/Doctrine/XmlMapping/JMS.Serializer.Tests.Fixtures.Doctrine.Embeddable.BlogPostSeo.dcm.xml b/tests/Fixtures/Doctrine/XmlMapping/JMS.Serializer.Tests.Fixtures.Doctrine.Embeddable.BlogPostSeo.dcm.xml index 87cce5a0d..4b13399d8 100644 --- a/tests/Fixtures/Doctrine/XmlMapping/JMS.Serializer.Tests.Fixtures.Doctrine.Embeddable.BlogPostSeo.dcm.xml +++ b/tests/Fixtures/Doctrine/XmlMapping/JMS.Serializer.Tests.Fixtures.Doctrine.Embeddable.BlogPostSeo.dcm.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Fixtures/GetSetObject.php b/tests/Fixtures/GetSetObject.php index ba4c48efa..088f9758e 100644 --- a/tests/Fixtures/GetSetObject.php +++ b/tests/Fixtures/GetSetObject.php @@ -13,7 +13,10 @@ #[AccessType(type: 'public_method')] class GetSetObject { - /** @AccessType("property") @Type("integer") */ + /** + * @AccessType("property") + * @AccessType("property") + @Type("integer") */ #[AccessType(type: 'property')] #[Type(name: 'integer')] private $id = 1; diff --git a/tests/Fixtures/MissingAttributeObject.php b/tests/Fixtures/MissingAttributeObject.php new file mode 100644 index 000000000..15f09af75 --- /dev/null +++ b/tests/Fixtures/MissingAttributeObject.php @@ -0,0 +1,24 @@ +") */ public Suit $ordinary; + /** * @Serializer\Type("enum<'JMS\Serializer\Tests\Fixtures\Enum\BackedSuit', 'value'>") */ - public BackedSuit $backed; + public BackedSuit $backedValue; + + /** + * @Serializer\Type("enum<'JMS\Serializer\Tests\Fixtures\Enum\BackedSuit'>") + */ + public BackedSuit $backedWithoutParam; /** * @Serializer\Type("array>") @@ -30,6 +36,11 @@ class ObjectWithEnums */ public array $backedArray; + /** + * @Serializer\Type("array>") + */ + public array $backedArrayWithoutParam; + public Suit $ordinaryAutoDetect; public BackedSuit $backedAutoDetect; @@ -46,9 +57,11 @@ public function __construct() { $this->ordinary = Suit::Clubs; - $this->backed = BackedSuit::Clubs; + $this->backedValue = BackedSuit::Clubs; + $this->backedWithoutParam = BackedSuit::Clubs; $this->backedArray = [BackedSuit::Clubs, BackedSuit::Hearts]; + $this->backedArrayWithoutParam = [BackedSuit::Clubs, BackedSuit::Hearts]; $this->ordinaryArray = [Suit::Clubs, Suit::Spades]; $this->ordinaryAutoDetect = Suit::Clubs; diff --git a/tests/Fixtures/ObjectWithInlineArray.php b/tests/Fixtures/ObjectWithInlineArray.php index 83b236e7c..cfa3b89e7 100644 --- a/tests/Fixtures/ObjectWithInlineArray.php +++ b/tests/Fixtures/ObjectWithInlineArray.php @@ -16,9 +16,6 @@ final class ObjectWithInlineArray #[Serializer\Type(name: 'array')] public $array; - /** - * @param array $array - */ public function __construct(array $array) { $this->array = $array; diff --git a/tests/Fixtures/ObjectWithIntListAndIntMap.php b/tests/Fixtures/ObjectWithIntListAndIntMap.php index 9cf6fe28a..9c0e804de 100644 --- a/tests/Fixtures/ObjectWithIntListAndIntMap.php +++ b/tests/Fixtures/ObjectWithIntListAndIntMap.php @@ -8,12 +8,18 @@ class ObjectWithIntListAndIntMap { - /** @Serializer\Type("array") @Serializer\XmlList */ + /** + * @Serializer\Type("array") + * @Serializer\Type("array") + @Serializer\XmlList */ #[Serializer\Type(name: 'array')] #[Serializer\XmlList] private $list; - /** @Serializer\Type("array") @Serializer\XmlMap */ + /** + * @Serializer\Type("array") + * @Serializer\Type("array") + @Serializer\XmlMap */ #[Serializer\Type(name: 'array')] #[Serializer\XmlMap] private $map; diff --git a/tests/Fixtures/ObjectWithLifecycleCallbacks.php b/tests/Fixtures/ObjectWithLifecycleCallbacks.php index fb8359481..e991ae992 100644 --- a/tests/Fixtures/ObjectWithLifecycleCallbacks.php +++ b/tests/Fixtures/ObjectWithLifecycleCallbacks.php @@ -39,6 +39,7 @@ public function __construct($firstname = 'Foo', $lastname = 'Bar') /** * @PreSerialize */ + #[PreSerialize] private function prepareForSerialization() { $this->name = $this->firstname . ' ' . $this->lastname; @@ -47,6 +48,7 @@ private function prepareForSerialization() /** * @PostSerialize */ + #[PostSerialize] private function cleanUpAfterSerialization() { $this->name = null; @@ -55,6 +57,7 @@ private function cleanUpAfterSerialization() /** * @PostDeserialize */ + #[PostDeserialize] private function afterDeserialization() { [$this->firstname, $this->lastname] = explode(' ', $this->name); diff --git a/tests/Fixtures/ObjectWithNamespacesAndList.php b/tests/Fixtures/ObjectWithNamespacesAndList.php index ff069eed2..a936a7665 100644 --- a/tests/Fixtures/ObjectWithNamespacesAndList.php +++ b/tests/Fixtures/ObjectWithNamespacesAndList.php @@ -114,7 +114,6 @@ class ObjectWithNamespacesAndList #[Type(name: 'array')] #[SerializedName(name: 'phones')] #[XmlList(entry: 'phone', inline: false)] - public $phonesAlternativeD; /** * @Type("array") diff --git a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithObjectType.php b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithObjectType.php index 548e4a85d..c625b1f69 100644 --- a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithObjectType.php +++ b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithObjectType.php @@ -29,7 +29,7 @@ public static function create1() [ 'key_first' => ObjectWithXmlKeyValuePairsWithType::create1(), 'key_second' => ObjectWithXmlKeyValuePairsWithType::create2(), - ] + ], ); } } diff --git a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php index 77e5bd59d..d0bece018 100644 --- a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php +++ b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php @@ -37,7 +37,7 @@ public static function create1() [ 'key-one' => 'foo', 'key-two' => 'bar', - ] + ], ); } @@ -49,7 +49,7 @@ public static function create2() 'key_02' => 'Two', 'key_03' => 'Three', ], - ['Four'] + ['Four'], ); } } diff --git a/tests/Fixtures/SimpleInternalObject.php b/tests/Fixtures/SimpleInternalObject.php index 638a6a45b..01a847e1d 100644 --- a/tests/Fixtures/SimpleInternalObject.php +++ b/tests/Fixtures/SimpleInternalObject.php @@ -19,6 +19,7 @@ class SimpleInternalObject extends \Exception public function __construct($foo, $bar) { parent::__construct($foo); + $this->bar = $bar; } } diff --git a/tests/Handler/ArrayCollectionDepthTest.php b/tests/Handler/ArrayCollectionDepthTest.php index d0ddcf143..1c924635a 100644 --- a/tests/Handler/ArrayCollectionDepthTest.php +++ b/tests/Handler/ArrayCollectionDepthTest.php @@ -11,6 +11,7 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Serializer as JMSSerializer; use JMS\Serializer\SerializerBuilder; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ArrayCollectionDepthTest extends TestCase @@ -28,6 +29,7 @@ protected function setUp(): void * * @dataProvider getCollections */ + #[DataProvider('getCollections')] public function testDepth($collection) { $context = SerializationContext::create() diff --git a/tests/Handler/ArrayCollectionHandlerTest.php b/tests/Handler/ArrayCollectionHandlerTest.php index 3fc13e34c..00053fd6f 100644 --- a/tests/Handler/ArrayCollectionHandlerTest.php +++ b/tests/Handler/ArrayCollectionHandlerTest.php @@ -11,6 +11,7 @@ use JMS\Serializer\Tests\Fixtures\ExclusionStrategy\AlwaysExcludeExclusionStrategy; use JMS\Serializer\Visitor\SerializationVisitorInterface; use Metadata\MetadataFactoryInterface; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; class ArrayCollectionHandlerTest extends TestCase @@ -18,6 +19,7 @@ class ArrayCollectionHandlerTest extends TestCase /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testSerializeArray() { $handler = new ArrayCollectionHandler(); @@ -36,6 +38,7 @@ public function testSerializeArray() /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testSerializeArraySkipByExclusionStrategy() { $handler = new ArrayCollectionHandler(false); diff --git a/tests/Handler/DateHandlerTest.php b/tests/Handler/DateHandlerTest.php index 78c99061c..86d4955da 100644 --- a/tests/Handler/DateHandlerTest.php +++ b/tests/Handler/DateHandlerTest.php @@ -9,6 +9,8 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; class DateHandlerTest extends TestCase @@ -39,11 +41,11 @@ public static function getParams() } /** - * @param array $params - * * @doesNotPerformAssertions * @dataProvider getParams */ + #[DataProvider('getParams')] + #[DoesNotPerformAssertions] public function testSerializeDate(array $params) { $context = $this->getMockBuilder(SerializationContext::class)->getMock(); @@ -57,12 +59,10 @@ public function testSerializeDate(array $params) } /** - * @param string $dateInterval - * @param \DateTime $expected - * * @dataProvider getDeserializeDateInterval */ - public function testDeserializeDateInterval($dateInterval, $expected) + #[DataProvider('getDeserializeDateInterval')] + public function testDeserializeDateInterval(string $dateInterval, array $expected) { $visitor = $this->getMockBuilder(DeserializationVisitorInterface::class)->getMock(); $visitor->method('visitString')->with('2017-06-18'); @@ -90,7 +90,7 @@ public function testTimePartGetsRemoved() $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', 'Y-m-d|']]; self::assertEquals( \DateTime::createFromFormat('Y-m-d|', '2017-06-18', $this->timezone), - $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type) + $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type), ); } @@ -101,7 +101,7 @@ public function testMultiFormatCase() $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', ['Y-m-d|', 'Y/m/d']]]; self::assertEquals( \DateTime::createFromFormat('Y/m/d', '2017/06/18', $this->timezone), - $this->handler->deserializeDateTimeFromJson($visitor, '2017/06/18', $type) + $this->handler->deserializeDateTimeFromJson($visitor, '2017/06/18', $type), ); } @@ -121,14 +121,14 @@ public function testTimePartGetsPreserved() $type = ['name' => 'DateTime', 'params' => ['Y-m-d']]; self::assertEquals( $expectedDateTime, - $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type) + $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type), ); // custom deserialization format specified $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', 'Y-m-d']]; self::assertEquals( $expectedDateTime, - $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type) + $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type), ); } @@ -147,7 +147,7 @@ public function testTimeZoneGetsPreservedWithUnixTimestamp() self::assertEquals( $expectedDateTime->format(\DateTime::RFC3339), - $actualDateTime->format(\DateTime::RFC3339) + $actualDateTime->format(\DateTime::RFC3339), ); } @@ -166,7 +166,7 @@ public function testImmutableTimeZoneGetsPreservedWithUnixTimestamp() self::assertEquals( $expectedDateTime->format(\DateTime::RFC3339), - $actualDateTime->format(\DateTime::RFC3339) + $actualDateTime->format(\DateTime::RFC3339), ); } } diff --git a/tests/Handler/FormErrorHandlerTest.php b/tests/Handler/FormErrorHandlerTest.php index 5f15f92da..353b6c20a 100644 --- a/tests/Handler/FormErrorHandlerTest.php +++ b/tests/Handler/FormErrorHandlerTest.php @@ -150,7 +150,7 @@ public function testDefaultTranslationDomain() ->with( $this->equalTo('error!'), $this->equalTo([]), - $this->equalTo('validators') + $this->equalTo('validators'), ); $formError = $this->getMockBuilder('Symfony\Component\Form\FormError')->disableOriginalConstructor()->getMock(); @@ -177,7 +177,7 @@ public function testDefaultTranslationDomainWithPluralTranslation() ->with( $this->equalTo('error!'), $this->equalTo(['%count%' => 0]), - $this->equalTo('validators') + $this->equalTo('validators'), ); } else { $translator->expects($this->once()) @@ -186,7 +186,7 @@ public function testDefaultTranslationDomainWithPluralTranslation() $this->equalTo('error!'), $this->equalTo(0), $this->equalTo([]), - $this->equalTo('validators') + $this->equalTo('validators'), ); } @@ -213,7 +213,7 @@ public function testCustomTranslationDomain() ->with( $this->equalTo('error!'), $this->equalTo([]), - $this->equalTo('custom_domain') + $this->equalTo('custom_domain'), ); $formError = $this->getMockBuilder('Symfony\Component\Form\FormError')->disableOriginalConstructor()->getMock(); @@ -241,7 +241,7 @@ public function testCustomTranslationDomainWithPluralTranslation() ->with( $this->equalTo('error!'), $this->equalTo(['%count%' => 0]), - $this->equalTo('custom_domain') + $this->equalTo('custom_domain'), ); } else { $translator->expects($this->once()) @@ -250,7 +250,7 @@ public function testCustomTranslationDomainWithPluralTranslation() $this->equalTo('error!'), $this->equalTo(0), $this->equalTo([]), - $this->equalTo('custom_domain') + $this->equalTo('custom_domain'), ); } diff --git a/tests/Handler/IteratorHandlerTest.php b/tests/Handler/IteratorHandlerTest.php index ec40747b4..d49f32b90 100644 --- a/tests/Handler/IteratorHandlerTest.php +++ b/tests/Handler/IteratorHandlerTest.php @@ -11,6 +11,7 @@ use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; final class IteratorHandlerTest extends TestCase @@ -40,13 +41,14 @@ public static function iteratorsProvider(): array /** * @dataProvider iteratorsProvider */ + #[DataProvider('iteratorsProvider')] public function testSerialize(\Iterator $iterator): void { $type = get_class($iterator); $serializationHandler = $this->handlerRegistry->getHandler( GraphNavigatorInterface::DIRECTION_SERIALIZATION, $type, - 'json' + 'json', ); self::assertIsCallable($serializationHandler); @@ -54,14 +56,14 @@ public function testSerialize(\Iterator $iterator): void $this->createSerializationVisitor(), $iterator, ['name' => $type, 'params' => []], - $this->getMockBuilder(SerializationContext::class)->getMock() + $this->getMockBuilder(SerializationContext::class)->getMock(), ); self::assertSame(self::DATA, $serialized); $deserializationHandler = $this->handlerRegistry->getHandler( GraphNavigatorInterface::DIRECTION_DESERIALIZATION, $type, - 'json' + 'json', ); self::assertIsCallable($deserializationHandler); @@ -69,7 +71,7 @@ public function testSerialize(\Iterator $iterator): void $this->createDeserializationVisitor(), $serialized, ['name' => $type, 'params' => []], - $this->getMockBuilder(DeserializationContext::class)->getMock() + $this->getMockBuilder(DeserializationContext::class)->getMock(), ); self::assertEquals($iterator, $deserialized); } diff --git a/tests/Handler/SymfonyUidHandlerTest.php b/tests/Handler/SymfonyUidHandlerTest.php index 7f0dbf956..9c7cf1b59 100644 --- a/tests/Handler/SymfonyUidHandlerTest.php +++ b/tests/Handler/SymfonyUidHandlerTest.php @@ -10,6 +10,7 @@ use JMS\Serializer\Handler\SymfonyUidHandler; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\SerializerInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Ulid; @@ -46,33 +47,36 @@ public static function dataUid(): \Generator /** * @dataProvider dataUid */ + #[DataProvider('dataUid')] public function testSerializeUidToJson(AbstractUid $uid): void { self::assertJsonStringEqualsJsonString( sprintf('"%s"', (string) $uid), - $this->createSerializer()->serialize($uid, 'json', null, AbstractUid::class) + $this->createSerializer()->serialize($uid, 'json', null, AbstractUid::class), ); } /** * @dataProvider dataUid */ + #[DataProvider('dataUid')] public function testSerializeUidToXmlWithCData(AbstractUid $uid): void { self::assertXmlStringEqualsXmlString( sprintf('%s', (string) $uid), - $this->createSerializer()->serialize($uid, 'xml', null, AbstractUid::class) + $this->createSerializer()->serialize($uid, 'xml', null, AbstractUid::class), ); } /** * @dataProvider dataUid */ + #[DataProvider('dataUid')] public function testSerializeUidToXmlWithoutCData(AbstractUid $uid): void { self::assertXmlStringEqualsXmlString( sprintf('%s', (string) $uid), - $this->createSerializer(false)->serialize($uid, 'xml', null, AbstractUid::class) + $this->createSerializer(false)->serialize($uid, 'xml', null, AbstractUid::class), ); } @@ -82,7 +86,7 @@ public function testSerializeUidToBase32(): void self::assertJsonStringEqualsJsonString( sprintf('"%s"', $uid->toBase32()), - $this->createSerializer()->serialize($uid, 'json', null, sprintf('%s<%s>', AbstractUid::class, SymfonyUidHandler::FORMAT_BASE32)) + $this->createSerializer()->serialize($uid, 'json', null, sprintf('%s<%s>', AbstractUid::class, SymfonyUidHandler::FORMAT_BASE32)), ); } @@ -92,7 +96,7 @@ public function testSerializeUidToBase58(): void self::assertJsonStringEqualsJsonString( sprintf('"%s"', $uid->toBase58()), - $this->createSerializer()->serialize($uid, 'json', null, sprintf('%s<%s>', AbstractUid::class, SymfonyUidHandler::FORMAT_BASE58)) + $this->createSerializer()->serialize($uid, 'json', null, sprintf('%s<%s>', AbstractUid::class, SymfonyUidHandler::FORMAT_BASE58)), ); } @@ -102,7 +106,7 @@ public function testSerializeUidToRfc4122(): void self::assertJsonStringEqualsJsonString( sprintf('"%s"', $uid->toRfc4122()), - $this->createSerializer()->serialize($uid, 'json', null, sprintf('%s<%s>', AbstractUid::class, SymfonyUidHandler::FORMAT_RFC4122)) + $this->createSerializer()->serialize($uid, 'json', null, sprintf('%s<%s>', AbstractUid::class, SymfonyUidHandler::FORMAT_RFC4122)), ); } @@ -117,6 +121,7 @@ public function testSerializeUidRejectsInvalidFormat(): void /** * @dataProvider dataUid */ + #[DataProvider('dataUid')] public function testDeserializeUidFromJson(AbstractUid $uid): void { self::assertTrue($uid->equals($this->createSerializer()->deserialize(sprintf('"%s"', (string) $uid), \get_class($uid), 'json'))); @@ -125,6 +130,7 @@ public function testDeserializeUidFromJson(AbstractUid $uid): void /** * @dataProvider dataUid */ + #[DataProvider('dataUid')] public function testDeserializeUidFromXml(AbstractUid $uid): void { self::assertTrue($uid->equals($this->createSerializer()->deserialize(sprintf('%s', (string) $uid), \get_class($uid), 'xml'))); diff --git a/tests/Metadata/ClassMetadataTest.php b/tests/Metadata/ClassMetadataTest.php index 6b523cfeb..eb31e4954 100644 --- a/tests/Metadata/ClassMetadataTest.php +++ b/tests/Metadata/ClassMetadataTest.php @@ -4,8 +4,10 @@ namespace JMS\Serializer\Tests\Metadata; +use JMS\Serializer\Exception\InvalidMetadataException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ClassMetadataTest extends TestCase @@ -23,14 +25,14 @@ public static function getAccessOrderCases() public function testSerialization() { - $meta = new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'b'); + $meta = new PropertyMetadata(PropertyMetadataOrder::class, 'b'); $restoredMeta = unserialize(serialize($meta)); self::assertEquals($meta, $restoredMeta); } public function testSerializationClass() { - $meta = new ClassMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder'); + $meta = new ClassMetadata(PropertyMetadataOrder::class); $meta->xmlRootPrefix = 'foo'; $meta->xmlDiscriminatorCData = true; $meta->xmlDiscriminatorAttribute = false; @@ -43,11 +45,12 @@ public function testSerializationClass() /** * @dataProvider getAccessOrderCases */ + #[DataProvider('getAccessOrderCases')] public function testSetAccessorOrderCustom(array $order, array $expected) { - $metadata = new ClassMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder'); - $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'b')); - $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'a')); + $metadata = new ClassMetadata(PropertyMetadataOrder::class); + $metadata->addPropertyMetadata(new PropertyMetadata(PropertyMetadataOrder::class, 'b')); + $metadata->addPropertyMetadata(new PropertyMetadata(PropertyMetadataOrder::class, 'a')); self::assertEquals(['b', 'a'], array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, $order); @@ -56,9 +59,9 @@ public function testSetAccessorOrderCustom(array $order, array $expected) public function testSetAccessorOrderAlphabetical() { - $metadata = new ClassMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder'); - $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'b')); - $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'a')); + $metadata = new ClassMetadata(PropertyMetadataOrder::class); + $metadata->addPropertyMetadata(new PropertyMetadata(PropertyMetadataOrder::class, 'b')); + $metadata->addPropertyMetadata(new PropertyMetadata(PropertyMetadataOrder::class, 'a')); self::assertEquals(['b', 'a'], array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_ALPHABETICAL); @@ -68,6 +71,7 @@ public function testSetAccessorOrderAlphabetical() /** * @dataProvider providerPublicMethodData */ + #[DataProvider('providerPublicMethodData')] public function testAccessorTypePublicMethod($property, $getterInit, $setterInit, $getterName, $setterName) { $object = new PropertyMetadataPublicMethod(); @@ -82,9 +86,10 @@ public function testAccessorTypePublicMethod($property, $getterInit, $setterInit /** * @dataProvider providerPublicMethodException */ + #[DataProvider('providerPublicMethodException')] public function testAccessorTypePublicMethodException($getter, $setter, $message) { - $this->expectException('\JMS\Serializer\Exception\InvalidMetadataException'); + $this->expectException(InvalidMetadataException::class); $this->expectExceptionMessage($message); $object = new PropertyMetadataPublicMethod(); diff --git a/tests/Metadata/Driver/AnnotationDriverTest.php b/tests/Metadata/Driver/AnnotationDriverTest.php index 6ae989d90..b03b6ab57 100644 --- a/tests/Metadata/Driver/AnnotationDriverTest.php +++ b/tests/Metadata/Driver/AnnotationDriverTest.php @@ -6,13 +6,20 @@ use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Metadata\Driver\AnnotationDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; +use Metadata\Driver\DriverChain; use Metadata\Driver\DriverInterface; class AnnotationDriverTest extends BaseAnnotationOrAttributeDriverTestCase { protected function getDriver(?string $subDir = null, bool $addUnderscoreDir = true): DriverInterface { - return new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy(), null, $this->getExpressionEvaluator()); + $namingStrategy = new IdenticalPropertyNamingStrategy(); + + return new DriverChain([ + new AnnotationDriver(new AnnotationReader(), $namingStrategy, null, $this->getExpressionEvaluator()), + new NullDriver($namingStrategy), + ]); } } diff --git a/tests/Metadata/Driver/AttributeDriverTest.php b/tests/Metadata/Driver/AttributeDriverTest.php index b2255b6da..5dcc3c4d8 100644 --- a/tests/Metadata/Driver/AttributeDriverTest.php +++ b/tests/Metadata/Driver/AttributeDriverTest.php @@ -5,7 +5,9 @@ namespace JMS\Serializer\Tests\Metadata\Driver; use JMS\Serializer\Metadata\Driver\AttributeDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; +use Metadata\Driver\DriverChain; use Metadata\Driver\DriverInterface; class AttributeDriverTest extends BaseAnnotationOrAttributeDriverTestCase @@ -21,6 +23,11 @@ protected function setUp(): void protected function getDriver(?string $subDir = null, bool $addUnderscoreDir = true): DriverInterface { - return new AttributeDriver(new IdenticalPropertyNamingStrategy(), null, $this->getExpressionEvaluator()); + $namingStrategy = new IdenticalPropertyNamingStrategy(); + + return new DriverChain([ + new AttributeDriver($namingStrategy, null, $this->getExpressionEvaluator()), + new NullDriver($namingStrategy), + ]); } } diff --git a/tests/Metadata/Driver/BaseAnnotationOrAttributeDriverTestCase.php b/tests/Metadata/Driver/BaseAnnotationOrAttributeDriverTestCase.php index 111da5737..97bfe54be 100644 --- a/tests/Metadata/Driver/BaseAnnotationOrAttributeDriverTestCase.php +++ b/tests/Metadata/Driver/BaseAnnotationOrAttributeDriverTestCase.php @@ -5,12 +5,13 @@ namespace JMS\Serializer\Tests\Metadata\Driver; use JMS\Serializer\Tests\Fixtures\AllExcludedObject; -use Metadata\Driver\DriverInterface; +use JMS\Serializer\Tests\Fixtures\MissingAttributeObject; +use ReflectionClass; + +use const PHP_VERSION_ID; abstract class BaseAnnotationOrAttributeDriverTestCase extends BaseDriverTestCase { - abstract protected function getDriver(?string $subDir = null, bool $addUnderscoreDir = true): DriverInterface; - public function testAllExcluded(): void { $a = new AllExcludedObject(); @@ -29,4 +30,14 @@ public function testShortExposeSyntax(): void { $this->markTestSkipped('Short expose syntax not supported on annotations or attribute'); } + + public function testCanHandleMissingAttributes(): void + { + $metadata = $this->getDriver()->loadMetadataForClass(new ReflectionClass(MissingAttributeObject::class)); + self::assertArrayHasKey('property', $metadata->propertyMetadata); + + if (PHP_VERSION_ID >= 80000) { + self::assertArrayHasKey('propertyFromMethod', $metadata->propertyMetadata); + } + } } diff --git a/tests/Metadata/Driver/BaseDriverTestCase.php b/tests/Metadata/Driver/BaseDriverTestCase.php index 8236d84b8..656adca7a 100644 --- a/tests/Metadata/Driver/BaseDriverTestCase.php +++ b/tests/Metadata/Driver/BaseDriverTestCase.php @@ -240,7 +240,7 @@ public function testLoadDiscriminator() 'car' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Car', 'moped' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Moped', ], - $m->discriminatorMap + $m->discriminatorMap, ); } @@ -257,7 +257,7 @@ public function testLoadDiscriminatorWhenParentIsInDiscriminatorMap() 'post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Post', 'image_post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost', ], - $m->discriminatorMap + $m->discriminatorMap, ); } @@ -273,7 +273,7 @@ public function testLoadXmlDiscriminator() [ 'child' => ObjectWithXmlAttributeDiscriminatorChild::class, ], - $m->discriminatorMap + $m->discriminatorMap, ); self::assertTrue($m->xmlDiscriminatorAttribute); self::assertFalse($m->xmlDiscriminatorCData); @@ -291,7 +291,7 @@ public function testLoadXmlDiscriminatorWithNamespaces() [ 'child' => ObjectWithXmlNamespaceDiscriminatorChild::class, ], - $m->discriminatorMap + $m->discriminatorMap, ); self::assertEquals('http://example.com/', $m->xmlDiscriminatorNamespace); self::assertFalse($m->xmlDiscriminatorAttribute); @@ -320,7 +320,7 @@ public function testLoadXmlDiscriminatorWithAttributeNamespaces() [ 'child' => ObjectWithXmlNamespaceAttributeDiscriminatorChild::class, ], - $m->discriminatorMap + $m->discriminatorMap, ); self::assertEquals('http://example.com/', $m->xmlDiscriminatorNamespace); self::assertTrue($m->xmlDiscriminatorAttribute); @@ -337,7 +337,7 @@ public function testLoadDiscriminatorWithGroup() self::assertEquals($m->name, $m->discriminatorBaseClass); self::assertEquals( ['car' => 'JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car'], - $m->discriminatorMap + $m->discriminatorMap, ); } diff --git a/tests/Metadata/Driver/DefaultDriverFactoryTest.php b/tests/Metadata/Driver/DefaultDriverFactoryTest.php index cd9258871..6f068c875 100644 --- a/tests/Metadata/Driver/DefaultDriverFactoryTest.php +++ b/tests/Metadata/Driver/DefaultDriverFactoryTest.php @@ -15,10 +15,6 @@ class DefaultDriverFactoryTest extends TestCase { public function testDefaultDriverFactoryLoadsTypedPropertiesDriver() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', __METHOD__)); - } - $factory = new DefaultDriverFactory(new IdenticalPropertyNamingStrategy()); $driver = $factory->createDriver([], new AnnotationReader()); diff --git a/tests/Metadata/Driver/DocBlockDriverTest.php b/tests/Metadata/Driver/DocBlockDriverTest.php index e608e78a0..414aa4a78 100644 --- a/tests/Metadata/Driver/DocBlockDriverTest.php +++ b/tests/Metadata/Driver/DocBlockDriverTest.php @@ -8,6 +8,7 @@ use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Metadata\Driver\DocBlockDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Metadata\Driver\TypedPropertiesDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; use JMS\Serializer\Tests\Fixtures\DocBlockType\AlternativePHPDocsNames; @@ -47,19 +48,23 @@ use JMS\Serializer\Tests\Fixtures\DocBlockType\SingleClassFromGlobalNamespaceTypeHint; use JMS\Serializer\Tests\Fixtures\DocBlockType\UnionTypedDocBLockProperty; use JMS\Serializer\Tests\Fixtures\DocBlockType\VirtualPropertyGetter; +use Metadata\Driver\DriverChain; use PHPUnit\Framework\TestCase; class DocBlockDriverTest extends TestCase { private function resolve(string $classToResolve): ClassMetadata { - if (PHP_VERSION_ID > 70400) { - $baseDriver = new TypedPropertiesDriver(new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy())); - } else { - $baseDriver = new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy()); - } + $namingStrategy = new IdenticalPropertyNamingStrategy(); + + $driver = new DriverChain([ + new AnnotationDriver(new AnnotationReader(), $namingStrategy), + new NullDriver($namingStrategy), + ]); + + $driver = new TypedPropertiesDriver($driver); - $driver = new DocBlockDriver($baseDriver); + $driver = new DocBlockDriver($driver); $m = $driver->loadMetadataForClass(new \ReflectionClass($classToResolve)); self::assertNotNull($m); @@ -69,122 +74,86 @@ private function resolve(string $classToResolve): ClassMetadata public function testInferDocBlockCollectionOfScalars() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfScalars::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => 'string', 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockCollectionAsList(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionAsList::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => 'int', 'params' => []], ['name' => 'string', 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockCollectionOfClassesFromSameNamespace() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromSameNamespace::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => Product::class, 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockCollectionOfClassesFromUsingFullNamespacePath() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesWithFullNamespacePath::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => Product::class, 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockCollectionFromGenericLikeClass() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionTypedAsGenericClass::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => Product::class, 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockMapFromGenericLikeClass() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(MapTypedAsGenericClass::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => 'int', 'params' => []], ['name' => Product::class, 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockCollectionOfClassesIgnoringNullTypeHint() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesWithNull::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => Product::class, 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testInferDocBlockCollectionOfClassesIgnoringNullTypeHintWithSingleLinePhpDoc() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesWithNullSingleLinePhpDoc::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => Product::class, 'params' => []]]], - $m->propertyMetadata['productIds']->type + $m->propertyMetadata['productIds']->type, ); } public function testThrowingExceptionWhenNotExistingClassWasGiven() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $this->expectException(\InvalidArgumentException::class); $this->resolve(CollectionOfNotExistingClasses::class); @@ -192,149 +161,109 @@ public function testThrowingExceptionWhenNotExistingClassWasGiven() public function testInferDocBlockCollectionOfClassesFromDifferentNamespace() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromDifferentNamespace::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductDescription::class, 'params' => []]]], - $m->propertyMetadata['productDescriptions']->type + $m->propertyMetadata['productDescriptions']->type, ); } public function testInferDocBlockCollectionOfClassesFromGlobalNamespace() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromGlobalNamespace::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => \stdClass::class, 'params' => []]]], - $m->propertyMetadata['products']->type + $m->propertyMetadata['products']->type, ); } public function testInferDocBlockCollectionOfClassesFromDifferentNamespaceUsingSingleAlias() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromDifferentNamespaceUsingSingleAlias::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductDescription::class, 'params' => []]]], - $m->propertyMetadata['productDescriptions']->type + $m->propertyMetadata['productDescriptions']->type, ); } public function testInferDocBlockCollectionOfClassesFromDifferentNamespaceUsingGroupAlias() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromDifferentNamespaceUsingGroupAlias::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductDescription::class, 'params' => []]]], - $m->propertyMetadata['productDescriptions']->type + $m->propertyMetadata['productDescriptions']->type, ); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductName::class, 'params' => []]]], - $m->propertyMetadata['productNames']->type + $m->propertyMetadata['productNames']->type, ); } public function testInferDocBlockCollectionOfClassesFromTraits() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromTrait::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductDescription::class, 'params' => []]]], - $m->propertyMetadata['productDescriptions']->type + $m->propertyMetadata['productDescriptions']->type, ); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductName::class, 'params' => []]]], - $m->propertyMetadata['productNames']->type + $m->propertyMetadata['productNames']->type, ); } public function testInferDocBlockCollectionOfClassesFromTraitInsideTrait() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfClassesFromTraitInsideTrait::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductDescription::class, 'params' => []]]], - $m->propertyMetadata['productDescriptions']->type + $m->propertyMetadata['productDescriptions']->type, ); } public function testInferDocBlockCollectionOfInterfacesFromDifferentNamespace() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfInterfacesFromDifferentNamespace::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductColor::class, 'params' => []]]], - $m->propertyMetadata['productColors']->type + $m->propertyMetadata['productColors']->type, ); } public function testInferDocBlockCollectionOfInterfacesFromGlobalNamespace() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfInterfacesFromGlobalNamespace::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductColor::class, 'params' => []]]], - $m->propertyMetadata['productColors']->type + $m->propertyMetadata['productColors']->type, ); } public function testInferDocBlockCollectionOfInterfacesFromSameNamespace() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfInterfacesFromSameNamespace::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => Vehicle::class, 'params' => []]]], - $m->propertyMetadata['vehicles']->type + $m->propertyMetadata['vehicles']->type, ); } public function testInferDocBlockCollectionOfInterfacesWithFullNamespacePath() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - $m = $this->resolve(CollectionOfInterfacesWithFullNamespacePath::class); self::assertEquals( ['name' => 'array', 'params' => [['name' => ProductColor::class, 'params' => []]]], - $m->propertyMetadata['productColors']->type + $m->propertyMetadata['productColors']->type, ); } @@ -344,7 +273,7 @@ public function testInferTypeForNonCollectionFromSameNamespaceType() self::assertEquals( ['name' => \stdClass::class, 'params' => []], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -354,7 +283,7 @@ public function testInferTypeForNonCollectionFromDifferentNamespaceType() self::assertEquals( ['name' => ProductDescription::class, 'params' => []], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -364,7 +293,7 @@ public function testInferTypeForNonUnionDocblockType() self::assertEquals( null, - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -378,7 +307,7 @@ public function testInferTypeForConstructorPropertyPromotion() self::assertEquals( ['name' => 'array', 'params' => [['name' => 'string', 'params' => []]]], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -392,7 +321,7 @@ public function testInferTypeForConstructorPropertyPromotionWithoutDocblock() self::assertEquals( null, - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -406,7 +335,7 @@ public function testInferTypeForConstructorPropertyPromotionWithScalar() self::assertEquals( ['name' => 'string', 'params' => []], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -416,7 +345,7 @@ public function testInferTypeForPhpstanArray() self::assertEquals( ['name' => 'array', 'params' => []], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -426,7 +355,7 @@ public function testInferTypeForPhpstanNestedArrayShape() self::assertEquals( ['name' => 'array', 'params' => []], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -436,11 +365,11 @@ public function testInferTypeForMultiplePhpstanArray() self::assertEquals( ['name' => 'array', 'params' => []], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); self::assertEquals( ['name' => 'array', 'params' => []], - $m->propertyMetadata['details']->type + $m->propertyMetadata['details']->type, ); } @@ -450,7 +379,7 @@ public function testInferTypeForPhpstanArrayCollection() self::assertEquals( ['name' => 'array', 'params' => [['name' => 'int', 'params' => []], ['name' => ProductType::class, 'params' => []]]], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } @@ -460,7 +389,7 @@ public function testInferTypeForVirtualPropertyGetter() self::assertEquals( ['name' => 'array', 'params' => [['name' => 'string', 'params' => []]]], - $m->propertyMetadata['arrayOfStrings']->type + $m->propertyMetadata['arrayOfStrings']->type, ); } @@ -470,17 +399,17 @@ public function testAlternativeNames() self::assertEquals( ['name' => 'integer', 'params' => []], - $m->propertyMetadata['integer']->type + $m->propertyMetadata['integer']->type, ); self::assertEquals( ['name' => 'double', 'params' => []], - $m->propertyMetadata['double']->type + $m->propertyMetadata['double']->type, ); self::assertEquals( ['name' => 'boolean', 'params' => []], - $m->propertyMetadata['boolean']->type + $m->propertyMetadata['boolean']->type, ); } } diff --git a/tests/Metadata/Driver/DocBlockTypeResolverTest.php b/tests/Metadata/Driver/DocBlockTypeResolverTest.php index 2ad9372da..827a8c622 100644 --- a/tests/Metadata/Driver/DocBlockTypeResolverTest.php +++ b/tests/Metadata/Driver/DocBlockTypeResolverTest.php @@ -18,8 +18,8 @@ public function testGetPropertyDocblockTypeHintDoesNotCrash(): void $resolver = new DocBlockTypeResolver(); self::assertNull( $resolver->getPropertyDocblockTypeHint( - new ReflectionProperty(ObjectWithPhpDocProperty::class, 'emptyBlock') - ) + new ReflectionProperty(ObjectWithPhpDocProperty::class, 'emptyBlock'), + ), ); } @@ -29,14 +29,14 @@ public function testGetPropertyDocblockTypeHintDoesNotCrashWhenUnionType(): void self::assertSame( 'string', $resolver->getPropertyDocblockTypeHint( - new ReflectionProperty(ObjectWithPhpDocProperty::class, 'firstname') - ) + new ReflectionProperty(ObjectWithPhpDocProperty::class, 'firstname'), + ), ); self::assertSame( 'string', $resolver->getPropertyDocblockTypeHint( - new ReflectionProperty(ObjectWithPhpDocProperty::class, 'lastname') - ) + new ReflectionProperty(ObjectWithPhpDocProperty::class, 'lastname'), + ), ); } } diff --git a/tests/Metadata/Driver/DoctrineDriverTest.php b/tests/Metadata/Driver/DoctrineDriverTest.php index 88fd2a0f0..bfaf44f90 100644 --- a/tests/Metadata/Driver/DoctrineDriverTest.php +++ b/tests/Metadata/Driver/DoctrineDriverTest.php @@ -5,15 +5,19 @@ namespace JMS\Serializer\Tests\Metadata\Driver; use Doctrine\Common\Annotations\AnnotationReader; +use Doctrine\DBAL\DriverManager; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; -use Doctrine\ORM\Mapping\Driver\AnnotationDriver as DoctrineDriver; -use Doctrine\ORM\Version as ORMVersion; +use Doctrine\ORM\Mapping\Driver\AnnotationDriver as DoctrineAnnotationDriver; +use Doctrine\ORM\Mapping\Driver\AttributeDriver as DoctrineAttributeDriver; use Doctrine\Persistence\ManagerRegistry; use JMS\Serializer\Metadata\Driver\AnnotationDriver; +use JMS\Serializer\Metadata\Driver\AnnotationOrAttributeDriver; use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; use JMS\Serializer\Tests\Fixtures\Doctrine\Embeddable\BlogPostWithEmbedded; +use Metadata\Driver\DriverChain; use PHPUnit\Framework\TestCase; class DoctrineDriverTest extends TestCase @@ -27,10 +31,6 @@ public function getMetadata() public function testMetadataForEmbedded() { - if (ORMVersion::compare('2.5') >= 0) { - $this->markTestSkipped('Not using Doctrine ORM >= 2.5 with Embedded entities'); - } - $refClass = new \ReflectionClass(BlogPostWithEmbedded::class); $meta = $this->getDoctrineDriver()->loadMetadataForClass($refClass); self::assertNotNull($meta); @@ -42,7 +42,7 @@ public function testTypelessPropertyIsGivenTypeFromDoctrineMetadata() self::assertEquals( ['name' => 'DateTime', 'params' => []], - $metadata->propertyMetadata['createdAt']->type + $metadata->propertyMetadata['createdAt']->type, ); } @@ -51,7 +51,7 @@ public function testSingleValuedAssociationIsProperlyHinted() $metadata = $this->getMetadata(); self::assertEquals( ['name' => 'JMS\Serializer\Tests\Fixtures\Doctrine\Entity\Author', 'params' => []], - $metadata->propertyMetadata['author']->type + $metadata->propertyMetadata['author']->type, ); } @@ -66,7 +66,7 @@ public function testMultiValuedAssociationIsProperlyHinted() ['name' => 'JMS\Serializer\Tests\Fixtures\Doctrine\Entity\Comment', 'params' => []], ], ], - $metadata->propertyMetadata['comments']->type + $metadata->propertyMetadata['comments']->type, ); } @@ -77,7 +77,7 @@ public function testTypeGuessByDoctrineIsOverwrittenByDelegateDriver() // This would be guessed as boolean but we've overriden it to integer self::assertEquals( ['name' => 'integer', 'params' => []], - $metadata->propertyMetadata['published']->type + $metadata->propertyMetadata['published']->type, ); } @@ -93,7 +93,7 @@ public function testNonDoctrineEntityClassIsNotModified() // because it has no Doctrine metadata. $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost'); - $plainMetadata = $this->getAnnotationDriver()->loadMetadataForClass($refClass); + $plainMetadata = $this->getMetadataDriver()->loadMetadataForClass($refClass); $doctrineMetadata = $this->getDoctrineDriver()->loadMetadataForClass($refClass); // Do not compare timestamps @@ -106,7 +106,7 @@ public function testNonDoctrineEntityClassIsNotModified() public function testExcludePropertyNoPublicAccessorException() { - $first = $this->getAnnotationDriver() + $first = $this->getMetadataDriver() ->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor')); self::assertArrayHasKey('id', $first->propertyMetadata); @@ -125,7 +125,7 @@ public function testGuidPropertyIsGivenStringType() self::assertEquals( ['name' => 'string', 'params' => []], - $metadata->propertyMetadata['guid']->type + $metadata->propertyMetadata['guid']->type, ); } @@ -134,21 +134,39 @@ protected function getEntityManager() $config = new Configuration(); $config->setProxyDir(sys_get_temp_dir() . '/JMSDoctrineTestProxies'); $config->setProxyNamespace('JMS\Tests\Proxies'); - $config->setMetadataDriverImpl( - new DoctrineDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/Doctrine') - ); - $conn = [ + if (PHP_VERSION_ID >= 80000 && class_exists(DoctrineAttributeDriver::class)) { + $config->setMetadataDriverImpl( + new DoctrineAttributeDriver([__DIR__ . '/../../Fixtures/Doctrine'], true), + ); + } else { + $config->setMetadataDriverImpl( + new DoctrineAnnotationDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/Doctrine'), + ); + } + + $conn = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'memory' => true, - ]; + ]); - return EntityManager::create($conn, $config); + return new EntityManager($conn, $config); } - public function getAnnotationDriver() + public function getMetadataDriver() { - return new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy()); + $driver = new DriverChain(); + $namingStrategy = new IdenticalPropertyNamingStrategy(); + + if (PHP_VERSION_ID >= 80000) { + $driver->addDriver(new AnnotationOrAttributeDriver($namingStrategy)); + } else { + $driver->addDriver(new AnnotationDriver(new AnnotationReader(), $namingStrategy)); + } + + $driver->addDriver(new NullDriver($namingStrategy)); + + return $driver; } protected function getDoctrineDriver() @@ -156,11 +174,11 @@ protected function getDoctrineDriver() $registry = $this->getMockBuilder(ManagerRegistry::class)->getMock(); $registry->expects($this->atLeastOnce()) ->method('getManagerForClass') - ->will($this->returnValue($this->getEntityManager())); + ->willReturn($this->getEntityManager()); return new DoctrineTypeDriver( - $this->getAnnotationDriver(), - $registry + $this->getMetadataDriver(), + $registry, ); } } diff --git a/tests/Metadata/Driver/DoctrinePHPCRDriverTest.php b/tests/Metadata/Driver/DoctrinePHPCRDriverTest.php index ea1e5980a..37c92e7a7 100644 --- a/tests/Metadata/Driver/DoctrinePHPCRDriverTest.php +++ b/tests/Metadata/Driver/DoctrinePHPCRDriverTest.php @@ -12,6 +12,11 @@ use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Metadata\Driver\DoctrinePHPCRTypeDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; +use JMS\Serializer\Tests\Fixtures\BlogPost; +use JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Author; +use JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\BlogPost as BlogPostPHPCR; +use JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Comment; +use PHPCR\SessionInterface; use PHPUnit\Framework\TestCase; class DoctrinePHPCRDriverTest extends TestCase @@ -25,7 +30,7 @@ protected function setUp(): void public function getMetadata() { - $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\BlogPost'); + $refClass = new \ReflectionClass(BlogPostPHPCR::class); return $this->getDoctrinePHPCRDriver()->loadMetadataForClass($refClass); } @@ -35,7 +40,7 @@ public function testTypelessPropertyIsGivenTypeFromDoctrineMetadata() $metadata = $this->getMetadata(); self::assertEquals( ['name' => 'DateTime', 'params' => []], - $metadata->propertyMetadata['createdAt']->type + $metadata->propertyMetadata['createdAt']->type, ); } @@ -43,8 +48,8 @@ public function testSingleValuedAssociationIsProperlyHinted() { $metadata = $this->getMetadata(); self::assertEquals( - ['name' => 'JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Author', 'params' => []], - $metadata->propertyMetadata['author']->type + ['name' => Author::class, 'params' => []], + $metadata->propertyMetadata['author']->type, ); } @@ -56,10 +61,10 @@ public function testMultiValuedAssociationIsProperlyHinted() [ 'name' => 'ArrayCollection', 'params' => [ - ['name' => 'JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Comment', 'params' => []], + ['name' => Comment::class, 'params' => []], ], ], - $metadata->propertyMetadata['comments']->type + $metadata->propertyMetadata['comments']->type, ); } @@ -70,7 +75,7 @@ public function testTypeGuessByDoctrineIsOverwrittenByDelegateDriver() // This would be guessed as boolean but we've overridden it to integer self::assertEquals( ['name' => 'integer', 'params' => []], - $metadata->propertyMetadata['published']->type + $metadata->propertyMetadata['published']->type, ); } @@ -78,7 +83,7 @@ public function testNonDoctrineDocumentClassIsNotModified() { // Note: Using regular BlogPost fixture here instead of Doctrine fixture // because it has no Doctrine metadata. - $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost'); + $refClass = new \ReflectionClass(BlogPost::class); $plainMetadata = $this->getAnnotationDriver()->loadMetadataForClass($refClass); $doctrineMetadata = $this->getDoctrinePHPCRDriver()->loadMetadataForClass($refClass); @@ -97,10 +102,10 @@ protected function getDocumentManager() $config->setProxyDir(sys_get_temp_dir() . '/JMSDoctrineTestProxies'); $config->setProxyNamespace('JMS\Tests\Proxies'); $config->setMetadataDriverImpl( - new DoctrinePHPCRDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/DoctrinePHPCR') + new DoctrinePHPCRDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/DoctrinePHPCR'), ); - $session = $this->getMockBuilder('PHPCR\SessionInterface')->getMock(); + $session = $this->getMockBuilder(SessionInterface::class)->getMock(); return DocumentManager::create($session, $config); } @@ -115,11 +120,11 @@ protected function getDoctrinePHPCRDriver() $registry = $this->getMockBuilder(ManagerRegistry::class)->getMock(); $registry->expects($this->atLeastOnce()) ->method('getManagerForClass') - ->will($this->returnValue($this->getDocumentManager())); + ->willReturn($this->getDocumentManager()); return new DoctrinePHPCRTypeDriver( $this->getAnnotationDriver(), - $registry + $registry, ); } } diff --git a/tests/Metadata/Driver/NullDriverTest.php b/tests/Metadata/Driver/NullDriverTest.php index 3a0c15f55..9c83dad17 100644 --- a/tests/Metadata/Driver/NullDriverTest.php +++ b/tests/Metadata/Driver/NullDriverTest.php @@ -6,13 +6,14 @@ use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\Driver\NullDriver; +use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; use PHPUnit\Framework\TestCase; class NullDriverTest extends TestCase { public function testReturnsValidMetadata() { - $driver = new NullDriver(); + $driver = new NullDriver(new IdenticalPropertyNamingStrategy()); $metadata = $driver->loadMetadataForClass(new \ReflectionClass('stdClass')); diff --git a/tests/Metadata/Driver/TypedPropertiesDriverTest.php b/tests/Metadata/Driver/TypedPropertiesDriverTest.php index 618197523..70540d2f1 100644 --- a/tests/Metadata/Driver/TypedPropertiesDriverTest.php +++ b/tests/Metadata/Driver/TypedPropertiesDriverTest.php @@ -15,13 +15,6 @@ class TypedPropertiesDriverTest extends TestCase { - protected function setUp(): void - { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', TypedPropertiesDriver::class)); - } - } - public function testInferPropertiesFromTypes() { $m = $this->resolve(User::class); diff --git a/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php b/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php index 150bf2245..ce22d05d9 100644 --- a/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php +++ b/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php @@ -7,9 +7,11 @@ use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\Driver\AnnotationDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Metadata\Driver\TypedPropertiesDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; use JMS\Serializer\Tests\Fixtures\TypedProperties\UnionTypedProperties; +use Metadata\Driver\DriverChain; use PHPUnit\Framework\TestCase; use ReflectionClass; @@ -40,14 +42,20 @@ public function testInferUnionTypesShouldResultInNoType() ], ], ], - $m->propertyMetadata['data']->type + $m->propertyMetadata['data']->type, ); } private function resolve(string $classToResolve): ClassMetadata { - $baseDriver = new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy()); - $driver = new TypedPropertiesDriver($baseDriver); + $namingStrategy = new IdenticalPropertyNamingStrategy(); + + $driver = new DriverChain([ + new AnnotationDriver(new AnnotationReader(), $namingStrategy), + new NullDriver($namingStrategy), + ]); + + $driver = new TypedPropertiesDriver($driver); $m = $driver->loadMetadataForClass(new ReflectionClass($classToResolve)); self::assertNotNull($m); diff --git a/tests/Metadata/Driver/YamlDriverTest.php b/tests/Metadata/Driver/YamlDriverTest.php index f2a31cc6b..4b528bc94 100644 --- a/tests/Metadata/Driver/YamlDriverTest.php +++ b/tests/Metadata/Driver/YamlDriverTest.php @@ -108,7 +108,7 @@ public function testLoadingMultipleMetadataExtensions(): void BlogPost::class, Person::class, ], - $classNames + $classNames, ); } diff --git a/tests/Ordering/CustomPropertyOrderingStrategyTest.php b/tests/Ordering/CustomPropertyOrderingStrategyTest.php index 065b07beb..b1062bd04 100644 --- a/tests/Ordering/CustomPropertyOrderingStrategyTest.php +++ b/tests/Ordering/CustomPropertyOrderingStrategyTest.php @@ -6,6 +6,7 @@ use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Ordering\CustomPropertyOrderingStrategy; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class CustomPropertyOrderingStrategyTest extends TestCase @@ -13,13 +14,14 @@ class CustomPropertyOrderingStrategyTest extends TestCase /** * @dataProvider dataOrder */ + #[DataProvider('dataOrder')] public function testOrder(array $ordering, array $keysToSort, array $expectedResult): void { $strategy = new CustomPropertyOrderingStrategy(array_flip($ordering)); $properties = array_combine( $keysToSort, - array_pad([], count($keysToSort), $this->createMock(PropertyMetadata::class)) + array_pad([], count($keysToSort), $this->createMock(PropertyMetadata::class)), ); $sortedProperties = $strategy->order($properties); self::assertEquals($expectedResult, array_keys($sortedProperties)); diff --git a/tests/Serializer/ArrayTest.php b/tests/Serializer/ArrayTest.php index a74418438..a59c03a51 100644 --- a/tests/Serializer/ArrayTest.php +++ b/tests/Serializer/ArrayTest.php @@ -4,12 +4,14 @@ namespace JMS\Serializer\Tests\Serializer; +use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Tests\Fixtures\Author; use JMS\Serializer\Tests\Fixtures\AuthorList; use JMS\Serializer\Tests\Fixtures\Order; use JMS\Serializer\Tests\Fixtures\Price; use JMS\Serializer\Tests\Fixtures\TypedProperties\ConstructorPromotion\DefaultValuesAndAccessors; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ArrayTest extends TestCase @@ -38,13 +40,14 @@ public function testToArray() /** * @dataProvider scalarValues */ + #[DataProvider('scalarValues')] public function testToArrayWithScalar($input) { - $this->expectException('JMS\Serializer\Exception\RuntimeException'); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage(sprintf( 'The input data of type "%s" did not convert to an array, but got a result of type "%s".', gettype($input), - gettype($input) + gettype($input), )); $result = $this->serializer->toArray($input); @@ -68,7 +71,7 @@ public function testFromArray() ]; $expected = new Order(new Price(2.5)); - $result = $this->serializer->fromArray($data, 'JMS\Serializer\Tests\Fixtures\Order'); + $result = $this->serializer->fromArray($data, Order::class); self::assertEquals($expected, $result); } diff --git a/tests/Serializer/BaseSerializationTestCase.php b/tests/Serializer/BaseSerializationTestCase.php index 9ce0d5cdb..befd9204f 100644 --- a/tests/Serializer/BaseSerializationTestCase.php +++ b/tests/Serializer/BaseSerializationTestCase.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Tests\Serializer; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\Version; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\Context; use JMS\Serializer\DeserializationContext; @@ -63,6 +64,7 @@ use JMS\Serializer\Tests\Fixtures\Discriminator\Post; use JMS\Serializer\Tests\Fixtures\Discriminator\Serialization\ExtendedUser; use JMS\Serializer\Tests\Fixtures\Discriminator\Serialization\User; +use JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle; use JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car as DiscriminatorGroupCar; use JMS\Serializer\Tests\Fixtures\DocBlockType\UnionTypedDocBLockProperty; use JMS\Serializer\Tests\Fixtures\ExclusionStrategy\AlwaysExcludeExclusionStrategy; @@ -128,9 +130,14 @@ use JMS\Serializer\Tests\Fixtures\VehicleInterfaceGarage; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Extension\Core\Type\ButtonType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Form; @@ -179,7 +186,7 @@ public function testSerializeNullArray() self::assertEquals( static::getContent('nullable'), - $this->serializer->serialize($arr, $this->getFormat(), SerializationContext::create()->setSerializeNull(true)) + $this->serializer->serialize($arr, $this->getFormat(), SerializationContext::create()->setSerializeNull(true)), ); } @@ -190,7 +197,7 @@ public function testSerializeNullRoot() self::assertEquals( static::getContent('nullable_root'), - $this->serializer->serialize(null, $this->getFormat(), $context) + $this->serializer->serialize(null, $this->getFormat(), $context), ); } @@ -208,7 +215,7 @@ public function testDeserializeObjectWithMissingTypedArrayProp() $dObj = $this->serializer->deserialize( static::getContent('empty_object'), ObjectWithTypedArraySetter::class, - $this->getFormat() + $this->getFormat(), ); assert($dObj instanceof ObjectWithTypedArraySetter); @@ -223,7 +230,7 @@ public function testSerializeNullArrayExcludingNulls() self::assertEquals( static::getContent('nullable_skip'), - $this->serializer->serialize($arr, $this->getFormat(), SerializationContext::create()->setSerializeNull(false)) + $this->serializer->serialize($arr, $this->getFormat(), SerializationContext::create()->setSerializeNull(false)), ); } @@ -234,7 +241,7 @@ public function testObjectUsingTypeCasting() self::assertEquals( static::getContent('type_casting'), - $this->serialize($typeAliasing) + $this->serialize($typeAliasing), ); } @@ -244,7 +251,7 @@ public function testSerializeNullObject() self::assertEquals( static::getContent('simple_object_nullable'), - $this->serializer->serialize($obj, $this->getFormat(), SerializationContext::create()->setSerializeNull(true)) + $this->serializer->serialize($obj, $this->getFormat(), SerializationContext::create()->setSerializeNull(true)), ); } @@ -259,7 +266,7 @@ public function testDeserializeNullObject() $dObj = $this->serializer->deserialize( static::getContent('simple_object_nullable'), ObjectWithNullProperty::class, - $this->getFormat() + $this->getFormat(), ); assert($dObj instanceof ObjectWithNullProperty); @@ -270,6 +277,7 @@ public function testDeserializeNullObject() /** * @dataProvider getTypes */ + #[DataProvider('getTypes')] public function testNull($type) { if ($this->hasDeserializer()) { @@ -287,6 +295,7 @@ public function testNull($type) /** * @dataProvider getTypes */ + #[DataProvider('getTypes')] public function testNullAllowed($type) { $context = SerializationContext::create()->setSerializeNull(true); @@ -552,6 +561,7 @@ public static function expressionFunctionProvider() * * @dataProvider expressionFunctionProvider */ + #[DataProvider('expressionFunctionProvider')] public function testExpressionExclusion($person, ExpressionFunction $function, $json) { $language = new ExpressionLanguage(); @@ -567,6 +577,7 @@ public function testExpressionExclusion($person, ExpressionFunction $function, $ /** * @dataProvider getBooleans */ + #[DataProvider('getBooleans')] public function testBooleans($strBoolean, $boolean) { self::assertEquals(static::getContent('boolean_' . $strBoolean), $this->serialize($boolean)); @@ -584,6 +595,7 @@ public static function getBooleans() /** * @dataProvider getNumerics */ + #[DataProvider('getNumerics')] public function testNumerics($key, $value, $type) { self::assertSame(static::getContent($key), $this->serialize($value)); @@ -817,9 +829,6 @@ public function testNamedDateTimeArrays() } } - /** - * @group datetime - */ public function testNamedDateTimeImmutableArrays() { $data = [ @@ -858,6 +867,7 @@ public function testArrayMixed() * @dataProvider getDateTime * @group datetime */ + #[DataProvider('getDateTime')] public function testDateTime($key, $value, $type) { self::assertEquals(static::getContent($key), $this->serialize($value)); @@ -883,6 +893,7 @@ public static function getDateTime() * @dataProvider getDateTimeImmutable * @group datetime */ + #[DataProvider('getDateTimeImmutable')] public function testDateTimeImmutable($key, $value, $type) { self::assertEquals(static::getContent($key), $this->serialize($value)); @@ -1246,13 +1257,14 @@ public function testFormErrors() /** * @dataProvider initialFormTypeProvider */ + #[DataProvider('initialFormTypeProvider')] public function testNestedFormErrors($type) { - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $formConfigBuilder = new FormConfigBuilder('foo', null, $dispatcher); $formConfigBuilder->setCompound(true); - $formConfigBuilder->setDataMapper($this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock()); + $formConfigBuilder->setDataMapper($this->getMockBuilder(DataMapperInterface::class)->getMock()); $fooConfig = $formConfigBuilder->getFormConfig(); $form = new Form($fooConfig); @@ -1274,13 +1286,11 @@ public function testNestedFormErrors($type) * @doesNotPerformAssertions * @dataProvider initialFormTypeProvider */ + #[DataProvider('initialFormTypeProvider')] + #[DoesNotPerformAssertions] public function testFormErrorsWithNonFormComponents($type) { - if (!class_exists('Symfony\Component\Form\Extension\Core\Type\SubmitType')) { - $this->markTestSkipped('Not using Symfony Form >= 2.3 with submit type'); - } - - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $factoryBuilder = new FormFactoryBuilder(); $factoryBuilder->addType(new SubmitType()); @@ -1290,7 +1300,7 @@ public function testFormErrorsWithNonFormComponents($type) $formConfigBuilder = new FormConfigBuilder('foo', null, $dispatcher); $formConfigBuilder->setFormFactory($factory); $formConfigBuilder->setCompound(true); - $formConfigBuilder->setDataMapper($this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock()); + $formConfigBuilder->setDataMapper($this->getMockBuilder(DataMapperInterface::class)->getMock()); $fooConfig = $formConfigBuilder->getFormConfig(); $form = new Form($fooConfig); @@ -1332,7 +1342,7 @@ public function testConstraintViolationList() public function testDoctrineProxy() { - if (!class_exists('Doctrine\ORM\Version')) { + if (!class_exists(Version::class)) { $this->markTestSkipped('Doctrine is not available.'); } @@ -1343,7 +1353,7 @@ public function testDoctrineProxy() public function testInitializedDoctrineProxy() { - if (!class_exists('Doctrine\ORM\Version')) { + if (!class_exists(Version::class)) { $this->markTestSkipped('Doctrine is not available.'); } @@ -1367,7 +1377,7 @@ public function testMixedAccessTypes() self::assertEquals(static::getContent('mixed_access_types'), $this->serialize($object)); if ($this->hasDeserializer()) { - $object = $this->deserialize(static::getContent('mixed_access_types'), 'JMS\Serializer\Tests\Fixtures\GetSetObject'); + $object = $this->deserialize(static::getContent('mixed_access_types'), GetSetObject::class); self::assertSame(1, $this->getField($object, 'id')); self::assertSame('Johannes', $this->getField($object, 'name')); self::assertSame(42, $this->getField($object, 'readOnlyProperty')); @@ -1389,27 +1399,27 @@ public function testGroups() self::assertEquals( static::getContent('groups_foo'), - $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(['foo'])) + $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(['foo'])), ); self::assertEquals( static::getContent('groups_foobar'), - $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(['foo', 'bar'])) + $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(['foo', 'bar'])), ); self::assertEquals( static::getContent('groups_all'), - $this->serializer->serialize($groupsObject, $this->getFormat()) + $this->serializer->serialize($groupsObject, $this->getFormat()), ); self::assertEquals( static::getContent('groups_default'), - $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups([GroupsExclusionStrategy::DEFAULT_GROUP])) + $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups([GroupsExclusionStrategy::DEFAULT_GROUP])), ); self::assertEquals( static::getContent('groups_default'), - $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups([GroupsExclusionStrategy::DEFAULT_GROUP])) + $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups([GroupsExclusionStrategy::DEFAULT_GROUP])), ); } @@ -1423,21 +1433,21 @@ public function testAdvancedGroups() [ new GroupsUser( 'John Manager friend 1', - new GroupsUser('John Manager friend 1 manager') + new GroupsUser('John Manager friend 1 manager'), ), new GroupsUser('John Manager friend 2'), - ] + ], ), [ new GroupsUser( 'John friend 1', - new GroupsUser('John friend 1 manager') + new GroupsUser('John friend 1 manager'), ), new GroupsUser( 'John friend 2', - new GroupsUser('John friend 2 manager') + new GroupsUser('John friend 2 manager'), ), - ] + ], ); self::assertEquals( @@ -1460,8 +1470,8 @@ public function testAdvancedGroups() 'manager_group', 'nickname_group', ], - ]) - ) + ]), + ), ); } @@ -1490,17 +1500,17 @@ public function testVirtualVersions() self::assertEquals( static::getContent('virtual_properties_low'), - $serializer->serialize(new ObjectWithVersionedVirtualProperties(), $this->getFormat(), SerializationContext::create()->setVersion('2')) + $serializer->serialize(new ObjectWithVersionedVirtualProperties(), $this->getFormat(), SerializationContext::create()->setVersion('2')), ); self::assertEquals( static::getContent('virtual_properties_all'), - $serializer->serialize(new ObjectWithVersionedVirtualProperties(), $this->getFormat(), SerializationContext::create()->setVersion('7')) + $serializer->serialize(new ObjectWithVersionedVirtualProperties(), $this->getFormat(), SerializationContext::create()->setVersion('7')), ); self::assertEquals( static::getContent('virtual_properties_high'), - $serializer->serialize(new ObjectWithVersionedVirtualProperties(), $this->getFormat(), SerializationContext::create()->setVersion('9')) + $serializer->serialize(new ObjectWithVersionedVirtualProperties(), $this->getFormat(), SerializationContext::create()->setVersion('9')), ); } @@ -1523,10 +1533,6 @@ public function testCustomHandler() public function testTypedProperties() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', __METHOD__)); - } - $builder = SerializerBuilder::create($this->handlerRegistry, $this->dispatcher); $builder->includeInterfaceMetadata(true); $this->serializer = $builder->build(); @@ -1580,10 +1586,6 @@ public function testConstructorPromotionWithDefaultValues() public function testUninitializedTypedProperties() { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped(sprintf('%s requires PHP 7.4', __METHOD__)); - } - $builder = SerializerBuilder::create($this->handlerRegistry, $this->dispatcher); $builder->includeInterfaceMetadata(true); $this->serializer = $builder->build(); @@ -1605,6 +1607,7 @@ public function testUninitializedTypedProperties() /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testCustomHandlerVisitingNull() { $handler = static function ($visitor, $attachment, array $type, Context $context) { @@ -1628,25 +1631,19 @@ public function testObjectWithEmptyHash() self::assertEquals(static::getContent('hash_empty'), $this->serializer->serialize(new ObjectWithEmptyHash(), $this->getFormat())); } - /** - * @group null - */ public function testSerializeObjectWhenNull() { self::assertEquals( static::getContent('object_when_null'), - $this->serialize(new Comment(null, 'foo'), SerializationContext::create()->setSerializeNull(false)) + $this->serialize(new Comment(null, 'foo'), SerializationContext::create()->setSerializeNull(false)), ); self::assertEquals( static::getContent('object_when_null_and_serialized'), - $this->serialize(new Comment(null, 'foo'), SerializationContext::create()->setSerializeNull(true)) + $this->serialize(new Comment(null, 'foo'), SerializationContext::create()->setSerializeNull(true)), ); } - /** - * @group polymorphic - */ public function testPolymorphicObjectsWithGroup() { $context = SerializationContext::create(); @@ -1654,7 +1651,7 @@ public function testPolymorphicObjectsWithGroup() self::assertEquals( static::getContent('car'), - $this->serialize(new DiscriminatorGroupCar(5), $context) + $this->serialize(new DiscriminatorGroupCar(5), $context), ); } @@ -1676,31 +1673,29 @@ public static function getDiscrimatorObjectsSamples(): array * * @dataProvider getDiscrimatorObjectsSamples */ + #[DataProvider('getDiscrimatorObjectsSamples')] public function testDiscrimatorObjects($data, $contentId) { $context = SerializationContext::create()->setGroups(['entity.identification']); self::assertEquals( static::getContent($contentId), - $this->serialize($data, $context) + $this->serialize($data, $context), ); } - /** - * @group polymorphic - */ public function testPolymorphicObjects() { self::assertEquals( static::getContent('car'), - $this->serialize(new Car(5)) + $this->serialize(new Car(5)), ); self::assertEquals( static::getContent('post'), - $this->serialize(new Post('Post Title')) + $this->serialize(new Post('Post Title')), ); self::assertEquals( static::getContent('image_post'), - $this->serialize(new ImagePost('Image Post Title')) + $this->serialize(new ImagePost('Image Post Title')), ); if ($this->hasDeserializer()) { @@ -1708,67 +1703,64 @@ public function testPolymorphicObjects() new Car(5), $this->deserialize( static::getContent('car'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\Car' + Car::class, ), - 'Class is resolved correctly when concrete sub-class is used.' + 'Class is resolved correctly when concrete sub-class is used.', ); self::assertEquals( new Car(5), $this->deserialize( static::getContent('car'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle' + Vehicle::class, ), - 'Class is resolved correctly when least supertype is used.' + 'Class is resolved correctly when least supertype is used.', ); self::assertEquals( new Car(5), $this->deserialize( static::getContent('car_without_type'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\Car' + Car::class, ), - 'Class is resolved correctly when concrete sub-class is used and no type is defined.' + 'Class is resolved correctly when concrete sub-class is used and no type is defined.', ); self::assertEquals( new Post('Post Title'), $this->deserialize( static::getContent('post'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\Post' + Post::class, ), - 'Class is resolved correctly when parent class is used and type is set.' + 'Class is resolved correctly when parent class is used and type is set.', ); self::assertEquals( new ImagePost('Image Post Title'), $this->deserialize( static::getContent('image_post'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\Post' + Post::class, ), - 'Class is resolved correctly when least supertype is used.' + 'Class is resolved correctly when least supertype is used.', ); self::assertEquals( new ImagePost('Image Post Title'), $this->deserialize( static::getContent('image_post'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost' + ImagePost::class, ), - 'Class is resolved correctly when concrete sub-class is used and no type is defined.' + 'Class is resolved correctly when concrete sub-class is used and no type is defined.', ); } } - /** - * @group polymorphic - */ public function testNestedPolymorphicObjects() { $garage = new Garage([new Car(3), new Moped(1)]); self::assertEquals( static::getContent('garage'), - $this->serialize($garage) + $this->serialize($garage), ); if ($this->hasDeserializer()) { @@ -1776,21 +1768,18 @@ public function testNestedPolymorphicObjects() $garage, $this->deserialize( static::getContent('garage'), - 'JMS\Serializer\Tests\Fixtures\Garage' - ) + Garage::class, + ), ); } } - /** - * @group polymorphic - */ public function testNestedPolymorphicInterfaces() { $garage = new VehicleInterfaceGarage([new Car(3), new Moped(1)]); self::assertEquals( static::getContent('garage'), - $this->serialize($garage) + $this->serialize($garage), ); if ($this->hasDeserializer()) { @@ -1798,15 +1787,12 @@ public function testNestedPolymorphicInterfaces() $garage, $this->deserialize( static::getContent('garage'), - 'JMS\Serializer\Tests\Fixtures\VehicleInterfaceGarage' - ) + VehicleInterfaceGarage::class, + ), ); } } - /** - * @group polymorphic - */ public function testPolymorphicObjectsInvalidDeserialization() { $this->expectException(\LogicException::class); @@ -1817,7 +1803,7 @@ public function testPolymorphicObjectsInvalidDeserialization() $this->deserialize( static::getContent('car_without_type'), - 'JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle' + Vehicle::class, ); } @@ -1835,7 +1821,7 @@ public function testDepthExclusionStrategy() ]), ]), ]), - ]) + ]), ); self::assertEquals(static::getContent('tree'), $this->serializer->serialize($data, $this->getFormat(), $context)); @@ -1892,7 +1878,7 @@ public function testDeserializingIntoExistingObject() static::getContent('order'), get_class($order), $this->getFormat(), - $context + $context, ); self::assertSame($order, $deseralizedOrder); @@ -1909,6 +1895,7 @@ public function testObjectWithNullableArrays() /** * @dataProvider getSerializeNullCases */ + #[DataProvider('getSerializeNullCases')] public function testSerializeNullArrayObjectWithExclusionStrategy(bool $serializeNull) { $arr = [ @@ -1921,7 +1908,7 @@ public function testSerializeNullArrayObjectWithExclusionStrategy(bool $serializ $serializationContext->addExclusionStrategy(new AlwaysExcludeExclusionStrategy()); self::assertEquals( static::getContent('array_objects_nullable'), - $this->serializer->serialize($arr, $this->getFormat(), $serializationContext) + $this->serializer->serialize($arr, $this->getFormat(), $serializationContext), ); } @@ -1937,7 +1924,7 @@ static function ($visitor, $data) use (&$invoked) { self::assertEquals('foo', $data); return null; - } + }, ); $this->serializer->serialize('foo', $this->getFormat(), null, 'Virtual'); @@ -1961,6 +1948,7 @@ public static function getFirstClassListCollectionsValues() * * @dataProvider getFirstClassListCollectionsValues */ + #[DataProvider('getFirstClassListCollectionsValues')] public function testFirstClassListCollections($items, $expected, ?FirstClassListCollection $expectedDeserializatrion = null) { $collection = new FirstClassListCollection($items); @@ -1968,7 +1956,7 @@ public function testFirstClassListCollections($items, $expected, ?FirstClassList self::assertSame($expected, $this->serialize($collection)); self::assertEquals( $expectedDeserializatrion ?: $collection, - $this->deserialize($expected, get_class($collection)) + $this->deserialize($expected, get_class($collection)), ); } @@ -2026,7 +2014,7 @@ public function testIterable(): void self::assertEquals( new ObjectWithIterable(Functions::iterableToArray($generator())), - $this->deserialize(static::getContent('iterable'), get_class($withIterable)) + $this->deserialize(static::getContent('iterable'), get_class($withIterable)), ); } @@ -2045,7 +2033,7 @@ public function testGenerator(): void self::assertEquals( $withGenerator, - $this->deserialize(static::getContent('generator'), get_class($withGenerator)) + $this->deserialize(static::getContent('generator'), get_class($withGenerator)), ); } @@ -2064,7 +2052,7 @@ public function testIterator(): void self::assertEquals( $withIterator, - $this->deserialize(static::getContent('iterator'), get_class($withIterator)) + $this->deserialize(static::getContent('iterator'), get_class($withIterator)), ); } @@ -2083,7 +2071,7 @@ public function testArrayIterator(): void self::assertEquals( $withArrayIterator, - $this->deserialize(static::getContent('iterator'), get_class($withArrayIterator)) + $this->deserialize(static::getContent('iterator'), get_class($withArrayIterator)), ); } @@ -2132,7 +2120,7 @@ protected function setUp(): void $this->getFormat(), static function (SerializationVisitorInterface $visitor, $object, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($object), $type); - } + }, ); $this->handlerRegistry->registerHandler( GraphNavigatorInterface::DIRECTION_DESERIALIZATION, @@ -2143,7 +2131,7 @@ static function (DeserializationVisitorInterface $visitor, $data, $type, Context 'name' => 'array', 'params' => [ ['name' => 'integer', 'params' => []], - ['name' => 'JMS\Serializer\Tests\Fixtures\Author', 'params' => []], + ['name' => Author::class, 'params' => []], ], ]; @@ -2154,7 +2142,7 @@ static function (DeserializationVisitorInterface $visitor, $data, $type, Context } return $list; - } + }, ); $this->dispatcher = new EventDispatcher(); diff --git a/tests/Serializer/ContextTest.php b/tests/Serializer/ContextTest.php index b70227985..c5fe9078f 100644 --- a/tests/Serializer/ContextTest.php +++ b/tests/Serializer/ContextTest.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\Exception\LogicException; +use JMS\Serializer\Exclusion\ExclusionStrategyInterface; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; @@ -18,6 +19,7 @@ use JMS\Serializer\Tests\Fixtures\VersionedObject; use JMS\Serializer\VisitorInterface; use Metadata\MetadataFactoryInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ContextTest extends TestCase @@ -32,7 +34,7 @@ public function testSerializationContextPathAndDepth() $self = $this; - $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); + $exclusionStrategy = $this->getMockBuilder(ExclusionStrategyInterface::class)->getMock(); $exclusionStrategy->expects($this->any()) ->method('shouldSkipClass') ->with($this->anything(), $this->callback(static function (SerializationContext $context) use ($self, $objects) { @@ -40,7 +42,7 @@ public function testSerializationContextPathAndDepth() if ($context->getObject() === $objects[0]) { $expectedDepth = 1; - $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node'; + $expectedPath = Node::class; } elseif ($context->getObject() === $objects[1]) { $expectedDepth = 2; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; @@ -57,7 +59,7 @@ public function testSerializationContextPathAndDepth() return true; })) - ->will($this->returnValue(false)); + ->willReturn(false); $exclusionStrategy->expects($this->any()) ->method('shouldSkipProperty') @@ -66,7 +68,7 @@ public function testSerializationContextPathAndDepth() if ($context->getObject() === $objects[0]) { $expectedDepth = 1; - $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node'; + $expectedPath = Node::class; } elseif ($context->getObject() === $objects[1]) { $expectedDepth = 2; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; @@ -83,7 +85,7 @@ public function testSerializationContextPathAndDepth() return true; })) - ->will($this->returnValue(false)); + ->willReturn(false); $serializer = SerializerBuilder::create()->build(); @@ -97,10 +99,10 @@ public function testSerializationMetadataStack() ]); $self = $this; - $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); - $exclusionStrategy->expects($this->any()) + $exclusionStrategy = $this->getMockBuilder(ExclusionStrategyInterface::class)->getMock(); + $exclusionStrategy ->method('shouldSkipClass') - ->will($this->returnCallback(static function (ClassMetadata $classMetadata, SerializationContext $context) use ($self, $object, $child) { + ->willReturnCallback(static function (ClassMetadata $classMetadata, SerializationContext $context) use ($self, $object, $child) { $stack = $context->getMetadataStack(); if ($object === $context->getObject()) { @@ -109,32 +111,32 @@ public function testSerializationMetadataStack() if ($child === $context->getObject()) { $self->assertEquals(2, $stack->count()); - $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[1]->name); + $self->assertEquals(Node::class, $stack[1]->name); $self->assertEquals('children', $stack[0]->name); } return false; - })); + }); - $exclusionStrategy->expects($this->any()) + $exclusionStrategy ->method('shouldSkipProperty') - ->will($this->returnCallback(static function (PropertyMetadata $propertyMetadata, SerializationContext $context) use ($self) { + ->willReturnCallback(static function (PropertyMetadata $propertyMetadata, SerializationContext $context) use ($self) { $stack = $context->getMetadataStack(); if ('JMS\Serializer\Tests\Fixtures\Node' === $propertyMetadata->class && 'children' === $propertyMetadata->name) { $self->assertEquals(1, $stack->count()); - $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[0]->name); + $self->assertEquals(Node::class, $stack[0]->name); } if ('JMS\Serializer\Tests\Fixtures\InlineChild' === $propertyMetadata->class) { $self->assertEquals(3, $stack->count()); - $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[2]->name); + $self->assertEquals(Node::class, $stack[2]->name); $self->assertEquals('children', $stack[1]->name); - $self->assertEquals('JMS\Serializer\Tests\Fixtures\InlineChild', $stack[0]->name); + $self->assertEquals(InlineChild::class, $stack[0]->name); } return false; - })); + }); $serializer = SerializerBuilder::create()->build(); $serializer->serialize($object, 'json', SerializationContext::create()->addExclusionStrategy($exclusionStrategy)); @@ -153,6 +155,7 @@ public static function getScalars() /** * @dataProvider getScalars */ + #[DataProvider('getScalars')] public function testCanVisitScalars($scalar) { $context = SerializationContext::create(); diff --git a/tests/Serializer/Doctrine/IntegrationTest.php b/tests/Serializer/Doctrine/IntegrationTest.php index 579e52b3b..fcee0228a 100644 --- a/tests/Serializer/Doctrine/IntegrationTest.php +++ b/tests/Serializer/Doctrine/IntegrationTest.php @@ -11,6 +11,7 @@ use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; +use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Doctrine\ORM\ORMException; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Persistence\AbstractManagerRegistry; @@ -67,9 +68,10 @@ public function testDiscriminatorIsInferredFromDoctrine() $teacher = new Teacher(); $class = new Clazz($teacher, [$student1, $student2]); + $em->persist($teacher); + $em->flush(); $em->persist($student1); $em->persist($student2); - $em->persist($teacher); $em->persist($class); $em->flush(); $em->clear(); @@ -98,7 +100,7 @@ static function ($id) use ($connection, $entityManager) { default: throw new \RuntimeException(sprintf('Unknown service id "%s".', $id)); } - } + }, ); $this->serializer = SerializerBuilder::create() @@ -107,7 +109,7 @@ static function (array $metadataDirs, Reader $annotationReader) use ($registry) $defaultFactory = new DefaultDriverFactory(new IdenticalPropertyNamingStrategy()); return new DoctrineTypeDriver($defaultFactory->createDriver($metadataDirs, $annotationReader), $registry); - } + }, )) ->build(); @@ -134,14 +136,23 @@ private function createConnection() private function createEntityManager(Connection $con) { $cfg = new Configuration(); - $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [ - __DIR__ . '/../../Fixtures/Doctrine/SingleTableInheritance', - ])); + + if (PHP_VERSION_ID >= 80000 && class_exists(AttributeDriver::class)) { + $cfg->setMetadataDriverImpl(new AttributeDriver([ + __DIR__ . '/../../Fixtures/Doctrine/SingleTableInheritance', + ])); + AnnotationReader::addGlobalIgnoredNamespace('Doctrine\ORM\Mapping'); + } else { + $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [ + __DIR__ . '/../../Fixtures/Doctrine/SingleTableInheritance', + ])); + } + $cfg->setAutoGenerateProxyClasses(true); $cfg->setProxyNamespace('JMS\Serializer\DoctrineProxy'); $cfg->setProxyDir(sys_get_temp_dir() . '/serializer-test-proxies'); - return EntityManager::create($con, $cfg); + return new EntityManager($con, $cfg); } } diff --git a/tests/Serializer/Doctrine/ObjectConstructorTest.php b/tests/Serializer/Doctrine/ObjectConstructorTest.php index f32d526c5..fad75ccaf 100644 --- a/tests/Serializer/Doctrine/ObjectConstructorTest.php +++ b/tests/Serializer/Doctrine/ObjectConstructorTest.php @@ -13,12 +13,12 @@ use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; +use Doctrine\ORM\Mapping\Driver\AttributeDriver; use Doctrine\ORM\Mapping\Driver\XmlDriver; use Doctrine\ORM\ORMException; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\ORM\UnitOfWork; -use Doctrine\ORM\Version as ORMVersion; use Doctrine\Persistence\AbstractManagerRegistry; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata; @@ -54,6 +54,7 @@ use LogicException; use Metadata\Driver\AdvancedDriverInterface; use Metadata\MetadataFactoryInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use ReflectionClass; use RuntimeException; @@ -272,7 +273,7 @@ public function testNamingForIdentifierColumnIsConsidered() self::assertSame( $em->getUnitOfWork()->getEntityState($serverDeserialized), - UnitOfWork::STATE_MANAGED + UnitOfWork::STATE_MANAGED, ); } @@ -305,7 +306,8 @@ public static function dataProviderPersistendCollectionIsNotReplaced(): array /** * @dataProvider dataProviderPersistendCollectionIsNotReplaced */ - public function testPersistendCollectionIsNotReplaced(string $data, string $type): void + #[DataProvider('dataProviderPersistendCollectionIsNotReplaced')] + public function testPersistendCollectionIsNotReplaced(string $serializedData, string $type): void { $serializer = $this->createSerializerWithDoctrineObjectConstructor(); @@ -322,12 +324,12 @@ public function testPersistendCollectionIsNotReplaced(string $data, string $type $em->flush(); $em->clear(); - $smartPhoneDeserialized = $serializer->deserialize($data, SmartPhone::class, $type); + $smartPhoneDeserialized = $serializer->deserialize($serializedData, SmartPhone::class, $type); self::assertInstanceOf(SmartPhone::class, $smartPhoneDeserialized); self::assertSame( $em->getUnitOfWork()->getEntityState($smartPhoneDeserialized), - UnitOfWork::STATE_MANAGED + UnitOfWork::STATE_MANAGED, ); self::assertInstanceOf(PersistentCollection::class, $smartPhoneDeserialized->getAppsRaw()); @@ -337,14 +339,14 @@ public function testPersistendCollectionIsNotReplaced(string $data, string $type self::assertCount( 1, $smartPhoneDeserialized->getApps( - $criteria - ) + $criteria, + ), ); $firstApp = $smartPhoneDeserialized->getApps()->first(); self::assertSame( $em->getUnitOfWork()->getEntityState($firstApp), - UnitOfWork::STATE_MANAGED + UnitOfWork::STATE_MANAGED, ); $em->flush(); @@ -358,10 +360,6 @@ public function testPersistendCollectionIsNotReplaced(string $data, string $type public function testFallbackOnEmbeddableClassWithXmlDriver() { - if (ORMVersion::compare('2.5') >= 0) { - $this->markTestSkipped('Not using Doctrine ORM >= 2.5 with Embedded entities'); - } - $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $fallback->expects($this->once())->method('construct'); @@ -380,7 +378,7 @@ static function ($id) use ($connection, $entityManager) { default: throw new RuntimeException(sprintf('Unknown service id "%s".', $id)); } - } + }, ); $type = ['name' => BlogPostSeo::class, 'params' => []]; @@ -392,10 +390,6 @@ static function ($id) use ($connection, $entityManager) { public function testFallbackOnEmbeddableClassWithXmlDriverAndXmlData() { - if (ORMVersion::compare('2.5') >= 0) { - $this->markTestSkipped('Not using Doctrine ORM >= 2.5 with Embedded entities'); - } - $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $fallback->expects($this->once())->method('construct'); @@ -414,7 +408,7 @@ static function ($id) use ($connection, $entityManager) { default: throw new RuntimeException(sprintf('Unknown service id "%s".', $id)); } - } + }, ); $type = ['name' => BlogPostSeo::class, 'params' => []]; @@ -479,8 +473,7 @@ public function testArrayKeyExistsOnObject(): void protected function setUp(): void { $this->visitor = $this->getMockBuilder(DeserializationVisitorInterface::class)->getMock(); - $this->context = $this->getMockBuilder('JMS\Serializer\DeserializationContext')->getMock(); - + $this->context = $this->getMockBuilder(DeserializationContext::class)->getMock(); $connection = $this->createConnection(); $entityManager = $this->createEntityManager($connection); @@ -496,7 +489,7 @@ static function ($id) use ($connection, $entityManager) { default: throw new RuntimeException(sprintf('Unknown service id "%s".', $id)); } - } + }, ); $this->driver = &$driver; @@ -506,7 +499,7 @@ static function (array $metadataDirs, Reader $annotationReader) use ($registry, $defaultFactory = new DefaultDriverFactory(new IdenticalPropertyNamingStrategy()); return $driver = new DoctrineTypeDriver($defaultFactory->createDriver($metadataDirs, $annotationReader), $registry); - } + }, )) ->build(); @@ -534,18 +527,28 @@ private function createEntityManager(Connection $con, ?Configuration $cfg = null { if (!$cfg) { $cfg = new Configuration(); - $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [ - __DIR__ . '/../../Fixtures/Doctrine/Entity', - __DIR__ . '/../../Fixtures/Doctrine/IdentityFields', - __DIR__ . '/../../Fixtures/Doctrine/PersistendCollection', - ])); + + if (PHP_VERSION_ID >= 80000 && class_exists(AttributeDriver::class)) { + AnnotationReader::addGlobalIgnoredNamespace('Doctrine\ORM\Mapping'); + $cfg->setMetadataDriverImpl(new AttributeDriver([ + __DIR__ . '/../../Fixtures/Doctrine/Entity', + __DIR__ . '/../../Fixtures/Doctrine/IdentityFields', + __DIR__ . '/../../Fixtures/Doctrine/PersistendCollection', + ])); + } else { + $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [ + __DIR__ . '/../../Fixtures/Doctrine/Entity', + __DIR__ . '/../../Fixtures/Doctrine/IdentityFields', + __DIR__ . '/../../Fixtures/Doctrine/PersistendCollection', + ])); + } } $cfg->setAutoGenerateProxyClasses(true); $cfg->setProxyNamespace('JMS\Serializer\DoctrineProxy'); $cfg->setProxyDir(sys_get_temp_dir() . '/serializer-test-proxies'); - return EntityManager::create($con, $cfg); + return new EntityManager($con, $cfg); } /** @@ -573,16 +576,16 @@ private function createSerializerWithDoctrineObjectConstructor() new DoctrineObjectConstructor( $this->registry, new UnserializeObjectConstructor(), - DoctrineObjectConstructor::ON_MISSING_FALLBACK - ) + DoctrineObjectConstructor::ON_MISSING_FALLBACK, + ), ) ->addDefaultHandlers() ->configureHandlers(function (HandlerRegistryInterface $handlerRegistry) { $handlerRegistry->registerSubscribingHandler( new ArrayCollectionHandler( true, - $this->registry - ) + $this->registry, + ), ); }) ->build(); diff --git a/tests/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriberTest.php b/tests/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriberTest.php index d318a421b..68f9cf020 100644 --- a/tests/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriberTest.php +++ b/tests/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriberTest.php @@ -80,7 +80,7 @@ public function testValidationIsOnlyPerformedOnRootObject(): void '{"authors":[{"full_name":"foo"},{"full_name":"bar"}]}', AuthorList::class, 'json', - DeserializationContext::create()->setAttribute('validation_groups', ['Foo']) + DeserializationContext::create()->setAttribute('validation_groups', ['Foo']), ); self::assertCount(2, $list); diff --git a/tests/Serializer/GraphNavigatorTest.php b/tests/Serializer/GraphNavigatorTest.php index a06c07f94..7b8de3708 100644 --- a/tests/Serializer/GraphNavigatorTest.php +++ b/tests/Serializer/GraphNavigatorTest.php @@ -21,12 +21,15 @@ use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\Handler\SubscribingHandlerInterface; use JMS\Serializer\Metadata\Driver\AnnotationDriver; +use JMS\Serializer\Metadata\Driver\NullDriver; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; use JMS\Serializer\SerializationContext; use JMS\Serializer\Visitor\DeserializationVisitorInterface; use JMS\Serializer\Visitor\SerializationVisitorInterface; use JMS\Serializer\VisitorInterface; +use Metadata\Driver\DriverChain; use Metadata\MetadataFactory; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; class GraphNavigatorTest extends TestCase @@ -58,29 +61,29 @@ public function testNavigatorPassesInstanceOnSerialization() $metadata = $this->metadataFactory->getMetadataForClass(get_class($object)); $self = $this; - $this->context = $this->getMockBuilder(SerializationContext::class)->getMock(); + $this->context = $this->createMock(SerializationContext::class); $context = $this->context; - $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); + $exclusionStrategy = $this->createMock(ExclusionStrategyInterface::class); $exclusionStrategy->expects($this->once()) ->method('shouldSkipClass') - ->will($this->returnCallback(static function ($passedMetadata, $passedContext) use ($metadata, $context, $self) { + ->willReturnCallback(static function ($passedMetadata, $passedContext) use ($metadata, $context, $self) { $self->assertSame($metadata, $passedMetadata); $self->assertSame($context, $passedContext); return false; - })); + }); $exclusionStrategy->expects($this->once()) ->method('shouldSkipProperty') - ->will($this->returnCallback(static function ($propertyMetadata, $passedContext) use ($context, $metadata, $self) { + ->willReturnCallback(static function ($propertyMetadata, $passedContext) use ($context, $metadata, $self) { $self->assertSame($metadata->propertyMetadata['foo'], $propertyMetadata); $self->assertSame($context, $passedContext); return false; - })); + }); $this->context->expects($this->once()) ->method('getExclusionStrategy') - ->will($this->returnValue($exclusionStrategy)); + ->willReturn($exclusionStrategy); $navigator = new SerializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->accessor, $this->dispatcher); $navigator->initialize($this->serializationVisitor, $this->context); @@ -110,7 +113,7 @@ public function testNavigatorPassesNullOnDeserialization() $this->context->expects($this->once()) ->method('getExclusionStrategy') - ->will($this->returnValue($exclusionStrategy)); + ->willReturn($exclusionStrategy); $navigator = new DeserializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->accessor, $this->dispatcher); $navigator->initialize($this->deserializationVisitor, $this->context); @@ -120,6 +123,7 @@ public function testNavigatorPassesNullOnDeserialization() /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testNavigatorChangeTypeOnSerialization() { $object = new SerializableClass(); @@ -182,6 +186,7 @@ public function testHandlerIsExecutedOnSerialization() /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testFilterableHandlerIsSkippedOnSerialization() { $object = new SerializableClass(); @@ -215,6 +220,7 @@ public function testFilterableHandlerIsNotSkippedOnSerialization() /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testNavigatorDoesNotCrashWhenObjectConstructorReturnsNull() { $objectConstructor = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); @@ -243,7 +249,14 @@ protected function setUp(): void $this->handlerRegistry = new HandlerRegistry(); $this->objectConstructor = new UnserializeObjectConstructor(); - $this->metadataFactory = new MetadataFactory(new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy())); + $namingStrategy = new IdenticalPropertyNamingStrategy(); + + $driver = new DriverChain([ + new AnnotationDriver(new AnnotationReader(), $namingStrategy), + new NullDriver($namingStrategy), + ]); + + $this->metadataFactory = new MetadataFactory($driver); $this->serializationNavigator = new SerializationGraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->accessor, $this->dispatcher); $this->serializationNavigator->initialize($this->serializationVisitor, $this->context); diff --git a/tests/Serializer/JsonSerializationTest.php b/tests/Serializer/JsonSerializationTest.php index 12cebabd3..73f8ede8f 100644 --- a/tests/Serializer/JsonSerializationTest.php +++ b/tests/Serializer/JsonSerializationTest.php @@ -17,10 +17,12 @@ use JMS\Serializer\Tests\Fixtures\FirstClassMapCollection; use JMS\Serializer\Tests\Fixtures\ObjectWithEmptyArrayAndHash; use JMS\Serializer\Tests\Fixtures\ObjectWithInlineArray; +use JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty; use JMS\Serializer\Tests\Fixtures\Tag; use JMS\Serializer\Tests\Fixtures\TypedProperties\UnionTypedProperties; use JMS\Serializer\Visitor\Factory\JsonSerializationVisitorFactory; use JMS\Serializer\Visitor\SerializationVisitorInterface; +use PHPUnit\Framework\Attributes\DataProvider; class JsonSerializationTest extends BaseSerializationTestCase { @@ -143,7 +145,7 @@ protected static function getContent($key) $outputs['custom_datetimeinterface'] = '{"custom":"2021-09-07"}'; $outputs['data_integer'] = '{"data":10000}'; $outputs['uid'] = '"66b3177c-e03b-4a22-9dee-ddd7d37a04d5"'; - $outputs['object_with_enums'] = '{"ordinary":"Clubs","backed":"C","ordinary_array":["Clubs","Spades"],"backed_array":["C","H"],"ordinary_auto_detect":"Clubs","backed_auto_detect":"C","backed_int_auto_detect":3,"backed_int":3,"backed_name":"C","backed_int_forced_str":3}'; + $outputs['object_with_enums'] = '{"ordinary":"Clubs","backed_value":"C","backed_without_param":"C","ordinary_array":["Clubs","Spades"],"backed_array":["C","H"],"backed_array_without_param":["C","H"],"ordinary_auto_detect":"Clubs","backed_auto_detect":"C","backed_int_auto_detect":3,"backed_int":3,"backed_name":"C","backed_int_forced_str":3}'; $outputs['object_with_autodetect_enums'] = '{"ordinary_array_auto_detect":["Clubs","Spades"],"backed_array_auto_detect":["C","H"],"mixed_array_auto_detect":["Clubs","H"]}'; $outputs['object_with_enums_disabled'] = '{"ordinary_array_auto_detect":[{"name":"Clubs"},{"name":"Spades"}],"backed_array_auto_detect":[{"name":"Clubs","value":"C"},{"name":"Hearts","value":"H"}],"mixed_array_auto_detect":[{"name":"Clubs"},{"name":"Hearts","value":"H"}]}'; } @@ -172,19 +174,17 @@ public static function getFirstClassMapCollectionsValues() } /** - * @param array $items - * @param array $expected - * * @dataProvider getFirstClassMapCollectionsValues */ - public function testFirstClassMapCollections($items, $expected): void + #[DataProvider('getFirstClassMapCollectionsValues')] + public function testFirstClassMapCollections(array $items, string $expected): void { $collection = new FirstClassMapCollection($items); self::assertSame($expected, $this->serialize($collection)); self::assertEquals( $collection, - $this->deserialize($expected, get_class($collection)) + $this->deserialize($expected, get_class($collection)), ); } @@ -192,21 +192,21 @@ public function testAddLinksToOutput() { $this->dispatcher->addListener('serializer.post_serialize', static function (Event $event) { self::assertFalse($event->getVisitor()->hasData('_links')); - }, 'JMS\Serializer\Tests\Fixtures\Author', 'json'); + }, Author::class, 'json'); $this->dispatcher->addSubscriber(new LinkAddingSubscriber()); $this->dispatcher->addListener('serializer.post_serialize', static function (Event $event) { self::assertTrue($event->getVisitor()->hasData('_links')); - }, 'JMS\Serializer\Tests\Fixtures\Author', 'json'); + }, Author::class, 'json'); $this->handlerRegistry->registerHandler( GraphNavigatorInterface::DIRECTION_SERIALIZATION, - 'JMS\Serializer\Tests\Fixtures\AuthorList', + AuthorList::class, 'json', static function (SerializationVisitorInterface $visitor, AuthorList $data, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($data), $type); - } + }, ); $list = new AuthorList(); @@ -221,11 +221,11 @@ public function testReplaceNameInOutput() $this->dispatcher->addSubscriber(new ReplaceNameSubscriber()); $this->handlerRegistry->registerHandler( GraphNavigatorInterface::DIRECTION_SERIALIZATION, - 'JMS\Serializer\Tests\Fixtures\AuthorList', + AuthorList::class, 'json', static function (SerializationVisitorInterface $visitor, AuthorList $data, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($data), $type); - } + }, ); $list = new AuthorList(); @@ -242,15 +242,15 @@ public function testDeserializingObjectWithObjectPropertyWithNoArrayToObject() $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Invalid data "baz" (string), expected "JMS\Serializer\Tests\Fixtures\Author".'); - $this->deserialize($content, 'JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty'); + $this->deserialize($content, ObjectWithObjectProperty::class); } public function testDeserializingObjectWithObjectProperty() { $content = self::getContent('object_with_object_property'); - $object = $this->deserialize($content, 'JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty'); + $object = $this->deserialize($content, ObjectWithObjectProperty::class); self::assertEquals('bar', $object->getFoo()); - self::assertInstanceOf('JMS\Serializer\Tests\Fixtures\Author', $object->getAuthor()); + self::assertInstanceOf(Author::class, $object->getAuthor()); self::assertEquals('baz', $object->getAuthor()->getName()); } @@ -279,29 +279,24 @@ public static function getPrimitiveTypes() /** * @dataProvider getPrimitiveTypes */ - public function testPrimitiveTypes($primitiveType, $data) + #[DataProvider('getPrimitiveTypes')] + public function testPrimitiveTypes(string $type, $data) { $navigator = $this->getMockBuilder(GraphNavigatorInterface::class)->getMock(); $factory = new JsonSerializationVisitorFactory(); $visitor = $factory->getVisitor(); $visitor->setNavigator($navigator); - $functionToCall = 'visit' . ucfirst($primitiveType); + $functionToCall = 'visit' . ucfirst($type); $result = $visitor->$functionToCall($data, [], $this->getMockBuilder(SerializationContext::class)->getMock()); - self::{'assertIs' . (['boolean' => 'bool', 'integer' => 'int', 'double' => 'float'][$primitiveType] ?? $primitiveType)}($result); + self::{'assertIs' . (['boolean' => 'bool', 'integer' => 'int', 'double' => 'float'][$type] ?? $type)}($result); } - /** - * @group empty-object - */ public function testSerializeEmptyObject() { self::assertEquals('{}', $this->serialize(new Author(null))); } - /** - * @group encoding - */ public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOff() { ini_set('display_errors', '1'); @@ -312,9 +307,6 @@ public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOff() $this->serialize(['foo' => 'bar', 'bar' => pack('H*', 'c32e')]); } - /** - * @group encoding - */ public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOn() { ini_set('display_errors', '0'); @@ -396,13 +388,10 @@ public static function getTypeHintedArrays() } /** - * @param array $array - * @param string $expected - * @param SerializationContext|null $context - * * @dataProvider getTypeHintedArrays */ - public function testTypeHintedArraySerialization(array $array, $expected, $context = null) + #[DataProvider('getTypeHintedArrays')] + public function testTypeHintedArraySerialization(array $array, string $expected, ?SerializationContext $context = null) { self::assertEquals($expected, $this->serialize($array, $context)); } @@ -449,13 +438,10 @@ public function testDeserializingUnionProperties() } /** - * @param array $array - * @param string $expected - * @param SerializationContext|null $context - * * @dataProvider getTypeHintedArraysAndStdClass */ - public function testTypeHintedArrayAncdtdClassSerialization(array $array, $expected, $context = null) + #[DataProvider('getTypeHintedArraysAndStdClass')] + public function testTypeHintedArrayAncdtdClassSerialization(array $array, string $expected, ?SerializationContext $context = null) { self::assertEquals($expected, $this->serialize($array, $context)); } @@ -481,7 +467,7 @@ public function onPostSerialize(ObjectEvent $event) public static function getSubscribedEvents() { return [ - ['event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => 'JMS\Serializer\Tests\Fixtures\Author'], + ['event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => Author::class], ]; } } @@ -496,7 +482,7 @@ public function onPostSerialize(Event $event) public static function getSubscribedEvents() { return [ - ['event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => 'JMS\Serializer\Tests\Fixtures\Author'], + ['event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => Author::class], ]; } } diff --git a/tests/Serializer/JsonStrictSerializationTest.php b/tests/Serializer/JsonStrictSerializationTest.php index 8bc0562bf..c0227fd28 100644 --- a/tests/Serializer/JsonStrictSerializationTest.php +++ b/tests/Serializer/JsonStrictSerializationTest.php @@ -6,6 +6,7 @@ use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Visitor\Factory\JsonDeserializationVisitorFactory; +use PHPUnit\Framework\Attributes\DataProvider; class JsonStrictSerializationTest extends JsonSerializationTest { @@ -17,12 +18,10 @@ protected function extendBuilder(SerializerBuilder $builder): void } /** - * @param array $items - * @param array $expected - * * @dataProvider getFirstClassMapCollectionsValues */ - public function testFirstClassMapCollections($items, $expected): void + #[DataProvider('getFirstClassMapCollectionsValues')] + public function testFirstClassMapCollections(array $items, string $expected): void { self::markTestIncomplete('Fixtures are broken'); } diff --git a/tests/Serializer/Naming/CamelCaseNamingStrategyTest.php b/tests/Serializer/Naming/CamelCaseNamingStrategyTest.php index 1f73c8c9c..d2f58b7af 100644 --- a/tests/Serializer/Naming/CamelCaseNamingStrategyTest.php +++ b/tests/Serializer/Naming/CamelCaseNamingStrategyTest.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Tests\Serializer\Naming; use JMS\Serializer\Naming\CamelCaseNamingStrategy; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class CamelCaseNamingStrategyTest extends TestCase @@ -20,6 +21,7 @@ public static function providePropertyNames() /** * @dataProvider providePropertyNames */ + #[DataProvider('providePropertyNames')] public function testCamelCaseNamingHandlesMultipleUppercaseLetters($propertyName, $expected) { $mockProperty = $this->getMockBuilder('JMS\Serializer\Metadata\PropertyMetadata')->disableOriginalConstructor()->getMock(); diff --git a/tests/Serializer/Naming/IdenticalPropertyNamingStrategyTest.php b/tests/Serializer/Naming/IdenticalPropertyNamingStrategyTest.php index be1f68d84..e5b39e08e 100644 --- a/tests/Serializer/Naming/IdenticalPropertyNamingStrategyTest.php +++ b/tests/Serializer/Naming/IdenticalPropertyNamingStrategyTest.php @@ -5,6 +5,7 @@ namespace JMS\Serializer\Tests\Serializer\Naming; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class IdenticalPropertyNamingStrategyTest extends TestCase @@ -21,6 +22,7 @@ public static function providePropertyNames() /** * @dataProvider providePropertyNames */ + #[DataProvider('providePropertyNames')] public function testTranslateName($propertyName) { $mockProperty = $this->getMockBuilder('JMS\Serializer\Metadata\PropertyMetadata')->disableOriginalConstructor()->getMock(); diff --git a/tests/Serializer/SerializationContextFactoryTest.php b/tests/Serializer/SerializationContextFactoryTest.php index bb2d079b3..6f12b95c3 100644 --- a/tests/Serializer/SerializationContextFactoryTest.php +++ b/tests/Serializer/SerializationContextFactoryTest.php @@ -6,6 +6,8 @@ use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Construction\UnserializeObjectConstructor; +use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface; +use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\Metadata\Driver\AnnotationDriver; @@ -42,14 +44,14 @@ protected function setUp(): void public function testSerializeUseProvidedSerializationContext() { - $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\SerializationContextFactoryInterface'); + $contextFactoryMock = $this->createMock(SerializationContextFactoryInterface::class); $context = new SerializationContext(); $context->setSerializeNull(true); $contextFactoryMock ->expects($this->once()) ->method('createSerializationContext') - ->will($this->returnValue($context)); + ->willReturn($context); $builder = SerializerBuilder::create(); $builder->setSerializationContextFactory($contextFactoryMock); @@ -62,13 +64,13 @@ public function testSerializeUseProvidedSerializationContext() public function testDeserializeUseProvidedDeserializationContext() { - $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\DeserializationContextFactoryInterface'); + $contextFactoryMock = $this->createMock(DeserializationContextFactoryInterface::class); $context = new DeserializationContext(); $contextFactoryMock ->expects($this->once()) ->method('createDeserializationContext') - ->will($this->returnValue($context)); + ->willReturn($context); $builder = SerializerBuilder::create(); $builder->setDeserializationContextFactory($contextFactoryMock); @@ -81,14 +83,14 @@ public function testDeserializeUseProvidedDeserializationContext() public function testToArrayUseProvidedSerializationContext() { - $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\SerializationContextFactoryInterface'); + $contextFactoryMock = $this->createMock(SerializationContextFactoryInterface::class); $context = new SerializationContext(); $context->setSerializeNull(true); $contextFactoryMock ->expects($this->once()) ->method('createSerializationContext') - ->will($this->returnValue($context)); + ->willReturn($context); $builder = SerializerBuilder::create(); $builder->setSerializationContextFactory($contextFactoryMock); @@ -101,13 +103,13 @@ public function testToArrayUseProvidedSerializationContext() public function testFromArrayUseProvidedDeserializationContext() { - $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\DeserializationContextFactoryInterface'); + $contextFactoryMock = $this->createMock(DeserializationContextFactoryInterface::class); $context = new DeserializationContext(); $contextFactoryMock ->expects($this->once()) ->method('createDeserializationContext') - ->will($this->returnValue($context)); + ->willReturn($context); $builder = SerializerBuilder::create(); $builder->setDeserializationContextFactory($contextFactoryMock); diff --git a/tests/Serializer/Type/ParserTest.php b/tests/Serializer/Type/ParserTest.php index 6fd9f0551..65c7d74d9 100644 --- a/tests/Serializer/Type/ParserTest.php +++ b/tests/Serializer/Type/ParserTest.php @@ -7,6 +7,7 @@ use JMS\Serializer\Type\Exception\SyntaxError; use JMS\Serializer\Type\Parser; use JMS\Serializer\Type\ParserInterface; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ParserTest extends TestCase @@ -22,11 +23,12 @@ protected function setUp(): void /** * @dataProvider validTypesProvider */ + #[DataProvider('validTypesProvider')] public function testParse(string $sourceType, array $expectedType): void { self::assertSame( $expectedType, - $this->parser->parse($sourceType) + $this->parser->parse($sourceType), ); } @@ -149,6 +151,7 @@ public static function validTypesProvider(): iterable /** * @dataProvider wrongSyntax */ + #[DataProvider('wrongSyntax')] public function testSyntaxError($value): void { $this->expectException(SyntaxError::class); diff --git a/tests/Serializer/XmlSerializationTest.php b/tests/Serializer/XmlSerializationTest.php index 7495b88c9..833a2a06f 100644 --- a/tests/Serializer/XmlSerializationTest.php +++ b/tests/Serializer/XmlSerializationTest.php @@ -48,6 +48,9 @@ use JMS\Serializer\Visitor\Factory\XmlDeserializationVisitorFactory; use JMS\Serializer\Visitor\Factory\XmlSerializationVisitorFactory; use JMS\Serializer\XmlSerializationVisitor; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\Group; class XmlSerializationTest extends BaseSerializationTestCase { @@ -63,6 +66,7 @@ public function testInvalidUsageOfXmlValue() /** * @dataProvider getXMLBooleans */ + #[DataProvider('getXMLBooleans')] public function testXMLBooleans($xmlBoolean, $boolean) { if ($this->hasDeserializer()) { @@ -85,7 +89,7 @@ public function testAccessorSetterDeserialization() collectionEntry ', - 'JMS\Serializer\Tests\Fixtures\AccessorSetter' + 'JMS\Serializer\Tests\Fixtures\AccessorSetter', ); \assert($object instanceof AccessorSetter); @@ -145,6 +149,7 @@ public function testDocumentTypesAreNotAllowed() /** * @doesNotPerformAssertions */ + #[DoesNotPerformAssertions] public function testWhitelistedDocumentTypesAreAllowed() { $xmlVisitor = new XmlDeserializationVisitorFactory(); @@ -173,7 +178,7 @@ public function testVirtualAttributes() { self::assertEquals( self::getContent('virtual_attributes'), - $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['attributes'])) + $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['attributes'])), ); } @@ -181,7 +186,7 @@ public function testVirtualValues() { self::assertEquals( self::getContent('virtual_values'), - $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['values'])) + $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['values'])), ); } @@ -189,7 +194,7 @@ public function testVirtualXmlList() { self::assertEquals( self::getContent('virtual_properties_list'), - $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['list'])) + $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['list'])), ); } @@ -197,7 +202,7 @@ public function testVirtualXmlMap() { self::assertEquals( self::getContent('virtual_properties_map'), - $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['map'])) + $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(['map'])), ); } @@ -236,11 +241,11 @@ public function testObjectWithNamespacesAndList() self::assertEquals( self::getContent('object_with_namespaces_and_list'), - $this->serialize($object, SerializationContext::create()) + $this->serialize($object, SerializationContext::create()), ); self::assertEquals( $object, - $this->deserialize(self::getContent('object_with_namespaces_and_list'), get_class($object)) + $this->deserialize(self::getContent('object_with_namespaces_and_list'), get_class($object)), ); } @@ -263,11 +268,11 @@ public function testObjectWithNamespaceAndNestedList() self::assertEquals( self::getContent('object_with_namespaces_and_nested_list'), - $this->serialize($object, SerializationContext::create()) + $this->serialize($object, SerializationContext::create()), ); self::assertEquals( $object, - $this->deserialize(self::getContent('object_with_namespaces_and_nested_list'), get_class($object)) + $this->deserialize(self::getContent('object_with_namespaces_and_nested_list'), get_class($object)), ); } @@ -304,6 +309,7 @@ public function testDeserializeTypedAndNestedArrayKeyValues() * @dataProvider getDateTime * @group datetime */ + #[DataProvider('getDateTime')] public function testDateTimeNoCData($key, $value, $type) { $builder = SerializerBuilder::create(); @@ -319,6 +325,7 @@ public function testDateTimeNoCData($key, $value, $type) * @dataProvider getDateTimeImmutable * @group datetime */ + #[DataProvider('getDateTimeImmutable')] public function testDateTimeImmutableNoCData($key, $value, $type) { $builder = SerializerBuilder::create(); @@ -358,7 +365,7 @@ public function testObjectWithOnlyNamespacesAndList() self::assertEquals( self::getContent('object_with_only_namespaces_and_list'), - $this->serialize($object, SerializationContext::create()) + $this->serialize($object, SerializationContext::create()), ); $deserialized = $this->deserialize(self::getContent('object_with_only_namespaces_and_list'), get_class($object)); @@ -425,7 +432,7 @@ static function (XmlSerializationVisitor $visitor, $data, $type, Context $contex $metadata->xmlNamespace = $classMetadata->xmlRootNamespace; $visitor->visitProperty($metadata, $author); - } + }, ); $serialized = $this->serialize($object); @@ -483,8 +490,8 @@ public function testDiscriminatorAsXmlAttribute() ObjectWithXmlAttributeDiscriminatorChild::class, $this->deserialize( $xml, - ObjectWithXmlAttributeDiscriminatorParent::class - ) + ObjectWithXmlAttributeDiscriminatorParent::class, + ), ); } @@ -496,8 +503,8 @@ public function testDiscriminatorAsNotCData() ObjectWithXmlNotCDataDiscriminatorChild::class, $this->deserialize( $xml, - ObjectWithXmlNotCDataDiscriminatorParent::class - ) + ObjectWithXmlNotCDataDiscriminatorParent::class, + ), ); } @@ -510,8 +517,8 @@ public function testDiscriminatorWithNamespace() ObjectWithXmlNamespaceDiscriminatorChild::class, $this->deserialize( $xml, - ObjectWithXmlNamespaceDiscriminatorParent::class - ) + ObjectWithXmlNamespaceDiscriminatorParent::class, + ), ); } @@ -524,8 +531,8 @@ public function testDiscriminatorAsXmlAttributeWithNamespace() ObjectWithXmlNamespaceAttributeDiscriminatorChild::class, $this->deserialize( $xml, - ObjectWithXmlNamespaceAttributeDiscriminatorParent::class - ) + ObjectWithXmlNamespaceAttributeDiscriminatorParent::class, + ), ); } @@ -577,7 +584,7 @@ public function testSerialisationWithPrecisionForFloat(): void 1.555, 1.5, 1.555, - 1.555 + 1.555, ); $result = $this->serialize($objectWithFloat, SerializationContext::create()); @@ -595,7 +602,7 @@ public function testSerialisationWithPrecisionForFloat(): void 1.6 1.560 ', - $result + $result, ); } diff --git a/tests/Serializer/xml/object_with_enums.xml b/tests/Serializer/xml/object_with_enums.xml index bba1a2b00..ab0017713 100644 --- a/tests/Serializer/xml/object_with_enums.xml +++ b/tests/Serializer/xml/object_with_enums.xml @@ -1,7 +1,8 @@ - + + @@ -10,6 +11,10 @@ + + + + 3 diff --git a/tests/SerializerBuilderTest.php b/tests/SerializerBuilderTest.php index 8551ae2c5..73fb575f9 100644 --- a/tests/SerializerBuilderTest.php +++ b/tests/SerializerBuilderTest.php @@ -4,6 +4,8 @@ namespace JMS\Serializer\Tests; +use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface; +use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Exception\UnsupportedFormatException; use JMS\Serializer\Expression\ExpressionEvaluator; @@ -16,6 +18,7 @@ use JMS\Serializer\Tests\Fixtures\PersonSecretWithVariables; use JMS\Serializer\Type\ParserInterface; use JMS\Serializer\Visitor\Factory\JsonSerializationVisitorFactory; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Constraint\FileExists; use PHPUnit\Framework\Constraint\LogicalNot; use PHPUnit\Framework\TestCase; @@ -102,7 +105,7 @@ public function testDoesNotAddOtherVisitorsWhenConfiguredExplicitly() { self::assertSame( $this->builder, - $this->builder->setSerializationVisitor('json', new JsonSerializationVisitorFactory()) + $this->builder->setSerializationVisitor('json', new JsonSerializationVisitorFactory()), ); $this->expectException(UnsupportedFormatException::class); @@ -115,35 +118,35 @@ public function testIncludeInterfaceMetadata() { self::assertFalse( $this->getIncludeInterfaces($this->builder), - 'Interface metadata are not included by default' + 'Interface metadata are not included by default', ); self::assertTrue( $this->getIncludeInterfaces($this->builder->includeInterfaceMetadata(true)), - 'Force including interface metadata' + 'Force including interface metadata', ); self::assertFalse( $this->getIncludeInterfaces($this->builder->includeInterfaceMetadata(false)), - 'Force not including interface metadata' + 'Force not including interface metadata', ); self::assertSame( $this->builder, - $this->builder->includeInterfaceMetadata(true) + $this->builder->includeInterfaceMetadata(true), ); } public function testSetSerializationContext() { - $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\SerializationContextFactoryInterface'); + $contextFactoryMock = $this->createMock(SerializationContextFactoryInterface::class); $context = new SerializationContext(); $context->setSerializeNull(true); $contextFactoryMock ->expects($this->once()) ->method('createSerializationContext') - ->will($this->returnValue($context)); + ->willReturn($context); $this->builder->setSerializationContextFactory($contextFactoryMock); @@ -156,13 +159,13 @@ public function testSetSerializationContext() public function testSetDeserializationContext() { - $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\DeserializationContextFactoryInterface'); + $contextFactoryMock = $this->createMock(DeserializationContextFactoryInterface::class); $context = new DeserializationContext(); $contextFactoryMock ->expects($this->once()) ->method('createDeserializationContext') - ->will($this->returnValue($context)); + ->willReturn($context); $this->builder->setDeserializationContextFactory($contextFactoryMock); @@ -229,6 +232,7 @@ public static function expressionFunctionProvider() * * @dataProvider expressionFunctionProvider */ + #[DataProvider('expressionFunctionProvider')] public function testExpressionEngine(ExpressionFunction $function, $json) { $language = new ExpressionLanguage(); diff --git a/tests/Twig/SerializerExtensionTest.php b/tests/Twig/SerializerExtensionTest.php index 2ef2b14af..79c729f4a 100644 --- a/tests/Twig/SerializerExtensionTest.php +++ b/tests/Twig/SerializerExtensionTest.php @@ -32,7 +32,7 @@ public function testSerialize() self::assertEquals( [new TwigFunction('serialization_context', '\JMS\Serializer\SerializationContext::create')], - $serializerExtension->getFunctions() + $serializerExtension->getFunctions(), ); } @@ -55,7 +55,7 @@ public function testSerializeWithPrefix() self::assertEquals( [new TwigFunction('foo_serialization_context', '\JMS\Serializer\SerializationContext::create')], - $serializerExtension->getFunctions() + $serializerExtension->getFunctions(), ); } @@ -80,11 +80,11 @@ public function testRuntimeSerializerExtension() self::assertEquals('jms_serializer', $serializerExtension->getName()); self::assertEquals( [new TwigFilter('serialize', [SerializerRuntimeHelper::class, 'serialize'])], - $serializerExtension->getFilters() + $serializerExtension->getFilters(), ); self::assertEquals( [new TwigFunction('serialization_context', '\JMS\Serializer\SerializationContext::create')], - $serializerExtension->getFunctions() + $serializerExtension->getFunctions(), ); } }