Skip to content
This repository has been archived by the owner on Feb 24, 2023. It is now read-only.

Commit

Permalink
feature #707 Add PHP 8.0 attributes support (Yoann-TYT)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 6.0.x-dev branch.

Discussion
----------

Add PHP 8.0 attributes support

# Add PHP 8.0 attributes support

## Using PHP attributes if we start a new project on PHP 8.0

Instead of using classic doctrine annotations
```php
    /**
     * @Cache(public=true, maxage="0", smaxage="1 month")
     * @IsGranted("ROLE_ADMIN")
     */
    public function foo() { }
```

We should use attributes PHP 8.0
```php
    #[Cache(public: true, maxage: '0', smaxage: '1 month')]
    #[IsGranted('ROLE_ADMIN')]
    public function foo() { }
```

### Note for Etag attribute

In the documentation, we use Etag ( not etag or ETag used in the unit tests ). So, to simplify the code, I suggest to fix the unit test. What do you think about that ?

Thank you for your reading :)

Commits
-------

ec5a467 Add PHP 8.0 attributes support
  • Loading branch information
fabpot committed Feb 16, 2021
2 parents 503c29d + ec5a467 commit 8b23c28
Show file tree
Hide file tree
Showing 29 changed files with 738 additions and 21 deletions.
41 changes: 39 additions & 2 deletions src/Configuration/Cache.php
Expand Up @@ -17,6 +17,7 @@
* @author Fabien Potencier <fabien@symfony.com>
* @Annotation
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class Cache extends ConfigurationAnnotation
{
/**
Expand All @@ -30,15 +31,15 @@ class Cache extends ConfigurationAnnotation
* The number of seconds that the response is considered fresh by a private
* cache like a web browser.
*
* @var int
* @var int|string|null
*/
private $maxage;

/**
* The number of seconds that the response is considered fresh by a public
* cache like a reverse proxy cache.
*
* @var int
* @var int|string|null
*/
private $smaxage;

Expand Down Expand Up @@ -101,6 +102,42 @@ class Cache extends ConfigurationAnnotation
*/
private $staleIfError;

/**
* @param int|string|null $maxage
* @param int|string|null $smaxage
* @param int|string|null $maxstale
* @param int|string|null $staleWhileRevalidate
* @param int|string|null $staleIfError
*/
public function __construct(
array $values = [],
string $expires = null,
$maxage = null,
$smaxage = null,
bool $public = false,
bool $mustRevalidate = false,
array $vary = [],
?string $lastModified = null,
?string $etag = null,
$maxstale = null,
$staleWhileRevalidate = null,
$staleIfError = null
) {
$values['expires'] = $values['expires'] ?? $expires;
$values['maxage'] = $values['maxage'] ?? $maxage;
$values['smaxage'] = $values['smaxage'] ?? $smaxage;
$values['public'] = $values['public'] ?? $public;
$values['mustRevalidate'] = $values['mustRevalidate'] ?? $mustRevalidate;
$values['vary'] = $values['vary'] ?? $vary;
$values['lastModified'] = $values['lastModified'] ?? $lastModified;
$values['Etag'] = $values['Etag'] ?? $etag;
$values['maxstale'] = $values['maxstale'] ?? $maxstale;
$values['staleWhileRevalidate'] = $values['staleWhileRevalidate'] ?? $staleWhileRevalidate;
$values['staleIfError'] = $values['staleIfError'] ?? $staleIfError;

parent::__construct($values);
}

/**
* Returns the expiration date for the Expires header field.
*
Expand Down
26 changes: 26 additions & 0 deletions src/Configuration/Entity.php
Expand Up @@ -17,6 +17,7 @@
* @author Ryan Weaver <ryan@knpuniversity.com>
* @Annotation
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class Entity extends ParamConverter
{
public function setExpr($expr)
Expand All @@ -26,4 +27,29 @@ public function setExpr($expr)

$this->setOptions($options);
}

/**
* @param array|string $data
*/
public function __construct(
$data = [],
string $expr = null,
string $class = null,
array $options = [],
bool $isOptional = false,
string $converter = null
) {
$values = [];
if (\is_string($data)) {
$values['value'] = $data;
} else {
$values = $data;
}

$values['expr'] = $values['expr'] ?? $expr;

parent::__construct($values, $class, $options, $isOptional, $converter);

$this->setExpr($values['expr']);
}
}
24 changes: 24 additions & 0 deletions src/Configuration/IsGranted.php
Expand Up @@ -17,6 +17,7 @@
* @author Ryan Weaver <ryan@knpuniversity.com>
* @Annotation
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class IsGranted extends ConfigurationAnnotation
{
/**
Expand Down Expand Up @@ -50,6 +51,29 @@ class IsGranted extends ConfigurationAnnotation
*/
private $statusCode;

/**
* @param mixed $subject
* @param array|string $data
*/
public function __construct(
$data = [],
$subject = null,
string $message = null,
?int $statusCode = null
) {
$values = [];
if (\is_string($data)) {
$values['attributes'] = $data;
} else {
$values = $data;
}

$values['subject'] = $values['subject'] ?? $subject;
$values['message'] = $values['message'] ?? $message;
$values['statusCode'] = $values['statusCode'] ?? $statusCode;
parent::__construct($values);
}

public function setAttributes($attributes)
{
$this->attributes = $attributes;
Expand Down
24 changes: 24 additions & 0 deletions src/Configuration/ParamConverter.php
Expand Up @@ -17,6 +17,7 @@
* @author Fabien Potencier <fabien@symfony.com>
* @Annotation
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class ParamConverter extends ConfigurationAnnotation
{
/**
Expand Down Expand Up @@ -54,6 +55,29 @@ class ParamConverter extends ConfigurationAnnotation
*/
private $converter;

/**
* @param array|string $data
*/
public function __construct(
$data = [],
string $class = null,
array $options = [],
bool $isOptional = false,
string $converter = null
) {
$values = [];
if (\is_string($data)) {
$values['value'] = $data;
} else {
$values = $data;
}
$values['class'] = $values['class'] ?? $class;
$values['options'] = $values['options'] ?? $options;
$values['isOptional'] = $values['isOptional'] ?? $isOptional;
$values['converter'] = $values['converter'] ?? $converter;
parent::__construct($values);
}

/**
* Returns the parameter name.
*
Expand Down
22 changes: 22 additions & 0 deletions src/Configuration/Security.php
Expand Up @@ -17,6 +17,7 @@
* @author Fabien Potencier <fabien@symfony.com>
* @Annotation
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class Security extends ConfigurationAnnotation
{
/**
Expand All @@ -43,6 +44,27 @@ class Security extends ConfigurationAnnotation
*/
protected $message = 'Access denied.';

/**
* @param array|string $data
*/
public function __construct(
$data = [],
string $message = null,
?int $statusCode = null
) {
$values = [];
if (\is_string($data)) {
$values['expression'] = $data;
} else {
$values = $data;
}

$values['message'] = $values['message'] ?? $message;
$values['statusCode'] = $values['statusCode'] ?? $statusCode;

parent::__construct($values);
}

public function getExpression()
{
return $this->expression;
Expand Down
24 changes: 24 additions & 0 deletions src/Configuration/Template.php
Expand Up @@ -17,6 +17,7 @@
* @author Fabien Potencier <fabien@symfony.com>
* @Annotation
*/
#[\Attribute(\Attribute::TARGET_METHOD)]
class Template extends ConfigurationAnnotation
{
/**
Expand Down Expand Up @@ -47,6 +48,29 @@ class Template extends ConfigurationAnnotation
*/
private $owner = [];

/**
* @param array|string $data
*/
public function __construct(
$data = [],
array $vars = [],
bool $isStreamable = false,
array $owner = []
) {
$values = [];
if (\is_string($data)) {
$values['template'] = $data;
} else {
$values = $data;
}

$values['isStreamable'] = $values['isStreamable'] ?? $isStreamable;
$values['vars'] = $values['vars'] ?? $vars;
$values['owner'] = $values['owner'] ?? $owner;

parent::__construct($values);
}

/**
* Returns the array of templates variables.
*
Expand Down
19 changes: 19 additions & 0 deletions src/EventListener/ControllerListener.php
Expand Up @@ -13,6 +13,7 @@

use Doctrine\Common\Annotations\Reader;
use Doctrine\Persistence\Proxy;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\KernelEvent;
Expand Down Expand Up @@ -60,6 +61,24 @@ public function onKernelController(KernelEvent $event)
$classConfigurations = $this->getConfigurations($this->reader->getClassAnnotations($object));
$methodConfigurations = $this->getConfigurations($this->reader->getMethodAnnotations($method));

if (80000 <= \PHP_VERSION_ID) {
$classAttributes = array_map(
function (\ReflectionAttribute $attribute) {
return $attribute->newInstance();
},
$object->getAttributes(ConfigurationAnnotation::class, \ReflectionAttribute::IS_INSTANCEOF)
);
$classConfigurations = array_merge($classConfigurations, $this->getConfigurations($classAttributes));

$methodAttributes = array_map(
function (\ReflectionAttribute $attribute) {
return $attribute->newInstance();
},
$method->getAttributes(ConfigurationAnnotation::class, \ReflectionAttribute::IS_INSTANCEOF)
);
$methodConfigurations = array_merge($methodConfigurations, $this->getConfigurations($methodAttributes));
}

$configurations = [];
foreach (array_merge(array_keys($classConfigurations), array_keys($methodConfigurations)) as $key) {
if (!\array_key_exists($key, $classConfigurations)) {
Expand Down

0 comments on commit 8b23c28

Please sign in to comment.