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

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