vendor/apy/breadcrumbtrail-bundle/src/EventListener/BreadcrumbListener.php line 54

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the APYBreadcrumbTrailBundle.
  4.  *
  5.  * (c) Abhoryo <abhoryo@free.fr>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace APY\BreadcrumbTrailBundle\EventListener;
  11. use APY\BreadcrumbTrailBundle\Annotation\Breadcrumb;
  12. use APY\BreadcrumbTrailBundle\Annotation\ResetBreadcrumbTrail;
  13. use APY\BreadcrumbTrailBundle\BreadcrumbTrail\Trail;
  14. use APY\BreadcrumbTrailBundle\MixedAnnotationWithAttributeBreadcrumbsException;
  15. use Doctrine\Common\Annotations\Reader;
  16. use Symfony\Component\HttpKernel\Event\KernelEvent;
  17. use Symfony\Component\HttpKernel\HttpKernelInterface;
  18. class BreadcrumbListener
  19. {
  20.     /**
  21.      * @var Reader An Reader instance
  22.      */
  23.     protected $reader;
  24.     /**
  25.      * @var Trail An Trail instance
  26.      */
  27.     protected $breadcrumbTrail;
  28.     private $supportedAttributes = [
  29.         Breadcrumb::class,
  30.         ResetBreadcrumbTrail::class,
  31.     ];
  32.     /**
  33.      * Constructor.
  34.      *
  35.      * @param Reader $reader          An Reader instance
  36.      * @param Trail  $breadcrumbTrail An Trail instance
  37.      */
  38.     public function __construct(Reader $readerTrail $breadcrumbTrail)
  39.     {
  40.         $this->reader $reader;
  41.         $this->breadcrumbTrail $breadcrumbTrail;
  42.     }
  43.     /**
  44.      * @param \Symfony\Component\HttpKernel\Event\FilterControllerEvent|\Symfony\Component\HttpKernel\Event\ControllerEvent $event
  45.      */
  46.     public function onKernelController(KernelEvent $event)
  47.     {
  48.         $controller $event->getController();
  49.         $reflectableClass \is_array($controller) ? $controller[0] : \get_class($controller);
  50.         $reflectableMethod \is_array($controller) ? $controller[1] : '__invoke';
  51.         // Annotations from class
  52.         $class = new \ReflectionClass($reflectableClass);
  53.         // Manage JMSSecurityExtraBundle proxy class
  54.         if (false !== $className $this->getRealClass($class->getName())) {
  55.             $class = new \ReflectionClass($className);
  56.         }
  57.         if ($class->isAbstract()) {
  58.             throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.'$class));
  59.         }
  60.         if (HttpKernelInterface::MASTER_REQUEST == $event->getRequestType()) {
  61.             $this->breadcrumbTrail->reset();
  62.             // Annotations from class
  63.             $classBreadcrumbs $this->reader->getClassAnnotations($class);
  64.             if ($this->supportsLoadingAttributes()) {
  65.                 $classAttributeBreadcrumbs $this->getAttributes($class);
  66.                 if (\count($classBreadcrumbs) > 0) {
  67.                     trigger_deprecation('apy/breadcrumb-bundle''1.7''Please replace the annotations in "%s" with attributes. Adding Breadcrumbs via annotations is deprecated and will be removed in v2.0, but luckily your platform supports using Attributes.'$class->name);
  68.                 }
  69.                 if (\count($classAttributeBreadcrumbs) > 0) {
  70.                     if (\count($classBreadcrumbs) > 0) {
  71.                         throw MixedAnnotationWithAttributeBreadcrumbsException::forClass($class->name);
  72.                     }
  73.                     $classBreadcrumbs $classAttributeBreadcrumbs;
  74.                 }
  75.             }
  76.             $this->addBreadcrumbsToTrail($classBreadcrumbs);
  77.             // Annotations from method
  78.             $method $class->getMethod($reflectableMethod);
  79.             $methodBreadcrumbs $this->reader->getMethodAnnotations($method);
  80.             if ($this->supportsLoadingAttributes()) {
  81.                 $methodAttributeBreadcrumbs $this->getAttributes($method);
  82.                 if (\count($methodBreadcrumbs) > 0) {
  83.                     trigger_deprecation('apy/breadcrumb-bundle''1.7''Please replace the annotations in "%s" with attributes. Adding Breadcrumbs via annotations is deprecated and will be removed in v2.0, but luckily your platform supports using Attributes.'$class->name.'::'.$method->name);
  84.                 }
  85.                 if (\count($methodAttributeBreadcrumbs) > 0) {
  86.                     if (\count($methodBreadcrumbs) > 0) {
  87.                         throw MixedAnnotationWithAttributeBreadcrumbsException::forClassMethod($class->name$method->name);
  88.                     }
  89.                     $methodBreadcrumbs $methodAttributeBreadcrumbs;
  90.                 }
  91.             }
  92.             $this->addBreadcrumbsToTrail($methodBreadcrumbs);
  93.         }
  94.     }
  95.     /**
  96.      * @param array $annotations Array of Breadcrumb annotations
  97.      */
  98.     private function addBreadcrumbsToTrail(array $annotations)
  99.     {
  100.         // requirements (@Breadcrumb)
  101.         foreach ($annotations as $annotation) {
  102.             if ($annotation instanceof ResetBreadcrumbTrail) {
  103.                 $this->breadcrumbTrail->reset();
  104.                 continue;
  105.             }
  106.             if ($annotation instanceof Breadcrumb) {
  107.                 $template $annotation->getTemplate();
  108.                 $title $annotation->getTitle();
  109.                 if (null === $title) {
  110.                     trigger_deprecation('apy/breadcrumb-bundle''1.8''Resetting the breadcrumb trail by passing a Breadcrumb without parameters, and will throw an exception in v2.0. Use #[ResetBreadcrumbTrail] attribute instead.');
  111.                 }
  112.                 if (null != $template) {
  113.                     $this->breadcrumbTrail->setTemplate($template);
  114.                     if (null === $title) {
  115.                         continue;
  116.                     }
  117.                 }
  118.                 $this->breadcrumbTrail->add(
  119.                     $title,
  120.                     $annotation->getRouteName(),
  121.                     $annotation->getRouteParameters(),
  122.                     $annotation->getRouteAbsolute(),
  123.                     $annotation->getPosition(),
  124.                     $annotation->getAttributes()
  125.                 );
  126.             }
  127.         }
  128.     }
  129.     private function getRealClass($className)
  130.     {
  131.         if (false === $pos strrpos($className'\\__CG__\\')) {
  132.             return false;
  133.         }
  134.         return substr($className$pos 8);
  135.     }
  136.     private function supportsLoadingAttributes(): bool
  137.     {
  138.         return \PHP_VERSION_ID >= 80000;
  139.     }
  140.     /**
  141.      * @param \ReflectionClass|\ReflectionMethod $reflected
  142.      *
  143.      * @return array<Breadcrumb>
  144.      */
  145.     private function getAttributes($reflected): array
  146.     {
  147.         if (false === $this->supportsLoadingAttributes()) {
  148.             throw new \RuntimeException('Detected an attempt on getting attributes while your version of PHP does not support this.');
  149.         }
  150.         $attributes = [];
  151.         foreach ($reflected->getAttributes() as $reflectionAttribute) {
  152.             if (false === \in_array($reflectionAttribute->getName(), $this->supportedAttributes)) {
  153.                 continue;
  154.             }
  155.             $attributes[] = $reflectionAttribute->newInstance();
  156.         }
  157.         return $attributes;
  158.     }
  159. }