Skip to content

Commit

Permalink
allow positional php8 attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
goetas committed Aug 3, 2021
1 parent a07fe03 commit fee85dd
Show file tree
Hide file tree
Showing 26 changed files with 185 additions and 331 deletions.
97 changes: 50 additions & 47 deletions doc/reference/annotations.rst
Original file line number Diff line number Diff line change
@@ -1,53 +1,6 @@
Annotations
===========

PHP 8 support
-------------

JMS serializer now supports PHP 8 attributes, with a few caveats:
- To avoid BC breaks, all annotations must use named parameters.
- Due to the missing support for nested annotations, the syntax for a few annotations has changed

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(name: 'classlow', exp: 'object.getVirtualValue(1)', options: [[Until::class, ['8']]])]
#[VirtualProperty(name: 'classhigh', exp: 'object.getVirtualValue(8)', options: [[Since::class, ['6']]])]
class ObjectWithVersionedVirtualProperties
{
/**
* @Groups({"versions"})
* @VirtualProperty
* @SerializedName("low")
* @Until("8")
*/
#[Groups(groups: ['versions'])]
#[VirtualProperty]
#[SerializedName(name: 'low')]
#[Until(version: '8')]
public function getVirtualLowValue()
{
return 1;
}
...
@ExclusionPolicy
~~~~~~~~~~~~~~~~
This annotation can be defined on a class to indicate the exclusion strategy
Expand Down Expand Up @@ -902,3 +855,53 @@ Resulting XML:
<full_name><![CDATA[Foo Bar]]></full_name>
</atom:author>
</blog>
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;
}
...
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ parameters:
- '~Class Doctrine\\ODM\\MongoDB\\PersistentCollection not found~'
- '~Class Symfony\\Component\\Translation\\TranslatorInterface not found~'
- '#Instantiated class Doctrine\\Common\\Cache\\FilesystemCache not found\.#'
- '#Constructor of class JMS\\Serializer\\Annotation\\.*? has an unused parameter#'

