Skip to content

Instantly share code, notes, and snippets.

@flohw
Last active November 6, 2019 12:05
Show Gist options
  • Select an option

  • Save flohw/4efb4e37e2b57dda1e69b35ad9f42db0 to your computer and use it in GitHub Desktop.

Select an option

Save flohw/4efb4e37e2b57dda1e69b35ad9f42db0 to your computer and use it in GitHub Desktop.

Revisions

  1. flohw revised this gist Nov 6, 2019. 5 changed files with 230 additions and 0 deletions.
    36 changes: 36 additions & 0 deletions Controller.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    <?php

    namespace App\Controller;

    use App\Rest\Annotations\PaginationParams;
    use FOS\RestBundle\Controller\Annotations as FOSRest;
    use FOS\RestBundle\Request\ParamFetcherInterface;

    class ArticleListController extends AbstractFOSRestController
    {
    /**
    * Ancienne méthode
    *
    * @FOSRest\QueryParam(name="_page", requirements="\d+", default=1)
    * @FOSRest\QueryParam(name="_per_page, requirements="(10|20|50|100)", default=50)
    * @FOSRest\QueryParam(name="_sort", requirements="-?[a-zA-Z_]+(\.[a-zA-Z_]+)?", default="id")
    */
    public function __invoke(ParamFetcherInterface $paramFetcher)
    {
    $paramFetcher->get('_page');
    $paramFetcher->get('_per_page');
    $paramFetcher->get('_sort');
    }

    /**
    * Nouvelle méthode
    *
    * @PaginationParams()
    */
    public function __invoke(ParamFetcherInterface $paramFetcher)
    {
    $paramFetcher->get('_page');
    $paramFetcher->get('_per_page');
    $paramFetcher->get('_sort');
    }
    }
    51 changes: 51 additions & 0 deletions GlobalParamFetcherSubscriber.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    <?php

    namespace App\EventListener;

    use App\Rest\ParamReader;
    use FOS\RestBundle\FOSRestBundle;
    use FOS\RestBundle\Request\ParamFetcherInterface;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpKernel\Event\ControllerEvent;
    use Symfony\Component\HttpKernel\KernelEvents;

    class GlobalParamFetcherSubscriber implements EventSubscriberInterface
    {
    private $paramFetcher;
    private $paramReader;

    public static function getSubscribedEvents()
    {
    return [
    KernelEvents::CONTROLLER => 'onKernelController',
    ];
    }

    public function __construct(ParamFetcherInterface $paramFetcher, ParamReader $paramReader)
    {
    $this->paramFetcher = $paramFetcher;
    $this->paramReader = $paramReader;
    }

    public function onKernelController(ControllerEvent $event)
    {
    $request = $event->getRequest();

    if (!$request->attributes->get(FOSRestBundle::ZONE_ATTRIBUTE, true)) {
    return;
    }

    $controller = $event->getController();

    if (\is_callable($controller) && method_exists($controller, '__invoke')) {
    $controller = [$controller, '__invoke'];
    }

    $annotations = $this->paramReader->read(new \ReflectionClass($controller[0]), $controller[1]);
    foreach ($annotations as $annotation) {
    foreach ($annotation->getAnnotationsInstances() as $fosRestAnnotation) {
    $this->paramFetcher->addParam($fosRestAnnotation);
    }
    }
    }
    }
    57 changes: 57 additions & 0 deletions PaginationParams.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    <?php

    namespace App\Rest\Annotations;

    use FOS\RestBundle\Controller\Annotations\QueryParam;

    /**
    * @Annotation
    */
    class PaginationParams implements ParamInterface
    {
    public $defaultSort = 'id';

    public function getAnnotationsInstances(): array
    {
    return [
    $this->getPageParam(),
    $this->getPerPageParam(),
    $this->getSortParam(),
    ];
    }

    public function getName(): string
    {
    return 'pagination';
    }

    private function getPageParam()
    {
    $page = new QueryParam();
    $page->name = '_page';
    $page->requirements = "\d+";
    $page->default = 1;

    return $page;
    }

    private function getPerPageParam()
    {
    $perPage = new QueryParam();
    $perPage->name = '_per_page';
    $perPage->requirements = '(10|25|50|100)';
    $perPage->default = 50;

    return $perPage;
    }

    private function getSortParam()
    {
    $sort = new QueryParam();
    $sort->name = '_sort';
    $sort->requirements = '(\-)?[a-zA-Z_]+(\.[a-zA-Z_]+)?';
    $sort->default = $this->defaultSort;

    return $sort;
    }
    }
    71 changes: 71 additions & 0 deletions PaginationParamsWithLegacy.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    <?php

    namespace App\Rest\Annotations;

    use FOS\RestBundle\Controller\Annotations\QueryParam;

    /**
    * @Annotation
    */
    class PaginationParams implements ParamInterface
    {
    public $defaultSort = 'id';

    public function getAnnotationsInstances(): array
    {
    return [
    $this->getPageParam(),
    $this->getPerPageParam(),
    $this->getSortParam(),
    $this->getLimitParam(),
    ];
    }

    public function getName(): string
    {
    return 'pagination';
    }

    private function getPageParam()
    {
    $page = new QueryParam();
    $page->name = '_page';
    $page->requirements = "\d+";
    $page->default = 1;

    return $page;
    }

    private function getPerPageParam()
    {
    $perPage = new QueryParam();
    $perPage->name = '_per_page';
    $perPage->requirements = '(10|25|50|100)';
    $perPage->default = 50;

    return $perPage;
    }

    private function getSortParam()
    {
    $sort = new QueryParam();
    $sort->name = '_sort';
    $sort->requirements = '(\-)?[a-zA-Z_]+(\.[a-zA-Z_]+)?';
    $sort->default = $this->defaultSort;

    return $sort;
    }

    /**
    * @deprecated use _per_page parameter instead
    */
    private function getLimitParam()
    {
    $limit = new QueryParam();
    $limit->name = 'limit';
    $limit->requirements = '(10|25|50|100)';
    $limit->default = 50;

    return $limit;
    }
    }
    15 changes: 15 additions & 0 deletions ParamInterface.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    <?php

    namespace App\Rest\Annotations;

    use FOS\RestBundle\Controller\Annotations\AbstractScalarParam;

    interface ParamInterface
    {
    /**
    * @return AbstractScalarParam[]
    */
    public function getAnnotationsInstances(): array;

    public function getName(): string;
    }
  2. flohw created this gist Nov 6, 2019.
    58 changes: 58 additions & 0 deletions ParamReader.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    <?php

    namespace App\Rest;

    use App\Rest\Annotations\ParamInterface;
    use Doctrine\Common\Annotations\Reader;
    use FOS\RestBundle\Request\ParamReaderInterface;

    class ParamReader implements ParamReaderInterface
    {
    private $annotationReader;

    public function __construct(Reader $annotationReader)
    {
    $this->annotationReader = $annotationReader;
    }

    /**
    * @return ParamInterface[]
    */
    public function read(\ReflectionClass $reflection, $method)
    {
    if (!$reflection->hasMethod($method)) {
    throw new \InvalidArgumentException(sprintf("Class '%s' has no method '%s'.", $reflection->getName(), $method));
    }

    $methodParams = $this->getParamsFromMethod($reflection->getMethod($method));
    $classParams = $this->getParamsFromClass($reflection);

    return array_merge($methodParams, $classParams);
    }

    public function getParamsFromMethod(\ReflectionMethod $method)
    {
    $annotations = $this->annotationReader->getMethodAnnotations($method);

    return $this->getParamsFromAnnotationArray($annotations);
    }

    public function getParamsFromClass(\ReflectionClass $class)
    {
    $annotations = $this->annotationReader->getClassAnnotations($class);

    return $this->getParamsFromAnnotationArray($annotations);
    }

    private function getParamsFromAnnotationArray(array $annotations)
    {
    $params = [];
    foreach ($annotations as $annotation) {
    if ($annotation instanceof ParamInterface) {
    $params[$annotation->getName()] = $annotation;
    }
    }

    return $params;
    }
    }