UrlMatcher.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <?php
  2. namespace Symfony\Components\Routing\Matcher;
  3. use Symfony\Components\Routing\Route;
  4. use Symfony\Components\Routing\RouteCollection;
  5. /*
  6. * This file is part of the symfony framework.
  7. *
  8. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  9. *
  10. * This source file is subject to the MIT license that is bundled
  11. * with this source code in the file LICENSE.
  12. */
  13. /**
  14. * UrlMatcher matches URL based on a set of routes.
  15. *
  16. * @package symfony
  17. * @subpackage routing
  18. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  19. */
  20. class UrlMatcher implements UrlMatcherInterface
  21. {
  22. protected $routes;
  23. protected $defaults;
  24. protected $context;
  25. /**
  26. * Constructor.
  27. *
  28. * @param RouteCollection $routes A RouteCollection instance
  29. * @param array $context The context
  30. * @param array $defaults The default values
  31. */
  32. public function __construct(RouteCollection $routes, array $context = array(), array $defaults = array())
  33. {
  34. $this->routes = $routes;
  35. $this->context = $context;
  36. $this->defaults = $defaults;
  37. }
  38. /**
  39. * Tries to match a URL with a set of routes.
  40. *
  41. * Returns false if no route matches the URL.
  42. *
  43. * @param string $url URL to be parsed
  44. *
  45. * @return array|false An array of parameters or false if no route matches
  46. */
  47. public function match($url)
  48. {
  49. $url = $this->normalizeUrl($url);
  50. foreach ($this->routes->getRoutes() as $name => $route)
  51. {
  52. $compiledRoute = $route->compile();
  53. // check HTTP method requirement
  54. if (isset($this->context['method']) && (($req = $route->getRequirement('_method')) && !in_array(strtolower($this->context['method']), array_map('strtolower', (array) $req))))
  55. {
  56. continue;
  57. }
  58. // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
  59. if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($url, $compiledRoute->getStaticPrefix()))
  60. {
  61. continue;
  62. }
  63. if (!preg_match($compiledRoute->getRegex(), $url, $matches))
  64. {
  65. continue;
  66. }
  67. return array_merge($this->mergeDefaults($matches, $route->getDefaults()), array('_route' => $name));
  68. }
  69. return false;
  70. }
  71. protected function mergeDefaults($params, $defaults)
  72. {
  73. $parameters = array_merge($this->defaults, $defaults);
  74. foreach ($params as $key => $value)
  75. {
  76. if (!is_int($key))
  77. {
  78. $parameters[$key] = urldecode($value);
  79. }
  80. }
  81. return $parameters;
  82. }
  83. protected function normalizeUrl($url)
  84. {
  85. // ensure that the URL starts with a /
  86. if ('/' !== substr($url, 0, 1))
  87. {
  88. $url = '/'.$url;
  89. }
  90. // remove the query string
  91. if (false !== $pos = strpos($url, '?'))
  92. {
  93. $url = substr($url, 0, $pos);
  94. }
  95. // remove multiple /
  96. return preg_replace('#/+#', '/', $url);
  97. }
  98. }