View source
<?php
namespace Symfony\Component\Routing\Matcher;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface {
const REQUIREMENT_MATCH = 0;
const REQUIREMENT_MISMATCH = 1;
const ROUTE_MATCH = 2;
protected $context;
protected $allow = array();
protected $routes;
protected $request;
protected $expressionLanguage;
protected $expressionLanguageProviders = array();
public function __construct(RouteCollection $routes, RequestContext $context) {
$this->routes = $routes;
$this->context = $context;
}
public function setContext(RequestContext $context) {
$this->context = $context;
}
public function getContext() {
return $this->context;
}
public function match($pathinfo) {
$this->allow = array();
if ($ret = $this
->matchCollection(rawurldecode($pathinfo), $this->routes)) {
return $ret;
}
throw 0 < count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
}
public function matchRequest(Request $request) {
$this->request = $request;
$ret = $this
->match($request
->getPathInfo());
$this->request = null;
return $ret;
}
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider) {
$this->expressionLanguageProviders[] = $provider;
}
protected function matchCollection($pathinfo, RouteCollection $routes) {
foreach ($routes as $name => $route) {
$compiledRoute = $route
->compile();
if ('' !== $compiledRoute
->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute
->getStaticPrefix())) {
continue;
}
if (!preg_match($compiledRoute
->getRegex(), $pathinfo, $matches)) {
continue;
}
$hostMatches = array();
if ($compiledRoute
->getHostRegex() && !preg_match($compiledRoute
->getHostRegex(), $this->context
->getHost(), $hostMatches)) {
continue;
}
if ($requiredMethods = $route
->getMethods()) {
if ('HEAD' === ($method = $this->context
->getMethod())) {
$method = 'GET';
}
if (!in_array($method, $requiredMethods)) {
$this->allow = array_merge($this->allow, $requiredMethods);
continue;
}
}
$status = $this
->handleRouteRequirements($pathinfo, $name, $route);
if (self::ROUTE_MATCH === $status[0]) {
return $status[1];
}
if (self::REQUIREMENT_MISMATCH === $status[0]) {
continue;
}
return $this
->getAttributes($route, $name, array_replace($matches, $hostMatches));
}
}
protected function getAttributes(Route $route, $name, array $attributes) {
$attributes['_route'] = $name;
return $this
->mergeDefaults($attributes, $route
->getDefaults());
}
protected function handleRouteRequirements($pathinfo, $name, Route $route) {
if ($route
->getCondition() && !$this
->getExpressionLanguage()
->evaluate($route
->getCondition(), array(
'context' => $this->context,
'request' => $this->request,
))) {
return array(
self::REQUIREMENT_MISMATCH,
null,
);
}
$scheme = $this->context
->getScheme();
$status = $route
->getSchemes() && !$route
->hasScheme($scheme) ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
return array(
$status,
null,
);
}
protected function mergeDefaults($params, $defaults) {
foreach ($params as $key => $value) {
if (!is_int($key)) {
$defaults[$key] = $value;
}
}
return $defaults;
}
protected function getExpressionLanguage() {
if (null === $this->expressionLanguage) {
if (!class_exists('Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage')) {
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
}
$this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
}
return $this->expressionLanguage;
}
}