4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Routing\Matcher
;
14 use Symfony\Component\Routing\Exception\ExceptionInterface
;
15 use Symfony\Component\Routing\Route
;
16 use Symfony\Component\Routing\RouteCollection
;
17 use Symfony\Component\Routing\Matcher\UrlMatcher
;
20 * TraceableUrlMatcher helps debug path info matching by tracing the match.
22 * @author Fabien Potencier <fabien@symfony.com>
24 class TraceableUrlMatcher
extends UrlMatcher
26 const ROUTE_DOES_NOT_MATCH
= 0;
27 const ROUTE_ALMOST_MATCHES
= 1;
28 const ROUTE_MATCHES
= 2;
32 public function getTraces($pathinfo)
34 $this->traces
= array();
37 $this->match($pathinfo);
38 } catch (ExceptionInterface
$e) {
44 protected function matchCollection($pathinfo, RouteCollection
$routes)
46 foreach ($routes as $name => $route) {
47 $compiledRoute = $route->compile();
49 if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
50 // does it match without any requirements?
51 $r = new Route($route->getPath(), $route->getDefaults(), array(), $route->getOptions());
53 if (!preg_match($cr->getRegex(), $pathinfo)) {
54 $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self
::ROUTE_DOES_NOT_MATCH
, $name, $route);
59 foreach ($route->getRequirements() as $n => $regex) {
60 $r = new Route($route->getPath(), $route->getDefaults(), array($n => $regex), $route->getOptions());
63 if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
64 $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self
::ROUTE_ALMOST_MATCHES
, $name, $route);
73 // check host requirement
74 $hostMatches = array();
75 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context
->getHost(), $hostMatches)) {
76 $this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context
->getHost(), $route->getHost()), self
::ROUTE_ALMOST_MATCHES
, $name, $route);
81 // check HTTP method requirement
82 if ($req = $route->getRequirement('_method')) {
83 // HEAD and GET are equivalent as per RFC
84 if ('HEAD' === $method = $this->context
->getMethod()) {
88 if (!in_array($method, $req = explode('|', strtoupper($req)))) {
89 $this->allow
= array_merge($this->allow
, $req);
91 $this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context
->getMethod(), implode(', ', $req)), self
::ROUTE_ALMOST_MATCHES
, $name, $route);
97 // check HTTP scheme requirement
98 if ($scheme = $route->getRequirement('_scheme')) {
99 if ($this->context
->getScheme() !== $scheme) {
100 $this->addTrace(sprintf('Scheme "%s" does not match the requirement ("%s"); the user will be redirected', $this->context
->getScheme(), $scheme), self
::ROUTE_ALMOST_MATCHES
, $name, $route);
106 $this->addTrace('Route matches!', self
::ROUTE_MATCHES
, $name, $route);
112 private function addTrace($log, $level = self
::ROUTE_DOES_NOT_MATCH
, $name = null, $route = null)
114 $this->traces
[] = array(
118 'path' => null !== $route ? $route->getPath() : null,