Skip to content

Commit

Permalink
Merge pull request #2327 from W0rma/param-attributes
Browse files Browse the repository at this point in the history
Add support for native PHP8 QueryParam, FileParam and RequestParam attributes
  • Loading branch information
goetas authored Dec 18, 2021
2 parents 9a17f71 + cb42f25 commit 519d967
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 51 deletions.
28 changes: 28 additions & 0 deletions Controller/Annotations/FileParam.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
* Represents a file that must be present.
*
* @Annotation
* @NamedArgumentConstructor
* @Target("METHOD")
*
* @author Ener-Getick <[email protected]>
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class FileParam extends AbstractParam
{
/** @var bool */
Expand All @@ -39,6 +41,32 @@ class FileParam extends AbstractParam
/** @var bool */
public $map = false;

/**
* @param mixed $requirements
* @param mixed $default
*/
public function __construct(
string $name = '',
bool $strict = true,
$requirements = null,
bool $image = false,
bool $map = false,
?string $key = null,
$default = null,
string $description = '',
bool $nullable = false
) {
$this->strict = $strict;
$this->requirements = $requirements;
$this->image = $image;
$this->map = $map;
$this->name = $name;
$this->key = $key;
$this->default = $default;
$this->description = $description;
$this->nullable = $nullable;
}

/**
* {@inheritdoc}
*/
Expand Down
30 changes: 30 additions & 0 deletions Controller/Annotations/QueryParam.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,42 @@
* Represents a parameter that must be present in GET data.
*
* @Annotation
* @NamedArgumentConstructor
* @Target({"CLASS", "METHOD"})
*
* @author Alexander <[email protected]>
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class QueryParam extends AbstractScalarParam
{
/**
* @param mixed $requirements
* @param mixed $default
*/
public function __construct(
string $name = '',
?string $key = null,
$requirements = null,
$default = null,
array $incompatibles = [],
string $description = '',
bool $strict = false,
bool $map = false,
bool $nullable = false,
bool $allowBlank = true
) {
$this->name = $name;
$this->key = $key;
$this->requirements = $requirements;
$this->default = $default;
$this->incompatibles = $incompatibles;
$this->description = $description;
$this->strict = $strict;
$this->map = $map;
$this->nullable = $nullable;
$this->allowBlank = $allowBlank;
}

/**
* {@inheritdoc}
*/
Expand Down
30 changes: 30 additions & 0 deletions Controller/Annotations/RequestParam.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,46 @@
* Represents a parameter that must be present in POST data.
*
* @Annotation
* @NamedArgumentConstructor
* @Target("METHOD")
*
* @author Jordi Boggiano <[email protected]>
* @author Boris Guéry <[email protected]>
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class RequestParam extends AbstractScalarParam
{
/** @var bool */
public $strict = true;

/**
* @param mixed $requirements
* @param mixed $default
*/
public function __construct(
string $name = '',
?string $key = null,
$requirements = null,
$default = null,
string $description = '',
array $incompatibles = [],
bool $strict = false,
bool $map = false,
bool $nullable = false,
bool $allowBlank = true
) {
$this->name = $name;
$this->key = $key;
$this->requirements = $requirements;
$this->default = $default;
$this->description = $description;
$this->incompatibles = $incompatibles;
$this->strict = $strict;
$this->map = $map;
$this->nullable = $nullable;
$this->allowBlank = $allowBlank;
}

/**
* {@inheritdoc}
*/
Expand Down
45 changes: 42 additions & 3 deletions Request/ParamReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
*/
final class ParamReader implements ParamReaderInterface
{
/**
* @var Reader|null
*/
private $annotationReader;

public function __construct(Reader $annotationReader)
public function __construct(?Reader $annotationReader = null)
{
$this->annotationReader = $annotationReader;
}
Expand All @@ -50,7 +53,17 @@ public function read(\ReflectionClass $reflection, string $method): array
*/
public function getParamsFromMethod(\ReflectionMethod $method): array
{
$annotations = $this->annotationReader->getMethodAnnotations($method);
$annotations = [];
if (\PHP_VERSION_ID >= 80000) {
$annotations = $this->getParamsFromAttributes($method);
}

if (null !== $this->annotationReader) {
$annotations = array_merge(
$annotations,
$this->annotationReader->getMethodAnnotations($method) ?? []
);
}

return $this->getParamsFromAnnotationArray($annotations);
}
Expand All @@ -60,7 +73,17 @@ public function getParamsFromMethod(\ReflectionMethod $method): array
*/
public function getParamsFromClass(\ReflectionClass $class): array
{
$annotations = $this->annotationReader->getClassAnnotations($class);
$annotations = [];
if (\PHP_VERSION_ID >= 80000) {
$annotations = $this->getParamsFromAttributes($class);
}

if (null !== $this->annotationReader) {
$annotations = array_merge(
$annotations,
$this->annotationReader->getClassAnnotations($class) ?? []
);
}

return $this->getParamsFromAnnotationArray($annotations);
}
Expand All @@ -79,4 +102,20 @@ private function getParamsFromAnnotationArray(array $annotations): array

return $params;
}

/**
* @param \ReflectionClass|\ReflectionMethod $reflection
*
* @return ParamInterface[]
*/
private function getParamsFromAttributes($reflection): array
{
$params = [];
foreach ($reflection->getAttributes(ParamInterface::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
$param = $attribute->newInstance();
$params[$param->getName()] = $param;
}

return $params;
}
}
2 changes: 1 addition & 1 deletion Resources/config/request.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<service id="FOS\RestBundle\Request\ParamFetcherInterface" alias="fos_rest.request.param_fetcher" />

<service id="fos_rest.request.param_fetcher.reader" class="FOS\RestBundle\Request\ParamReader" public="false">
<argument type="service" id="annotation_reader"/>
<argument type="service" id="annotation_reader" on-invalid="null"/>
</service>

</services>
Expand Down
157 changes: 110 additions & 47 deletions Resources/doc/annotations-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,126 @@ Param fetcher
QueryParam
~~~~~~~~~~

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\QueryParam;
/**
* @QueryParam(
* name="",
* key=null,
* requirements="",
* incompatibles={},
* default=null,
* description="",
* strict=false,
* map=false,
* nullable=false
* )
*/
.. tabs::

.. tab:: Annotations

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\QueryParam;
/**
* @QueryParam(
* name="",
* key=null,
* requirements="",
* incompatibles={},
* default=null,
* description="",
* strict=false,
* map=false,
* nullable=false
* )
*/
.. tab:: Attributes

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\QueryParam;
#[QueryParam(
name: '',
key: null,
requirements: '',
incompatibles: [],
default: null,
description: '',
strict: false,
map: false,
nullable: false
)]
RequestParam
~~~~~~~~~~~~

.. code-block:: php
.. tabs::

use FOS\RestBundle\Controller\Annotations\RequestParam;
.. tab:: Annotations

/**
* @RequestParam(
* name="",
* key=null,
* requirements="",
* default=null,
* description="",
* strict=true,
* map=false,
* nullable=false
* )
*/
.. code-block:: php
use FOS\RestBundle\Controller\Annotations\RequestParam;
/**
* @RequestParam(
* name="",
* key=null,
* requirements="",
* default=null,
* description="",
* strict=true,
* map=false,
* nullable=false
* )
*/
.. tab:: Attributes

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\RequestParam;
#[RequestParam(
name: '',
key: null,
requirements: '',
default: null,
description: '',
strict: true,
map: false,
nullable: false
)]
FileParam
~~~~~~~~~

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\FileParam;
/**
* @FileParam(
* name="",
* key=null,
* requirements={},
* default=null,
* description="",
* strict=true,
* nullable=false,
* image=false
* )
*/
.. tabs::

.. tab:: Annotations

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\FileParam;
/**
* @FileParam(
* name="",
* key=null,
* requirements={},
* default=null,
* description="",
* strict=true,
* nullable=false,
* image=false
* )
*/
.. tab:: Attributes

.. code-block:: php
use FOS\RestBundle\Controller\Annotations\FileParam;
#[FileParam(
name: '',
key: null,
requirements: [],
default: null,
description: '',
strict: true,
nullable: false,
image: false
)]
View
----
Expand Down
Loading

0 comments on commit 519d967

Please sign in to comment.