TraceableUrlMatcher.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  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\Component\Routing\Matcher;
  11. use Symfony\Component\Routing\Exception\ExceptionInterface;
  12. use Symfony\Component\Routing\Route;
  13. use Symfony\Component\Routing\RouteCollection;
  14. use Symfony\Component\Routing\Matcher\UrlMatcher;
  15. /**
  16. * TraceableUrlMatcher helps debug path info matching by tracing the match.
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. */
  20. class TraceableUrlMatcher extends UrlMatcher
  21. {
  22. const ROUTE_DOES_NOT_MATCH = 0;
  23. const ROUTE_ALMOST_MATCHES = 1;
  24. const ROUTE_MATCHES = 2;
  25. protected $traces;
  26. public function getTraces($pathinfo)
  27. {
  28. $this->traces = array();
  29. try {
  30. $this->match($pathinfo);
  31. } catch (ExceptionInterface $e) {
  32. }
  33. return $this->traces;
  34. }
  35. protected function matchCollection($pathinfo, RouteCollection $routes)
  36. {
  37. foreach ($routes as $name => $route) {
  38. $compiledRoute = $route->compile();
  39. if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
  40. // does it match without any requirements?
  41. $r = new Route($route->getPath(), $route->getDefaults(), array(), $route->getOptions());
  42. $cr = $r->compile();
  43. if (!preg_match($cr->getRegex(), $pathinfo)) {
  44. $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
  45. continue;
  46. }
  47. foreach ($route->getRequirements() as $n => $regex) {
  48. $r = new Route($route->getPath(), $route->getDefaults(), array($n => $regex), $route->getOptions());
  49. $cr = $r->compile();
  50. if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
  51. $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
  52. continue 2;
  53. }
  54. }
  55. continue;
  56. }
  57. // check host requirement
  58. $hostMatches = array();
  59. if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
  60. $this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
  61. return true;
  62. }
  63. // check HTTP method requirement
  64. if ($req = $route->getRequirement('_method')) {
  65. // HEAD and GET are equivalent as per RFC
  66. if ('HEAD' === $method = $this->context->getMethod()) {
  67. $method = 'GET';
  68. }
  69. if (!in_array($method, $req = explode('|', strtoupper($req)))) {
  70. $this->allow = array_merge($this->allow, $req);
  71. $this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context->getMethod(), implode(', ', $req)), self::ROUTE_ALMOST_MATCHES, $name, $route);
  72. continue;
  73. }
  74. }
  75. // check HTTP scheme requirement
  76. if ($scheme = $route->getRequirement('_scheme')) {
  77. if ($this->context->getScheme() !== $scheme) {
  78. $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);
  79. return true;
  80. }
  81. }
  82. $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route);
  83. return true;
  84. }
  85. }
  86. private function addTrace($log, $level = self::ROUTE_DOES_NOT_MATCH, $name = null, $route = null)
  87. {
  88. $this->traces[] = array(
  89. 'log' => $log,
  90. 'name' => $name,
  91. 'level' => $level,
  92. 'path' => null !== $route ? $route->getPath() : null,
  93. );
  94. }
  95. }