UrlMatcher.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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\MethodNotAllowedException;
  12. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  13. use Symfony\Component\Routing\Route;
  14. use Symfony\Component\Routing\RouteCollection;
  15. use Symfony\Component\Routing\RequestContext;
  16. /**
  17. * UrlMatcher matches URL based on a set of routes.
  18. *
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. */
  21. class UrlMatcher implements UrlMatcherInterface
  22. {
  23. protected $context;
  24. private $routes;
  25. /**
  26. * Constructor.
  27. *
  28. * @param RouteCollection $routes A RouteCollection instance
  29. * @param RequestContext $context The context
  30. */
  31. public function __construct(RouteCollection $routes, RequestContext $context)
  32. {
  33. $this->routes = $routes;
  34. $this->context = $context;
  35. }
  36. /**
  37. * Sets the request context.
  38. *
  39. * @param RequestContext $context The context
  40. */
  41. public function setContext(RequestContext $context)
  42. {
  43. $this->context = $context;
  44. }
  45. /**
  46. * Gets the request context.
  47. *
  48. * @return RequestContext The context
  49. */
  50. public function getContext()
  51. {
  52. return $this->context;
  53. }
  54. /**
  55. * Tries to match a URL with a set of routes.
  56. *
  57. * @param string $pathinfo The path info to be parsed
  58. *
  59. * @return array An array of parameters
  60. *
  61. * @throws ResourceNotFoundException If the resource could not be found
  62. * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
  63. */
  64. public function match($pathinfo)
  65. {
  66. $this->allow = array();
  67. if ($ret = $this->matchCollection($pathinfo, $this->routes)) {
  68. return $ret;
  69. }
  70. throw 0 < count($this->allow)
  71. ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow)))
  72. : new ResourceNotFoundException();
  73. }
  74. protected function matchCollection($pathinfo, RouteCollection $routes)
  75. {
  76. foreach ($routes as $name => $route) {
  77. if ($route instanceof RouteCollection) {
  78. if (false === strpos($route->getPrefix(), '{') && $route->getPrefix() !== substr($pathinfo, 0, strlen($route->getPrefix()))) {
  79. continue;
  80. }
  81. if (!$ret = $this->matchCollection($pathinfo, $route)) {
  82. continue;
  83. }
  84. return $ret;
  85. }
  86. $compiledRoute = $route->compile();
  87. // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
  88. if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
  89. continue;
  90. }
  91. if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
  92. continue;
  93. }
  94. // check HTTP method requirement
  95. if ($req = $route->getRequirement('_method')) {
  96. // HEAD and GET are equivalent as per RFC
  97. if ('HEAD' === $method = $this->context->getMethod()) {
  98. $method = 'GET';
  99. }
  100. if (!in_array($method, $req = explode('|', strtoupper($req)))) {
  101. $this->allow = array_merge($this->allow, $req);
  102. continue;
  103. }
  104. }
  105. return array_merge($this->mergeDefaults($matches, $route->getDefaults()), array('_route' => $name));
  106. }
  107. }
  108. protected function mergeDefaults($params, $defaults)
  109. {
  110. $parameters = $defaults;
  111. foreach ($params as $key => $value) {
  112. if (!is_int($key)) {
  113. $parameters[$key] = rawurldecode($value);
  114. }
  115. }
  116. return $parameters;
  117. }
  118. }