class ChainRouter in Zircon Profile 8
Same name and namespace in other branches
- 8.0 vendor/symfony-cmf/routing/ChainRouter.php \Symfony\Cmf\Component\Routing\ChainRouter
The ChainRouter allows to combine several routers to try in a defined order.
@author Henrik Bjornskov <henrik@bjrnskov.dk> @author Magnus Nordlander <magnus@e-butik.se>
Hierarchy
- class \Symfony\Cmf\Component\Routing\ChainRouter implements ChainRouterInterface, WarmableInterface
Expanded class hierarchy of ChainRouter
2 files declare their use of ChainRouter
- AccessAwareRouter.php in core/
lib/ Drupal/ Core/ Routing/ AccessAwareRouter.php - Contains \Drupal\Core\Routing\AccessAwareRouter.
- ChainRouterTest.php in vendor/
symfony-cmf/ routing/ Tests/ Routing/ ChainRouterTest.php
1 string reference to 'ChainRouter'
- core.services.yml in core/
core.services.yml - core/core.services.yml
1 service uses ChainRouter
File
- vendor/
symfony-cmf/ routing/ ChainRouter.php, line 33
Namespace
Symfony\Cmf\Component\RoutingView source
class ChainRouter implements ChainRouterInterface, WarmableInterface {
/**
* @var RequestContext
*/
private $context;
/**
* Array of arrays of routers grouped by priority
* @var array
*/
private $routers = array();
/**
* @var RouterInterface[] Array of routers, sorted by priority
*/
private $sortedRouters;
/**
* @var RouteCollection
*/
private $routeCollection;
/**
* @var null|LoggerInterface
*/
protected $logger;
/**
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger = null) {
$this->logger = $logger;
}
/**
* @return RequestContext
*/
public function getContext() {
return $this->context;
}
/**
* {@inheritdoc}
*/
public function add($router, $priority = 0) {
if (!$router instanceof RouterInterface && !($router instanceof RequestMatcherInterface && $router instanceof UrlGeneratorInterface)) {
throw new \InvalidArgumentException(sprintf('%s is not a valid router.', get_class($router)));
}
if (empty($this->routers[$priority])) {
$this->routers[$priority] = array();
}
$this->routers[$priority][] = $router;
$this->sortedRouters = array();
}
/**
* {@inheritdoc}
*/
public function all() {
if (empty($this->sortedRouters)) {
$this->sortedRouters = $this
->sortRouters();
// setContext() is done here instead of in add() to avoid fatal errors when clearing and warming up caches
// See https://github.com/symfony-cmf/Routing/pull/18
$context = $this
->getContext();
if (null !== $context) {
foreach ($this->sortedRouters as $router) {
if ($router instanceof RequestContextAwareInterface) {
$router
->setContext($context);
}
}
}
}
return $this->sortedRouters;
}
/**
* Sort routers by priority.
* The highest priority number is the highest priority (reverse sorting)
*
* @return RouterInterface[]
*/
protected function sortRouters() {
$sortedRouters = array();
krsort($this->routers);
foreach ($this->routers as $routers) {
$sortedRouters = array_merge($sortedRouters, $routers);
}
return $sortedRouters;
}
/**
* {@inheritdoc}
*
* Loops through all routes and tries to match the passed url.
*
* Note: You should use matchRequest if you can.
*/
public function match($url) {
return $this
->doMatch($url);
}
/**
* {@inheritdoc}
*
* Loops through all routes and tries to match the passed request.
*/
public function matchRequest(Request $request) {
return $this
->doMatch($request
->getPathInfo(), $request);
}
/**
* Loops through all routers and tries to match the passed request or url.
*
* At least the url must be provided, if a request is additionally provided
* the request takes precedence.
*
* @param string $url
* @param Request $request
*
* @return array An array of parameters
*
* @throws ResourceNotFoundException If no router matched.
*/
private function doMatch($url, Request $request = null) {
$methodNotAllowed = null;
$requestForMatching = $request;
foreach ($this
->all() as $router) {
try {
// the request/url match logic is the same as in Symfony/Component/HttpKernel/EventListener/RouterListener.php
// matching requests is more powerful than matching URLs only, so try that first
if ($router instanceof RequestMatcherInterface) {
if (empty($requestForMatching)) {
$requestForMatching = Request::create($url);
}
return $router
->matchRequest($requestForMatching);
}
// every router implements the match method
return $router
->match($url);
} catch (ResourceNotFoundException $e) {
if ($this->logger) {
$this->logger
->debug('Router ' . get_class($router) . ' was not able to match, message "' . $e
->getMessage() . '"');
}
// Needs special care
} catch (MethodNotAllowedException $e) {
if ($this->logger) {
$this->logger
->debug('Router ' . get_class($router) . ' throws MethodNotAllowedException with message "' . $e
->getMessage() . '"');
}
$methodNotAllowed = $e;
}
}
$info = $request ? "this request\n{$request}" : "url '{$url}'";
throw $methodNotAllowed ?: new ResourceNotFoundException("None of the routers in the chain matched {$info}");
}
/**
* {@inheritdoc}
*
* Loops through all registered routers and returns a router if one is found.
* It will always return the first route generated.
*/
public function generate($name, $parameters = array(), $absolute = false) {
$debug = array();
foreach ($this
->all() as $router) {
// if $router does not announce it is capable of handling
// non-string routes and $name is not a string, continue
if ($name && !is_string($name) && !$router instanceof VersatileGeneratorInterface) {
continue;
}
// If $router is versatile and doesn't support this route name, continue
if ($router instanceof VersatileGeneratorInterface && !$router
->supports($name)) {
continue;
}
try {
return $router
->generate($name, $parameters, $absolute);
} catch (RouteNotFoundException $e) {
$hint = $this
->getErrorMessage($name, $router, $parameters);
$debug[] = $hint;
if ($this->logger) {
$this->logger
->debug('Router ' . get_class($router) . " was unable to generate route. Reason: '{$hint}': " . $e
->getMessage());
}
}
}
if ($debug) {
$debug = array_unique($debug);
$info = implode(', ', $debug);
}
else {
$info = $this
->getErrorMessage($name);
}
throw new RouteNotFoundException(sprintf('None of the chained routers were able to generate route: %s', $info));
}
private function getErrorMessage($name, $router = null, $parameters = null) {
if ($router instanceof VersatileGeneratorInterface) {
$displayName = $router
->getRouteDebugMessage($name, $parameters);
}
elseif (is_object($name)) {
$displayName = method_exists($name, '__toString') ? (string) $name : get_class($name);
}
else {
$displayName = (string) $name;
}
return "Route '{$displayName}' not found";
}
/**
* {@inheritdoc}
*/
public function setContext(RequestContext $context) {
foreach ($this
->all() as $router) {
if ($router instanceof RequestContextAwareInterface) {
$router
->setContext($context);
}
}
$this->context = $context;
}
/**
* {@inheritdoc}
*
* check for each contained router if it can warmup
*/
public function warmUp($cacheDir) {
foreach ($this
->all() as $router) {
if ($router instanceof WarmableInterface) {
$router
->warmUp($cacheDir);
}
}
}
/**
* {@inheritdoc}
*/
public function getRouteCollection() {
if (!$this->routeCollection instanceof RouteCollection) {
$this->routeCollection = new ChainRouteCollection();
foreach ($this
->all() as $router) {
$this->routeCollection
->addCollection($router
->getRouteCollection());
}
}
return $this->routeCollection;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ChainRouter:: |
private | property | ||
ChainRouter:: |
protected | property | ||
ChainRouter:: |
private | property | ||
ChainRouter:: |
private | property | Array of arrays of routers grouped by priority | |
ChainRouter:: |
private | property | ||
ChainRouter:: |
public | function |
Add a Router to the index. Overrides ChainRouterInterface:: |
|
ChainRouter:: |
public | function |
Sorts the routers and flattens them. Overrides ChainRouterInterface:: |
|
ChainRouter:: |
private | function | Loops through all routers and tries to match the passed request or url. | |
ChainRouter:: |
public | function |
Loops through all registered routers and returns a router if one is found.
It will always return the first route generated. Overrides UrlGeneratorInterface:: |
|
ChainRouter:: |
public | function |
Overrides RequestContextAwareInterface:: |
|
ChainRouter:: |
private | function | ||
ChainRouter:: |
public | function |
Gets the RouteCollection instance associated with this Router. Overrides RouterInterface:: |
|
ChainRouter:: |
public | function |
Loops through all routes and tries to match the passed url. Overrides UrlMatcherInterface:: |
|
ChainRouter:: |
public | function |
Loops through all routes and tries to match the passed request. Overrides RequestMatcherInterface:: |
|
ChainRouter:: |
public | function |
Sets the request context. Overrides RequestContextAwareInterface:: |
|
ChainRouter:: |
protected | function | Sort routers by priority. The highest priority number is the highest priority (reverse sorting) | |
ChainRouter:: |
public | function |
check for each contained router if it can warmup Overrides WarmableInterface:: |
|
ChainRouter:: |
public | function | ||
UrlGeneratorInterface:: |
constant | Generates an absolute path, e.g. "/dir/file". | ||
UrlGeneratorInterface:: |
constant | Generates an absolute URL, e.g. "http://example.com/dir/file". | ||
UrlGeneratorInterface:: |
constant | Generates a network path, e.g. "//example.com/dir/file". Such reference reuses the current scheme but specifies the host. | ||
UrlGeneratorInterface:: |
constant | Generates a relative path based on the current request path, e.g. "../parent-file". |