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