paths:
- %currentWorkingDirectory%/src
Expand Down
12 changes: 3 additions & 9 deletions src/Annotation/AccessType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY)]
final class AccessType
{
use AnnotationUtilsTrait;

/**
* @Required
* @var string|null
Expand All @@ -21,14 +23,6 @@ final class AccessType

public function __construct(array $values = [], ?string $type = null)
{
if (array_key_exists('value', $values)) {
$type = $values['value'];
}

if (array_key_exists('type', $values)) {
$type = $values['type'];
}

$this->type = $type;
$this->loadAnnotationParameters(get_defined_vars());
}
}
17 changes: 3 additions & 14 deletions src/Annotation/Accessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#[\Attribute(\Attribute::TARGET_PROPERTY)]
final class Accessor
{
use AnnotationUtilsTrait;

/**
* @var string|null
*/
Expand All @@ -25,19 +27,6 @@ final class Accessor

public function __construct(array $values = [], ?string $getter = null, ?string $setter = null)
{
if (array_key_exists('value', $values)) {
$getter = $values['value'];
}

if (array_key_exists('getter', $values)) {
$getter = $values['getter'];
}

if (array_key_exists('setter', $values)) {
$setter = $values['setter'];
}

$this->getter = $getter;
$this->setter = $setter;
$this->loadAnnotationParameters(get_defined_vars());
}
}
18 changes: 4 additions & 14 deletions src/Annotation/AccessorOrder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#[\Attribute(\Attribute::TARGET_CLASS)]
final class AccessorOrder
{
use AnnotationUtilsTrait;
use AnnotationUtilsTrait;

/**
* @Required
* @var string|null
Expand All @@ -28,19 +31,6 @@ final class AccessorOrder

public function __construct(array $values = [], ?string $order = null, array $custom = [])
{
if (array_key_exists('value', $values)) {
$order = $values['value'];
}

if (array_key_exists('order', $values)) {
$order = $values['order'];
}

if (array_key_exists('custom', $values)) {
$custom = $values['custom'];
}

$this->order = $order;
$this->custom = $custom;
$this->loadAnnotationParameters(get_defined_vars());
}
}
40 changes: 40 additions & 0 deletions src/Annotation/AnnotationUtilsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace JMS\Serializer\Annotation;

use JMS\Serializer\Exception\InvalidArgumentException;

trait AnnotationUtilsTrait
{
private function loadAnnotationParameters(array $vars): void
{
if (!array_key_exists('values', $vars)) {
$values = [];
} elseif (!is_array($vars['values'])) {
$values = ['value' => $vars['values']];
} else {
$values = $vars['values'];
}

unset($vars['values']);

if (array_key_exists('value', $values)) {
$values[key($vars)] = $values['value'];
unset($values['value']);
}

foreach ($values as $key => $value) {
$vars[$key] = $value;
}

foreach ($vars as $key => $value) {
if (!property_exists(static::class, $key)) {
throw new InvalidArgumentException(sprintf('Unknown property "%s" on annotation "%s".', $key, static::class));
}

$this->{$key} = $value;
}
}
}
23 changes: 3 additions & 20 deletions src/Annotation/Discriminator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#[\Attribute(\Attribute::TARGET_CLASS)]
class Discriminator
{
use AnnotationUtilsTrait;

/** @var array<string> */
public $map = [];

Expand All @@ -25,25 +27,6 @@ class Discriminator

public function __construct(array $values = [], string $field = 'type', array $groups = [], array $map = [], bool $disabled = false)
{
if (array_key_exists('field', $values)) {
$field = $values['field'];
}

if (array_key_exists('groups', $values)) {
$groups = $values['groups'];
}

if (array_key_exists('map', $values)) {
$map = $values['map'];
}

if (array_key_exists('disabled', $values)) {
$disabled = $values['disabled'];
}

$this->field = $field;
$this->groups = $groups;
$this->map = $map;
$this->disabled = $disabled;
$this->loadAnnotationParameters(get_defined_vars());
}
}
12 changes: 3 additions & 9 deletions src/Annotation/Exclude.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD)]
final class Exclude
{
use AnnotationUtilsTrait;

/**
* @var string|null
*/
public $if;

public function __construct(array $values = [], ?string $if = null)
{
if (array_key_exists('value', $values)) {
$if = $values['value'];
}

if (array_key_exists('if', $values)) {
$if = $values['if'];
}

$this->if = $if;
$this->loadAnnotationParameters(get_defined_vars());
}
}
31 changes: 8 additions & 23 deletions src/Annotation/ExclusionPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,25 @@
#[\Attribute(\Attribute::TARGET_CLASS)]
final class ExclusionPolicy
{
use AnnotationUtilsTrait;
use AnnotationUtilsTrait;

public const NONE = 'NONE';
public const ALL = 'ALL';

/**
* @var string|null
*/
public $policy = null;
public $policy = 'NONE';

public function __construct(array $values = [], ?string $policy = null)
public function __construct($values = [], ?string $policy = null)
{
$value = self::NONE;

if (array_key_exists('value', $values)) {
$value = $values['value'];
}

if (array_key_exists('policy', $values)) {
$value = $values['policy'];
}
$this->loadAnnotationParameters(get_defined_vars());

if (null !== $policy) {
$value = $policy;
}

if (!\is_string($value)) {
throw new RuntimeException('Exclusion policy value must be of string type.');
}
$this->policy = strtoupper($this->policy);

$value = strtoupper($value);

if (self::NONE !== $value && self::ALL !== $value) {
if (self::NONE !== $this->policy && self::ALL !== $this->policy) {
throw new RuntimeException('Exclusion policy must either be "ALL", or "NONE".');
}

$this->policy = $value;
}
}
12 changes: 3 additions & 9 deletions src/Annotation/Expose.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]
final class Expose
{
use AnnotationUtilsTrait;

/**
* @var string|null
*/
public $if = null;

public function __construct(array $values = [], ?string $if = null)
{
if (array_key_exists('value', $values)) {
$if = $values['value'];
}

if (array_key_exists('if', $values)) {
$if = $values['if'];
}

$this->if = $if;
$this->loadAnnotationParameters(get_defined_vars());
}
}
Loading

0 comments on commit fee85dd

Please sign in to comment.