Security update to Drupal 8.4.6
[yaffs-website] / vendor / symfony / routing / Route.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 /**
15  * A Route describes a route and its parameters.
16  *
17  * @author Fabien Potencier <fabien@symfony.com>
18  * @author Tobias Schultze <http://tobion.de>
19  */
20 class Route implements \Serializable
21 {
22     /**
23      * @var string
24      */
25     private $path = '/';
26
27     /**
28      * @var string
29      */
30     private $host = '';
31
32     /**
33      * @var array
34      */
35     private $schemes = array();
36
37     /**
38      * @var array
39      */
40     private $methods = array();
41
42     /**
43      * @var array
44      */
45     private $defaults = array();
46
47     /**
48      * @var array
49      */
50     private $requirements = array();
51
52     /**
53      * @var array
54      */
55     private $options = array();
56
57     /**
58      * @var null|CompiledRoute
59      */
60     private $compiled;
61
62     /**
63      * @var string
64      */
65     private $condition = '';
66
67     /**
68      * Constructor.
69      *
70      * Available options:
71      *
72      *  * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
73      *  * utf8:           Whether UTF-8 matching is enforced ot not
74      *
75      * @param string       $path         The path pattern to match
76      * @param array        $defaults     An array of default parameter values
77      * @param array        $requirements An array of requirements for parameters (regexes)
78      * @param array        $options      An array of options
79      * @param string       $host         The host pattern to match
80      * @param string|array $schemes      A required URI scheme or an array of restricted schemes
81      * @param string|array $methods      A required HTTP method or an array of restricted methods
82      * @param string       $condition    A condition that should evaluate to true for the route to match
83      */
84     public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array(), $condition = '')
85     {
86         $this->setPath($path);
87         $this->setDefaults($defaults);
88         $this->setRequirements($requirements);
89         $this->setOptions($options);
90         $this->setHost($host);
91         $this->setSchemes($schemes);
92         $this->setMethods($methods);
93         $this->setCondition($condition);
94     }
95
96     /**
97      * {@inheritdoc}
98      */
99     public function serialize()
100     {
101         return serialize(array(
102             'path' => $this->path,
103             'host' => $this->host,
104             'defaults' => $this->defaults,
105             'requirements' => $this->requirements,
106             'options' => $this->options,
107             'schemes' => $this->schemes,
108             'methods' => $this->methods,
109             'condition' => $this->condition,
110             'compiled' => $this->compiled,
111         ));
112     }
113
114     /**
115      * {@inheritdoc}
116      */
117     public function unserialize($serialized)
118     {
119         $data = unserialize($serialized);
120         $this->path = $data['path'];
121         $this->host = $data['host'];
122         $this->defaults = $data['defaults'];
123         $this->requirements = $data['requirements'];
124         $this->options = $data['options'];
125         $this->schemes = $data['schemes'];
126         $this->methods = $data['methods'];
127
128         if (isset($data['condition'])) {
129             $this->condition = $data['condition'];
130         }
131         if (isset($data['compiled'])) {
132             $this->compiled = $data['compiled'];
133         }
134     }
135
136     /**
137      * Returns the pattern for the path.
138      *
139      * @return string The path pattern
140      */
141     public function getPath()
142     {
143         return $this->path;
144     }
145
146     /**
147      * Sets the pattern for the path.
148      *
149      * This method implements a fluent interface.
150      *
151      * @param string $pattern The path pattern
152      *
153      * @return $this
154      */
155     public function setPath($pattern)
156     {
157         // A pattern must start with a slash and must not have multiple slashes at the beginning because the
158         // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
159         $this->path = '/'.ltrim(trim($pattern), '/');
160         $this->compiled = null;
161
162         return $this;
163     }
164
165     /**
166      * Returns the pattern for the host.
167      *
168      * @return string The host pattern
169      */
170     public function getHost()
171     {
172         return $this->host;
173     }
174
175     /**
176      * Sets the pattern for the host.
177      *
178      * This method implements a fluent interface.
179      *
180      * @param string $pattern The host pattern
181      *
182      * @return $this
183      */
184     public function setHost($pattern)
185     {
186         $this->host = (string) $pattern;
187         $this->compiled = null;
188
189         return $this;
190     }
191
192     /**
193      * Returns the lowercased schemes this route is restricted to.
194      * So an empty array means that any scheme is allowed.
195      *
196      * @return array The schemes
197      */
198     public function getSchemes()
199     {
200         return $this->schemes;
201     }
202
203     /**
204      * Sets the schemes (e.g. 'https') this route is restricted to.
205      * So an empty array means that any scheme is allowed.
206      *
207      * This method implements a fluent interface.
208      *
209      * @param string|array $schemes The scheme or an array of schemes
210      *
211      * @return $this
212      */
213     public function setSchemes($schemes)
214     {
215         $this->schemes = array_map('strtolower', (array) $schemes);
216         $this->compiled = null;
217
218         return $this;
219     }
220
221     /**
222      * Checks if a scheme requirement has been set.
223      *
224      * @param string $scheme
225      *
226      * @return bool true if the scheme requirement exists, otherwise false
227      */
228     public function hasScheme($scheme)
229     {
230         return in_array(strtolower($scheme), $this->schemes, true);
231     }
232
233     /**
234      * Returns the uppercased HTTP methods this route is restricted to.
235      * So an empty array means that any method is allowed.
236      *
237      * @return array The methods
238      */
239     public function getMethods()
240     {
241         return $this->methods;
242     }
243
244     /**
245      * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
246      * So an empty array means that any method is allowed.
247      *
248      * This method implements a fluent interface.
249      *
250      * @param string|array $methods The method or an array of methods
251      *
252      * @return $this
253      */
254     public function setMethods($methods)
255     {
256         $this->methods = array_map('strtoupper', (array) $methods);
257         $this->compiled = null;
258
259         return $this;
260     }
261
262     /**
263      * Returns the options.
264      *
265      * @return array The options
266      */
267     public function getOptions()
268     {
269         return $this->options;
270     }
271
272     /**
273      * Sets the options.
274      *
275      * This method implements a fluent interface.
276      *
277      * @param array $options The options
278      *
279      * @return $this
280      */
281     public function setOptions(array $options)
282     {
283         $this->options = array(
284             'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
285         );
286
287         return $this->addOptions($options);
288     }
289
290     /**
291      * Adds options.
292      *
293      * This method implements a fluent interface.
294      *
295      * @param array $options The options
296      *
297      * @return $this
298      */
299     public function addOptions(array $options)
300     {
301         foreach ($options as $name => $option) {
302             $this->options[$name] = $option;
303         }
304         $this->compiled = null;
305
306         return $this;
307     }
308
309     /**
310      * Sets an option value.
311      *
312      * This method implements a fluent interface.
313      *
314      * @param string $name  An option name
315      * @param mixed  $value The option value
316      *
317      * @return $this
318      */
319     public function setOption($name, $value)
320     {
321         $this->options[$name] = $value;
322         $this->compiled = null;
323
324         return $this;
325     }
326
327     /**
328      * Get an option value.
329      *
330      * @param string $name An option name
331      *
332      * @return mixed The option value or null when not given
333      */
334     public function getOption($name)
335     {
336         return isset($this->options[$name]) ? $this->options[$name] : null;
337     }
338
339     /**
340      * Checks if an option has been set.
341      *
342      * @param string $name An option name
343      *
344      * @return bool true if the option is set, false otherwise
345      */
346     public function hasOption($name)
347     {
348         return array_key_exists($name, $this->options);
349     }
350
351     /**
352      * Returns the defaults.
353      *
354      * @return array The defaults
355      */
356     public function getDefaults()
357     {
358         return $this->defaults;
359     }
360
361     /**
362      * Sets the defaults.
363      *
364      * This method implements a fluent interface.
365      *
366      * @param array $defaults The defaults
367      *
368      * @return $this
369      */
370     public function setDefaults(array $defaults)
371     {
372         $this->defaults = array();
373
374         return $this->addDefaults($defaults);
375     }
376
377     /**
378      * Adds defaults.
379      *
380      * This method implements a fluent interface.
381      *
382      * @param array $defaults The defaults
383      *
384      * @return $this
385      */
386     public function addDefaults(array $defaults)
387     {
388         foreach ($defaults as $name => $default) {
389             $this->defaults[$name] = $default;
390         }
391         $this->compiled = null;
392
393         return $this;
394     }
395
396     /**
397      * Gets a default value.
398      *
399      * @param string $name A variable name
400      *
401      * @return mixed The default value or null when not given
402      */
403     public function getDefault($name)
404     {
405         return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
406     }
407
408     /**
409      * Checks if a default value is set for the given variable.
410      *
411      * @param string $name A variable name
412      *
413      * @return bool true if the default value is set, false otherwise
414      */
415     public function hasDefault($name)
416     {
417         return array_key_exists($name, $this->defaults);
418     }
419
420     /**
421      * Sets a default value.
422      *
423      * @param string $name    A variable name
424      * @param mixed  $default The default value
425      *
426      * @return $this
427      */
428     public function setDefault($name, $default)
429     {
430         $this->defaults[$name] = $default;
431         $this->compiled = null;
432
433         return $this;
434     }
435
436     /**
437      * Returns the requirements.
438      *
439      * @return array The requirements
440      */
441     public function getRequirements()
442     {
443         return $this->requirements;
444     }
445
446     /**
447      * Sets the requirements.
448      *
449      * This method implements a fluent interface.
450      *
451      * @param array $requirements The requirements
452      *
453      * @return $this
454      */
455     public function setRequirements(array $requirements)
456     {
457         $this->requirements = array();
458
459         return $this->addRequirements($requirements);
460     }
461
462     /**
463      * Adds requirements.
464      *
465      * This method implements a fluent interface.
466      *
467      * @param array $requirements The requirements
468      *
469      * @return $this
470      */
471     public function addRequirements(array $requirements)
472     {
473         foreach ($requirements as $key => $regex) {
474             $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
475         }
476         $this->compiled = null;
477
478         return $this;
479     }
480
481     /**
482      * Returns the requirement for the given key.
483      *
484      * @param string $key The key
485      *
486      * @return string|null The regex or null when not given
487      */
488     public function getRequirement($key)
489     {
490         return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
491     }
492
493     /**
494      * Checks if a requirement is set for the given key.
495      *
496      * @param string $key A variable name
497      *
498      * @return bool true if a requirement is specified, false otherwise
499      */
500     public function hasRequirement($key)
501     {
502         return array_key_exists($key, $this->requirements);
503     }
504
505     /**
506      * Sets a requirement for the given key.
507      *
508      * @param string $key   The key
509      * @param string $regex The regex
510      *
511      * @return $this
512      */
513     public function setRequirement($key, $regex)
514     {
515         $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
516         $this->compiled = null;
517
518         return $this;
519     }
520
521     /**
522      * Returns the condition.
523      *
524      * @return string The condition
525      */
526     public function getCondition()
527     {
528         return $this->condition;
529     }
530
531     /**
532      * Sets the condition.
533      *
534      * This method implements a fluent interface.
535      *
536      * @param string $condition The condition
537      *
538      * @return $this
539      */
540     public function setCondition($condition)
541     {
542         $this->condition = (string) $condition;
543         $this->compiled = null;
544
545         return $this;
546     }
547
548     /**
549      * Compiles the route.
550      *
551      * @return CompiledRoute A CompiledRoute instance
552      *
553      * @throws \LogicException If the Route cannot be compiled because the
554      *                         path or host pattern is invalid
555      *
556      * @see RouteCompiler which is responsible for the compilation process
557      */
558     public function compile()
559     {
560         if (null !== $this->compiled) {
561             return $this->compiled;
562         }
563
564         $class = $this->getOption('compiler_class');
565
566         return $this->compiled = $class::compile($this);
567     }
568
569     private function sanitizeRequirement($key, $regex)
570     {
571         if (!is_string($regex)) {
572             throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.', $key));
573         }
574
575         if ('' !== $regex && '^' === $regex[0]) {
576             $regex = (string) substr($regex, 1); // returns false for a single character
577         }
578
579         if ('$' === substr($regex, -1)) {
580             $regex = substr($regex, 0, -1);
581         }
582
583         if ('' === $regex) {
584             throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
585         }
586
587         return $regex;
588     }
589 }