vendor/symfony-cmf/routing/src/DynamicRouter.php line 281

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony CMF package.
  4.  *
  5.  * (c) Symfony CMF
  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 Symfony\Cmf\Component\Routing;
  11. use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerTrait;
  12. use Symfony\Cmf\Component\Routing\Event\Events;
  13. use Symfony\Cmf\Component\Routing\Event\RouterGenerateEvent;
  14. use Symfony\Cmf\Component\Routing\Event\RouterMatchEvent;
  15. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  16. use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  19. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  20. use Symfony\Component\Routing\Exception\RouteNotFoundException;
  21. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  22. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  23. use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
  24. use Symfony\Component\Routing\RequestContext;
  25. use Symfony\Component\Routing\RequestContextAwareInterface;
  26. use Symfony\Component\Routing\Route;
  27. use Symfony\Component\Routing\RouteCollection;
  28. use Symfony\Component\Routing\RouterInterface;
  29. /**
  30.  * A flexible router accepting matcher and generator through injection and
  31.  * using the RouteEnhancer concept to generate additional data on the routes.
  32.  *
  33.  * @author Larry Garfield
  34.  * @author David Buchmann
  35.  */
  36. class DynamicRouter implements RouterInterfaceRequestMatcherInterfaceChainedRouterInterface
  37. {
  38.     use RouteEnhancerTrait;
  39.     /**
  40.      * @var RequestMatcherInterface|UrlMatcherInterface
  41.      */
  42.     protected $matcher;
  43.     /**
  44.      * @var UrlGeneratorInterface
  45.      */
  46.     protected $generator;
  47.     /**
  48.      * @var EventDispatcherInterface
  49.      */
  50.     protected $eventDispatcher;
  51.     /**
  52.      * The regexp pattern that needs to be matched before a dynamic lookup is
  53.      * made.
  54.      *
  55.      * @var string
  56.      */
  57.     protected $uriFilterRegexp;
  58.     /**
  59.      * @var RouteProviderInterface
  60.      */
  61.     private $provider;
  62.     /**
  63.      * @var RequestContext
  64.      */
  65.     protected $context;
  66.     /**
  67.      * @var RouteCollection
  68.      */
  69.     private $routeCollection;
  70.     /**
  71.      * @param RequestContext                              $context
  72.      * @param RequestMatcherInterface|UrlMatcherInterface $matcher
  73.      * @param UrlGeneratorInterface                       $generator
  74.      * @param string                                      $uriFilterRegexp
  75.      * @param EventDispatcherInterface|null               $eventDispatcher
  76.      * @param RouteProviderInterface                      $provider
  77.      *
  78.      * @throws \InvalidArgumentException If the matcher is not a request or url matcher
  79.      */
  80.     public function __construct(
  81.         RequestContext $context,
  82.         $matcher,
  83.         UrlGeneratorInterface $generator,
  84.         $uriFilterRegexp '',
  85.         EventDispatcherInterface $eventDispatcher null,
  86.         RouteProviderInterface $provider null
  87.     ) {
  88.         $this->context $context;
  89.         if (!$matcher instanceof RequestMatcherInterface && !$matcher instanceof UrlMatcherInterface) {
  90.             throw new \InvalidArgumentException(
  91.                 sprintf('Matcher must implement either %s or %s'RequestMatcherInterface::class, UrlMatcherInterface::class)
  92.             );
  93.         }
  94.         $this->matcher $matcher;
  95.         $this->generator $generator;
  96.         $this->eventDispatcher $eventDispatcher;
  97.         $this->uriFilterRegexp $uriFilterRegexp;
  98.         $this->provider $provider;
  99.         if (class_exists(LegacyEventDispatcherProxy::class)) {
  100.             $this->eventDispatcher LegacyEventDispatcherProxy::decorate($eventDispatcher);
  101.         }
  102.         $this->generator->setContext($context);
  103.     }
  104.     /**
  105.      * {@inheritdoc}
  106.      */
  107.     public function getRouteCollection()
  108.     {
  109.         if (!$this->routeCollection instanceof RouteCollection) {
  110.             $this->routeCollection $this->provider
  111.                 ? new LazyRouteCollection($this->provider) : new RouteCollection();
  112.         }
  113.         return $this->routeCollection;
  114.     }
  115.     /**
  116.      * @return RequestMatcherInterface|UrlMatcherInterface
  117.      */
  118.     public function getMatcher()
  119.     {
  120.         /* we may not set the context in DynamicRouter::setContext as this
  121.          * would lead to symfony cache warmup problems.
  122.          * a request matcher does not need the request context separately as it
  123.          * can get it from the request.
  124.          */
  125.         if ($this->matcher instanceof RequestContextAwareInterface) {
  126.             $this->matcher->setContext($this->getContext());
  127.         }
  128.         return $this->matcher;
  129.     }
  130.     /**
  131.      * @return UrlGeneratorInterface
  132.      */
  133.     public function getGenerator()
  134.     {
  135.         $this->generator->setContext($this->getContext());
  136.         return $this->generator;
  137.     }
  138.     /**
  139.      * Generates a URL from the given parameters.
  140.      *
  141.      * If the generator is not able to generate the url, it must throw the
  142.      * RouteNotFoundException as documented below.
  143.      *
  144.      * The CMF routing system used to allow to pass route objects as $name to generate the route.
  145.      * Since Symfony 5.0, the UrlGeneratorInterface declares $name as string. We widen the contract
  146.      * for BC but deprecate passing non-strings.
  147.      * Instead, Pass the RouteObjectInterface::OBJECT_BASED_ROUTE_NAME as route name and the object
  148.      * in the parameters with key RouteObjectInterface::ROUTE_OBJECT.
  149.      *
  150.      * @param string|Route $name The name of the route or the Route instance
  151.      *
  152.      * @throws RouteNotFoundException if route doesn't exist
  153.      */
  154.     public function generate($name$parameters = [], $referenceType UrlGeneratorInterface::ABSOLUTE_PATH)
  155.     {
  156.         if (is_object($name)) {
  157.             @trigger_error('Passing an object as route name is deprecated since version 2.3. Pass the `RouteObjectInterface::OBJECT_BASED_ROUTE_NAME` as route name and the object in the parameters with key `RouteObjectInterface::ROUTE_OBJECT'E_USER_DEPRECATED);
  158.         }
  159.         if ($this->eventDispatcher) {
  160.             $event = new RouterGenerateEvent($name$parameters$referenceType);
  161.             $this->eventDispatcher->dispatch($eventEvents::PRE_DYNAMIC_GENERATE);
  162.             $name $event->getRoute();
  163.             $parameters $event->getParameters();
  164.             $referenceType $event->getReferenceType();
  165.         }
  166.         return $this->getGenerator()->generate($name$parameters$referenceType);
  167.     }
  168.     /**
  169.      * Delegate to our generator.
  170.      *
  171.      * {@inheritdoc}
  172.      */
  173.     public function supports($name)
  174.     {
  175.         if ($this->generator instanceof VersatileGeneratorInterface) {
  176.             return $this->generator->supports($name);
  177.         }
  178.         return is_string($name);
  179.     }
  180.     /**
  181.      * Tries to match a URL path with a set of routes.
  182.      *
  183.      * If the matcher can not find information, it must throw one of the
  184.      * exceptions documented below.
  185.      *
  186.      * @param string $pathinfo The path info to be parsed (raw format, i.e. not
  187.      *                         urldecoded)
  188.      *
  189.      * @return array An array of parameters
  190.      *
  191.      * @throws ResourceNotFoundException If the resource could not be found
  192.      * @throws MethodNotAllowedException If the resource was found but the
  193.      *                                   request method is not allowed
  194.      *
  195.      * @deprecated Use matchRequest exclusively to avoid problems. This method will be removed in version 2.0
  196.      *
  197.      * @api
  198.      */
  199.     public function match($pathinfo)
  200.     {
  201.         @trigger_error(__METHOD__.'() is deprecated since version 1.3 and will be removed in 2.0. Use matchRequest() instead.'E_USER_DEPRECATED);
  202.         $request Request::create($pathinfo);
  203.         if ($this->eventDispatcher) {
  204.             $event = new RouterMatchEvent();
  205.             $this->eventDispatcher->dispatch($eventEvents::PRE_DYNAMIC_MATCH);
  206.         }
  207.         if (!empty($this->uriFilterRegexp) && !preg_match($this->uriFilterRegexp$pathinfo)) {
  208.             throw new ResourceNotFoundException("$pathinfo does not match the '{$this->uriFilterRegexp}' pattern");
  209.         }
  210.         $matcher $this->getMatcher();
  211.         if (!$matcher instanceof UrlMatcherInterface) {
  212.             throw new \InvalidArgumentException('Wrong matcher type, you need to call matchRequest');
  213.         }
  214.         $defaults $matcher->match($pathinfo);
  215.         return $this->applyRouteEnhancers($defaults$request);
  216.     }
  217.     /**
  218.      * Tries to match a request with a set of routes and returns the array of
  219.      * information for that route.
  220.      *
  221.      * If the matcher can not find information, it must throw one of the
  222.      * exceptions documented below.
  223.      *
  224.      * @param Request $request The request to match
  225.      *
  226.      * @return array An array of parameters
  227.      *
  228.      * @throws ResourceNotFoundException If no matching resource could be found
  229.      * @throws MethodNotAllowedException If a matching resource was found but
  230.      *                                   the request method is not allowed
  231.      */
  232.     public function matchRequest(Request $request)
  233.     {
  234.         if ($this->eventDispatcher) {
  235.             $event = new RouterMatchEvent($request);
  236.             $this->eventDispatcher->dispatch($eventEvents::PRE_DYNAMIC_MATCH_REQUEST);
  237.         }
  238.         if ($this->uriFilterRegexp
  239.             && !preg_match($this->uriFilterRegexp$request->getPathInfo())
  240.         ) {
  241.             throw new ResourceNotFoundException("{$request->getPathInfo()} does not match the '{$this->uriFilterRegexp}' pattern");
  242.         }
  243.         $matcher $this->getMatcher();
  244.         if ($matcher instanceof UrlMatcherInterface) {
  245.             $defaults $matcher->match($request->getPathInfo());
  246.         } else {
  247.             $defaults $matcher->matchRequest($request);
  248.         }
  249.         return $this->applyRouteEnhancers($defaults$request);
  250.     }
  251.     /**
  252.      * Sets the request context.
  253.      *
  254.      * @param RequestContext $context The context
  255.      *
  256.      * @api
  257.      */
  258.     public function setContext(RequestContext $context)
  259.     {
  260.         $this->context $context;
  261.     }
  262.     /**
  263.      * Gets the request context.
  264.      *
  265.      * @return RequestContext The context
  266.      *
  267.      * @api
  268.      */
  269.     public function getContext()
  270.     {
  271.         return $this->context;
  272.     }
  273.     /**
  274.      * {@inheritdoc}
  275.      *
  276.      * Forwards to the generator.
  277.      */
  278.     public function getRouteDebugMessage($name, array $parameters = [])
  279.     {
  280.         if ($this->generator instanceof VersatileGeneratorInterface) {
  281.             return $this->generator->getRouteDebugMessage($name$parameters);
  282.         }
  283.         return "Route '$name' not found";
  284.     }
  285. }