Drupal investigation

NestedMatcher.php 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <?php
  2. /*
  3. * This file is part of the Symfony CMF package.
  4. *
  5. * (c) 2011-2015 Symfony CMF
  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\Cmf\Component\Routing\NestedMatcher;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  13. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  14. use Symfony\Cmf\Component\Routing\RouteProviderInterface;
  15. /**
  16. * A more flexible approach to matching. The route collection to match against
  17. * can be dynamically determined based on the request and users can inject
  18. * their own filters or use a custom final matching strategy.
  19. *
  20. * The nested matcher splits matching into three configurable steps:
  21. *
  22. * 1) Get potential matches from a RouteProviderInterface
  23. * 2) Apply any RouteFilterInterface to reduce the route collection
  24. * 3) Have FinalMatcherInterface select the best match of the remaining routes
  25. *
  26. * @author Larry Garfield
  27. * @author David Buchmann
  28. */
  29. class NestedMatcher implements RequestMatcherInterface
  30. {
  31. /**
  32. * The route provider responsible for the first-pass match.
  33. *
  34. * @var RouteProviderInterface
  35. */
  36. protected $routeProvider;
  37. /**
  38. * The final matcher.
  39. *
  40. * @var FinalMatcherInterface
  41. */
  42. protected $finalMatcher;
  43. /**
  44. * An array of RouteFilterInterface objects.
  45. *
  46. * @var RouteFilterInterface[]
  47. */
  48. protected $filters = array();
  49. /**
  50. * Array of RouteFilterInterface objects, sorted.
  51. *
  52. * @var RouteFilterInterface[]
  53. */
  54. protected $sortedFilters = array();
  55. /**
  56. * Constructs a new NestedMatcher.
  57. *
  58. * @param RouteProviderInterface $provider The route provider this matcher
  59. * should use
  60. * @param FinalMatcherInterface $final The Final Matcher to match the
  61. * routes
  62. */
  63. public function __construct(
  64. RouteProviderInterface $provider = null,
  65. FinalMatcherInterface $final = null
  66. ) {
  67. if (null !== $provider) {
  68. $this->setRouteProvider($provider);
  69. }
  70. if (null !== $final) {
  71. $this->setFinalMatcher($final);
  72. }
  73. }
  74. /**
  75. * Sets the route provider for the matching plan.
  76. *
  77. * @param RouteProviderInterface $provider A source of routes.
  78. *
  79. * @return NestedMatcher this object to have a fluent interface
  80. */
  81. public function setRouteProvider(RouteProviderInterface $provider)
  82. {
  83. $this->routeProvider = $provider;
  84. return $this;
  85. }
  86. /**
  87. * Adds a partial matcher to the matching plan.
  88. *
  89. * Partial matchers will be run in the order in which they are added.
  90. *
  91. * @param RouteFilterInterface $filter
  92. * @param int $priority (optional) The priority of the
  93. * filter. Higher number filters will
  94. * be used first. Defaults to 0.
  95. *
  96. * @return NestedMatcher this object to have a fluent interface
  97. */
  98. public function addRouteFilter(RouteFilterInterface $filter, $priority = 0)
  99. {
  100. if (empty($this->filters[$priority])) {
  101. $this->filters[$priority] = array();
  102. }
  103. $this->filters[$priority][] = $filter;
  104. $this->sortedFilters = array();
  105. return $this;
  106. }
  107. /**
  108. * Sets the final matcher for the matching plan.
  109. *
  110. * @param FinalMatcherInterface $final The final matcher that will have to
  111. * pick the route that will be used.
  112. *
  113. * @return NestedMatcher this object to have a fluent interface
  114. */
  115. public function setFinalMatcher(FinalMatcherInterface $final)
  116. {
  117. $this->finalMatcher = $final;
  118. return $this;
  119. }
  120. /**
  121. * {@inheritdoc}
  122. */
  123. public function matchRequest(Request $request)
  124. {
  125. $collection = $this->routeProvider->getRouteCollectionForRequest($request);
  126. if (!count($collection)) {
  127. throw new ResourceNotFoundException();
  128. }
  129. // Route filters are expected to throw an exception themselves if they
  130. // end up filtering the list down to 0.
  131. foreach ($this->getRouteFilters() as $filter) {
  132. $collection = $filter->filter($collection, $request);
  133. }
  134. $attributes = $this->finalMatcher->finalMatch($collection, $request);
  135. return $attributes;
  136. }
  137. /**
  138. * Sorts the filters and flattens them.
  139. *
  140. * @return RouteFilterInterface[] the filters ordered by priority
  141. */
  142. public function getRouteFilters()
  143. {
  144. if (empty($this->sortedFilters)) {
  145. $this->sortedFilters = $this->sortFilters();
  146. }
  147. return $this->sortedFilters;
  148. }
  149. /**
  150. * Sort filters by priority.
  151. *
  152. * The highest priority number is the highest priority (reverse sorting).
  153. *
  154. * @return RouteFilterInterface[] the sorted filters
  155. */
  156. protected function sortFilters()
  157. {
  158. $sortedFilters = array();
  159. krsort($this->filters);
  160. foreach ($this->filters as $filters) {
  161. $sortedFilters = array_merge($sortedFilters, $filters);
  162. }
  163. return $sortedFilters;
  164. }
  165. }