123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- <?php
- /*
- * This file is part of the Symfony CMF package.
- *
- * (c) 2011-2015 Symfony CMF
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Cmf\Component\Routing;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\Routing\RequestContext;
- use Symfony\Component\Routing\Route;
- use Symfony\Component\Routing\RouteCollection;
- use Symfony\Component\Routing\RouterInterface;
- use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
- use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
- use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
- use Symfony\Component\Routing\RequestContextAwareInterface;
- use Symfony\Component\Routing\Exception\RouteNotFoundException;
- use Symfony\Component\Routing\Exception\ResourceNotFoundException;
- use Symfony\Component\Routing\Exception\MethodNotAllowedException;
- use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
- use Symfony\Component\EventDispatcher\EventDispatcherInterface;
- use Symfony\Cmf\Component\Routing\Event\Events;
- use Symfony\Cmf\Component\Routing\Event\RouterMatchEvent;
- use Symfony\Cmf\Component\Routing\Event\RouterGenerateEvent;
- /**
- * A flexible router accepting matcher and generator through injection and
- * using the RouteEnhancer concept to generate additional data on the routes.
- *
- * @author Larry Garfield
- * @author David Buchmann
- */
- class DynamicRouter implements RouterInterface, RequestMatcherInterface, ChainedRouterInterface
- {
- /**
- * @var RequestMatcherInterface|UrlMatcherInterface
- */
- protected $matcher;
- /**
- * @var UrlGeneratorInterface
- */
- protected $generator;
- /**
- * @var EventDispatcherInterface
- */
- protected $eventDispatcher;
- /**
- * @var RouteEnhancerInterface[]
- */
- protected $enhancers = array();
- /**
- * Cached sorted list of enhancers.
- *
- * @var RouteEnhancerInterface[]
- */
- protected $sortedEnhancers = array();
- /**
- * The regexp pattern that needs to be matched before a dynamic lookup is
- * made.
- *
- * @var string
- */
- protected $uriFilterRegexp;
- /**
- * @var RequestContext
- */
- protected $context;
- /**
- * @var RouteCollection
- */
- private $routeCollection;
- /**
- * @param RequestContext $context
- * @param RequestMatcherInterface|UrlMatcherInterface $matcher
- * @param UrlGeneratorInterface $generator
- * @param string $uriFilterRegexp
- * @param EventDispatcherInterface|null $eventDispatcher
- * @param RouteProviderInterface $provider
- */
- public function __construct(RequestContext $context,
- $matcher,
- UrlGeneratorInterface $generator,
- $uriFilterRegexp = '',
- EventDispatcherInterface $eventDispatcher = null,
- RouteProviderInterface $provider = null
- ) {
- $this->context = $context;
- if (!$matcher instanceof RequestMatcherInterface && !$matcher instanceof UrlMatcherInterface) {
- throw new \InvalidArgumentException('Matcher must implement either Symfony\Component\Routing\Matcher\RequestMatcherInterface or Symfony\Component\Routing\Matcher\UrlMatcherInterface');
- }
- $this->matcher = $matcher;
- $this->generator = $generator;
- $this->eventDispatcher = $eventDispatcher;
- $this->uriFilterRegexp = $uriFilterRegexp;
- $this->provider = $provider;
- $this->generator->setContext($context);
- }
- /**
- * {@inheritdoc}
- */
- public function getRouteCollection()
- {
- if (!$this->routeCollection instanceof RouteCollection) {
- $this->routeCollection = $this->provider
- ? new LazyRouteCollection($this->provider) : new RouteCollection();
- }
- return $this->routeCollection;
- }
- /**
- * @return RequestMatcherInterface|UrlMatcherInterface
- */
- public function getMatcher()
- {
- /* we may not set the context in DynamicRouter::setContext as this
- * would lead to symfony cache warmup problems.
- * a request matcher does not need the request context separately as it
- * can get it from the request.
- */
- if ($this->matcher instanceof RequestContextAwareInterface) {
- $this->matcher->setContext($this->getContext());
- }
- return $this->matcher;
- }
- /**
- * @return UrlGeneratorInterface
- */
- public function getGenerator()
- {
- $this->generator->setContext($this->getContext());
- return $this->generator;
- }
- /**
- * Generates a URL from the given parameters.
- *
- * If the generator is not able to generate the url, it must throw the
- * RouteNotFoundException as documented below.
- *
- * @param string|Route $name The name of the route or the Route instance
- * @param mixed $parameters An array of parameters
- * @param bool|string $referenceType The type of reference to be generated (one of the constants in UrlGeneratorInterface)
- *
- * @return string The generated URL
- *
- * @throws RouteNotFoundException if route doesn't exist
- *
- * @api
- */
- public function generate($name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
- {
- if ($this->eventDispatcher) {
- $event = new RouterGenerateEvent($name, $parameters, $referenceType);
- $this->eventDispatcher->dispatch(Events::PRE_DYNAMIC_GENERATE, $event);
- $name = $event->getRoute();
- $parameters = $event->getParameters();
- $referenceType = $event->getReferenceType();
- }
- return $this->getGenerator()->generate($name, $parameters, $referenceType);
- }
- /**
- * Delegate to our generator.
- *
- * {@inheritdoc}
- */
- public function supports($name)
- {
- if ($this->generator instanceof VersatileGeneratorInterface) {
- return $this->generator->supports($name);
- }
- return is_string($name);
- }
- /**
- * Tries to match a URL path with a set of routes.
- *
- * If the matcher can not find information, it must throw one of the
- * exceptions documented below.
- *
- * @param string $pathinfo The path info to be parsed (raw format, i.e. not
- * urldecoded)
- *
- * @return array An array of parameters
- *
- * @throws ResourceNotFoundException If the resource could not be found
- * @throws MethodNotAllowedException If the resource was found but the
- * request method is not allowed
- *
- * @deprecated Use matchRequest exclusively to avoid problems. This method will be removed in version 2.0
- *
- * @api
- */
- public function match($pathinfo)
- {
- @trigger_error(__METHOD__.'() is deprecated since version 1.3 and will be removed in 2.0. Use matchRequest() instead.', E_USER_DEPRECATED);
- $request = Request::create($pathinfo);
- if ($this->eventDispatcher) {
- $event = new RouterMatchEvent();
- $this->eventDispatcher->dispatch(Events::PRE_DYNAMIC_MATCH, $event);
- }
- if (!empty($this->uriFilterRegexp) && !preg_match($this->uriFilterRegexp, $pathinfo)) {
- throw new ResourceNotFoundException("$pathinfo does not match the '{$this->uriFilterRegexp}' pattern");
- }
- $matcher = $this->getMatcher();
- if (!$matcher instanceof UrlMatcherInterface) {
- throw new \InvalidArgumentException('Wrong matcher type, you need to call matchRequest');
- }
- $defaults = $matcher->match($pathinfo);
- return $this->applyRouteEnhancers($defaults, $request);
- }
- /**
- * Tries to match a request with a set of routes and returns the array of
- * information for that route.
- *
- * If the matcher can not find information, it must throw one of the
- * exceptions documented below.
- *
- * @param Request $request The request to match
- *
- * @return array An array of parameters
- *
- * @throws ResourceNotFoundException If no matching resource could be found
- * @throws MethodNotAllowedException If a matching resource was found but
- * the request method is not allowed
- */
- public function matchRequest(Request $request)
- {
- if ($this->eventDispatcher) {
- $event = new RouterMatchEvent($request);
- $this->eventDispatcher->dispatch(Events::PRE_DYNAMIC_MATCH_REQUEST, $event);
- }
- if (!empty($this->uriFilterRegexp)
- && !preg_match($this->uriFilterRegexp, $request->getPathInfo())
- ) {
- throw new ResourceNotFoundException("{$request->getPathInfo()} does not match the '{$this->uriFilterRegexp}' pattern");
- }
- $matcher = $this->getMatcher();
- if ($matcher instanceof UrlMatcherInterface) {
- $defaults = $matcher->match($request->getPathInfo());
- } else {
- $defaults = $matcher->matchRequest($request);
- }
- return $this->applyRouteEnhancers($defaults, $request);
- }
- /**
- * Apply the route enhancers to the defaults, according to priorities.
- *
- * @param array $defaults
- * @param Request $request
- *
- * @return array
- */
- protected function applyRouteEnhancers($defaults, Request $request)
- {
- foreach ($this->getRouteEnhancers() as $enhancer) {
- $defaults = $enhancer->enhance($defaults, $request);
- }
- return $defaults;
- }
- /**
- * Add route enhancers to the router to let them generate information on
- * matched routes.
- *
- * The order of the enhancers is determined by the priority, the higher the
- * value, the earlier the enhancer is run.
- *
- * @param RouteEnhancerInterface $enhancer
- * @param int $priority
- */
- public function addRouteEnhancer(RouteEnhancerInterface $enhancer, $priority = 0)
- {
- if (empty($this->enhancers[$priority])) {
- $this->enhancers[$priority] = array();
- }
- $this->enhancers[$priority][] = $enhancer;
- $this->sortedEnhancers = array();
- return $this;
- }
- /**
- * Sorts the enhancers and flattens them.
- *
- * @return RouteEnhancerInterface[] the enhancers ordered by priority
- */
- public function getRouteEnhancers()
- {
- if (empty($this->sortedEnhancers)) {
- $this->sortedEnhancers = $this->sortRouteEnhancers();
- }
- return $this->sortedEnhancers;
- }
- /**
- * Sort enhancers by priority.
- *
- * The highest priority number is the highest priority (reverse sorting).
- *
- * @return RouteEnhancerInterface[] the sorted enhancers
- */
- protected function sortRouteEnhancers()
- {
- $sortedEnhancers = array();
- krsort($this->enhancers);
- foreach ($this->enhancers as $enhancers) {
- $sortedEnhancers = array_merge($sortedEnhancers, $enhancers);
- }
- return $sortedEnhancers;
- }
- /**
- * Sets the request context.
- *
- * @param RequestContext $context The context
- *
- * @api
- */
- public function setContext(RequestContext $context)
- {
- $this->context = $context;
- }
- /**
- * Gets the request context.
- *
- * @return RequestContext The context
- *
- * @api
- */
- public function getContext()
- {
- return $this->context;
- }
- /**
- * {@inheritdoc}
- *
- * Forwards to the generator.
- */
- public function getRouteDebugMessage($name, array $parameters = array())
- {
- if ($this->generator instanceof VersatileGeneratorInterface) {
- return $this->generator->getRouteDebugMessage($name, $parameters);
- }
- return "Route '$name' not found";
- }
- }
|