No Description

TraceableUrlMatcher.php 4.7KB

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