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