Yaffs site version 1.1
[yaffs-website] / vendor / symfony / routing / RouteCollectionBuilder.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
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\Component\Routing;
13
14 use Symfony\Component\Config\Exception\FileLoaderLoadException;
15 use Symfony\Component\Config\Loader\LoaderInterface;
16 use Symfony\Component\Config\Resource\ResourceInterface;
17
18 /**
19  * Helps add and import routes into a RouteCollection.
20  *
21  * @author Ryan Weaver <ryan@knpuniversity.com>
22  */
23 class RouteCollectionBuilder
24 {
25     /**
26      * @var Route[]|RouteCollectionBuilder[]
27      */
28     private $routes = array();
29
30     private $loader;
31     private $defaults = array();
32     private $prefix;
33     private $host;
34     private $condition;
35     private $requirements = array();
36     private $options = array();
37     private $schemes;
38     private $methods;
39     private $resources = array();
40
41     /**
42      * @param LoaderInterface $loader
43      */
44     public function __construct(LoaderInterface $loader = null)
45     {
46         $this->loader = $loader;
47     }
48
49     /**
50      * Import an external routing resource and returns the RouteCollectionBuilder.
51      *
52      *  $routes->import('blog.yml', '/blog');
53      *
54      * @param mixed       $resource
55      * @param string|null $prefix
56      * @param string      $type
57      *
58      * @return self
59      *
60      * @throws FileLoaderLoadException
61      */
62     public function import($resource, $prefix = '/', $type = null)
63     {
64         /** @var RouteCollection $collection */
65         $collection = $this->load($resource, $type);
66
67         // create a builder from the RouteCollection
68         $builder = $this->createBuilder();
69         foreach ($collection->all() as $name => $route) {
70             $builder->addRoute($route, $name);
71         }
72
73         foreach ($collection->getResources() as $resource) {
74             $builder->addResource($resource);
75         }
76
77         // mount into this builder
78         $this->mount($prefix, $builder);
79
80         return $builder;
81     }
82
83     /**
84      * Adds a route and returns it for future modification.
85      *
86      * @param string      $path       The route path
87      * @param string      $controller The route's controller
88      * @param string|null $name       The name to give this route
89      *
90      * @return Route
91      */
92     public function add($path, $controller, $name = null)
93     {
94         $route = new Route($path);
95         $route->setDefault('_controller', $controller);
96         $this->addRoute($route, $name);
97
98         return $route;
99     }
100
101     /**
102      * Returns a RouteCollectionBuilder that can be configured and then added with mount().
103      *
104      * @return self
105      */
106     public function createBuilder()
107     {
108         return new self($this->loader);
109     }
110
111     /**
112      * Add a RouteCollectionBuilder.
113      *
114      * @param string                 $prefix
115      * @param RouteCollectionBuilder $builder
116      */
117     public function mount($prefix, RouteCollectionBuilder $builder)
118     {
119         $builder->prefix = trim(trim($prefix), '/');
120         $this->routes[] = $builder;
121     }
122
123     /**
124      * Adds a Route object to the builder.
125      *
126      * @param Route       $route
127      * @param string|null $name
128      *
129      * @return $this
130      */
131     public function addRoute(Route $route, $name = null)
132     {
133         if (null === $name) {
134             // used as a flag to know which routes will need a name later
135             $name = '_unnamed_route_'.spl_object_hash($route);
136         }
137
138         $this->routes[$name] = $route;
139
140         return $this;
141     }
142
143     /**
144      * Sets the host on all embedded routes (unless already set).
145      *
146      * @param string $pattern
147      *
148      * @return $this
149      */
150     public function setHost($pattern)
151     {
152         $this->host = $pattern;
153
154         return $this;
155     }
156
157     /**
158      * Sets a condition on all embedded routes (unless already set).
159      *
160      * @param string $condition
161      *
162      * @return $this
163      */
164     public function setCondition($condition)
165     {
166         $this->condition = $condition;
167
168         return $this;
169     }
170
171     /**
172      * Sets a default value that will be added to all embedded routes (unless that
173      * default value is already set).
174      *
175      * @param string $key
176      * @param mixed  $value
177      *
178      * @return $this
179      */
180     public function setDefault($key, $value)
181     {
182         $this->defaults[$key] = $value;
183
184         return $this;
185     }
186
187     /**
188      * Sets a requirement that will be added to all embedded routes (unless that
189      * requirement is already set).
190      *
191      * @param string $key
192      * @param mixed  $regex
193      *
194      * @return $this
195      */
196     public function setRequirement($key, $regex)
197     {
198         $this->requirements[$key] = $regex;
199
200         return $this;
201     }
202
203     /**
204      * Sets an opiton that will be added to all embedded routes (unless that
205      * option is already set).
206      *
207      * @param string $key
208      * @param mixed  $value
209      *
210      * @return $this
211      */
212     public function setOption($key, $value)
213     {
214         $this->options[$key] = $value;
215
216         return $this;
217     }
218
219     /**
220      * Sets the schemes on all embedded routes (unless already set).
221      *
222      * @param array|string $schemes
223      *
224      * @return $this
225      */
226     public function setSchemes($schemes)
227     {
228         $this->schemes = $schemes;
229
230         return $this;
231     }
232
233     /**
234      * Sets the methods on all embedded routes (unless already set).
235      *
236      * @param array|string $methods
237      *
238      * @return $this
239      */
240     public function setMethods($methods)
241     {
242         $this->methods = $methods;
243
244         return $this;
245     }
246
247     /**
248      * Adds a resource for this collection.
249      *
250      * @param ResourceInterface $resource
251      *
252      * @return $this
253      */
254     private function addResource(ResourceInterface $resource)
255     {
256         $this->resources[] = $resource;
257
258         return $this;
259     }
260
261     /**
262      * Creates the final RouteCollection and returns it.
263      *
264      * @return RouteCollection
265      */
266     public function build()
267     {
268         $routeCollection = new RouteCollection();
269
270         foreach ($this->routes as $name => $route) {
271             if ($route instanceof Route) {
272                 $route->setDefaults(array_merge($this->defaults, $route->getDefaults()));
273                 $route->setOptions(array_merge($this->options, $route->getOptions()));
274
275                 // we're extra careful here to avoid re-setting deprecated _method and _scheme
276                 foreach ($this->requirements as $key => $val) {
277                     if (!$route->hasRequirement($key)) {
278                         $route->setRequirement($key, $val);
279                     }
280                 }
281
282                 if (null !== $this->prefix) {
283                     $route->setPath('/'.$this->prefix.$route->getPath());
284                 }
285
286                 if (!$route->getHost()) {
287                     $route->setHost($this->host);
288                 }
289
290                 if (!$route->getCondition()) {
291                     $route->setCondition($this->condition);
292                 }
293
294                 if (!$route->getSchemes()) {
295                     $route->setSchemes($this->schemes);
296                 }
297
298                 if (!$route->getMethods()) {
299                     $route->setMethods($this->methods);
300                 }
301
302                 // auto-generate the route name if it's been marked
303                 if ('_unnamed_route_' === substr($name, 0, 15)) {
304                     $name = $this->generateRouteName($route);
305                 }
306
307                 $routeCollection->add($name, $route);
308             } else {
309                 /* @var self $route */
310                 $subCollection = $route->build();
311                 $subCollection->addPrefix($this->prefix);
312
313                 $routeCollection->addCollection($subCollection);
314             }
315
316             foreach ($this->resources as $resource) {
317                 $routeCollection->addResource($resource);
318             }
319         }
320
321         return $routeCollection;
322     }
323
324     /**
325      * Generates a route name based on details of this route.
326      *
327      * @return string
328      */
329     private function generateRouteName(Route $route)
330     {
331         $methods = implode('_', $route->getMethods()).'_';
332
333         $routeName = $methods.$route->getPath();
334         $routeName = str_replace(array('/', ':', '|', '-'), '_', $routeName);
335         $routeName = preg_replace('/[^a-z0-9A-Z_.]+/', '', $routeName);
336
337         // Collapse consecutive underscores down into a single underscore.
338         $routeName = preg_replace('/_+/', '_', $routeName);
339
340         return $routeName;
341     }
342
343     /**
344      * Finds a loader able to load an imported resource and loads it.
345      *
346      * @param mixed       $resource A resource
347      * @param string|null $type     The resource type or null if unknown
348      *
349      * @return RouteCollection
350      *
351      * @throws FileLoaderLoadException If no loader is found
352      */
353     private function load($resource, $type = null)
354     {
355         if (null === $this->loader) {
356             throw new \BadMethodCallException('Cannot import other routing resources: you must pass a LoaderInterface when constructing RouteCollectionBuilder.');
357         }
358
359         if ($this->loader->supports($resource, $type)) {
360             return $this->loader->load($resource, $type);
361         }
362
363         if (null === $resolver = $this->loader->getResolver()) {
364             throw new FileLoaderLoadException($resource);
365         }
366
367         if (false === $loader = $resolver->resolve($resource, $type)) {
368             throw new FileLoaderLoadException($resource);
369         }
370
371         return $loader->load($resource, $type);
372     }
373 }