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

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