fee2002c9d9bb32a3dff243a8c254016c6538fa0
[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      *
74      * @param string       $path         The path pattern to match
75      * @param array        $defaults     An array of default parameter values
76      * @param array        $requirements An array of requirements for parameters (regexes)
77      * @param array        $options      An array of options
78      * @param string       $host         The host pattern to match
79      * @param string|array $schemes      A required URI scheme or an array of restricted schemes
80      * @param string|array $methods      A required HTTP method or an array of restricted methods
81      * @param string       $condition    A condition that should evaluate to true for the route to match
82      */
83     public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array(), $condition = '')
84     {
85         $this->setPath($path);
86         $this->setDefaults($defaults);
87         $this->setRequirements($requirements);
88         $this->setOptions($options);
89         $this->setHost($host);
90         // The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement.
91         // They can be removed when the BC layer is removed.
92         if ($schemes) {
93             $this->setSchemes($schemes);
94         }
95         if ($methods) {
96             $this->setMethods($methods);
97         }
98         $this->setCondition($condition);
99     }
100
101     /**
102      * {@inheritdoc}
103      */
104     public function serialize()
105     {
106         return serialize(array(
107             'path' => $this->path,
108             'host' => $this->host,
109             'defaults' => $this->defaults,
110             'requirements' => $this->requirements,
111             'options' => $this->options,
112             'schemes' => $this->schemes,
113             'methods' => $this->methods,
114             'condition' => $this->condition,
115             'compiled' => $this->compiled,
116         ));
117     }
118
119     /**
120      * {@inheritdoc}
121      */
122     public function unserialize($serialized)
123     {
124         $data = unserialize($serialized);
125         $this->path = $data['path'];
126         $this->host = $data['host'];
127         $this->defaults = $data['defaults'];
128         $this->requirements = $data['requirements'];
129         $this->options = $data['options'];
130         $this->schemes = $data['schemes'];
131         $this->methods = $data['methods'];
132
133         if (isset($data['condition'])) {
134             $this->condition = $data['condition'];
135         }
136         if (isset($data['compiled'])) {
137             $this->compiled = $data['compiled'];
138         }
139     }
140
141     /**
142      * Returns the pattern for the path.
143      *
144      * @return string The pattern
145      *
146      * @deprecated since version 2.2, to be removed in 3.0. Use getPath instead.
147      */
148     public function getPattern()
149     {
150         @trigger_error('The '.__METHOD__.' method is deprecated since version 2.2 and will be removed in 3.0. Use the getPath() method instead.', E_USER_DEPRECATED);
151
152         return $this->path;
153     }
154
155     /**
156      * Sets the pattern for the path.
157      *
158      * This method implements a fluent interface.
159      *
160      * @param string $pattern The path pattern
161      *
162      * @return $this
163      *
164      * @deprecated since version 2.2, to be removed in 3.0. Use setPath instead.
165      */
166     public function setPattern($pattern)
167     {
168         @trigger_error('The '.__METHOD__.' method is deprecated since version 2.2 and will be removed in 3.0. Use the setPath() method instead.', E_USER_DEPRECATED);
169
170         return $this->setPath($pattern);
171     }
172
173     /**
174      * Returns the pattern for the path.
175      *
176      * @return string The path pattern
177      */
178     public function getPath()
179     {
180         return $this->path;
181     }
182
183     /**
184      * Sets the pattern for the path.
185      *
186      * This method implements a fluent interface.
187      *
188      * @param string $pattern The path pattern
189      *
190      * @return $this
191      */
192     public function setPath($pattern)
193     {
194         // A pattern must start with a slash and must not have multiple slashes at the beginning because the
195         // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
196         $this->path = '/'.ltrim(trim($pattern), '/');
197         $this->compiled = null;
198
199         return $this;
200     }
201
202     /**
203      * Returns the pattern for the host.
204      *
205      * @return string The host pattern
206      */
207     public function getHost()
208     {
209         return $this->host;
210     }
211
212     /**
213      * Sets the pattern for the host.
214      *
215      * This method implements a fluent interface.
216      *
217      * @param string $pattern The host pattern
218      *
219      * @return $this
220      */
221     public function setHost($pattern)
222     {
223         $this->host = (string) $pattern;
224         $this->compiled = null;
225
226         return $this;
227     }
228
229     /**
230      * Returns the lowercased schemes this route is restricted to.
231      * So an empty array means that any scheme is allowed.
232      *
233      * @return array The schemes
234      */
235     public function getSchemes()
236     {
237         return $this->schemes;
238     }
239
240     /**
241      * Sets the schemes (e.g. 'https') this route is restricted to.
242      * So an empty array means that any scheme is allowed.
243      *
244      * This method implements a fluent interface.
245      *
246      * @param string|array $schemes The scheme or an array of schemes
247      *
248      * @return $this
249      */
250     public function setSchemes($schemes)
251     {
252         $this->schemes = array_map('strtolower', (array) $schemes);
253
254         // this is to keep BC and will be removed in a future version
255         if ($this->schemes) {
256             $this->requirements['_scheme'] = implode('|', $this->schemes);
257         } else {
258             unset($this->requirements['_scheme']);
259         }
260
261         $this->compiled = null;
262
263         return $this;
264     }
265
266     /**
267      * Checks if a scheme requirement has been set.
268      *
269      * @param string $scheme
270      *
271      * @return bool true if the scheme requirement exists, otherwise false
272      */
273     public function hasScheme($scheme)
274     {
275         return in_array(strtolower($scheme), $this->schemes, true);
276     }
277
278     /**
279      * Returns the uppercased HTTP methods this route is restricted to.
280      * So an empty array means that any method is allowed.
281      *
282      * @return array The methods
283      */
284     public function getMethods()
285     {
286         return $this->methods;
287     }
288
289     /**
290      * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
291      * So an empty array means that any method is allowed.
292      *
293      * This method implements a fluent interface.
294      *
295      * @param string|array $methods The method or an array of methods
296      *
297      * @return $this
298      */
299     public function setMethods($methods)
300     {
301         $this->methods = array_map('strtoupper', (array) $methods);
302
303         // this is to keep BC and will be removed in a future version
304         if ($this->methods) {
305             $this->requirements['_method'] = implode('|', $this->methods);
306         } else {
307             unset($this->requirements['_method']);
308         }
309
310         $this->compiled = null;
311
312         return $this;
313     }
314
315     /**
316      * Returns the options.
317      *
318      * @return array The options
319      */
320     public function getOptions()
321     {
322         return $this->options;
323     }
324
325     /**
326      * Sets the options.
327      *
328      * This method implements a fluent interface.
329      *
330      * @param array $options The options
331      *
332      * @return $this
333      */
334     public function setOptions(array $options)
335     {
336         $this->options = array(
337             'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
338         );
339
340         return $this->addOptions($options);
341     }
342
343     /**
344      * Adds options.
345      *
346      * This method implements a fluent interface.
347      *
348      * @param array $options The options
349      *
350      * @return $this
351      */
352     public function addOptions(array $options)
353     {
354         foreach ($options as $name => $option) {
355             $this->options[$name] = $option;
356         }
357         $this->compiled = null;
358
359         return $this;
360     }
361
362     /**
363      * Sets an option value.
364      *
365      * This method implements a fluent interface.
366      *
367      * @param string $name  An option name
368      * @param mixed  $value The option value
369      *
370      * @return $this
371      */
372     public function setOption($name, $value)
373     {
374         $this->options[$name] = $value;
375         $this->compiled = null;
376
377         return $this;
378     }
379
380     /**
381      * Get an option value.
382      *
383      * @param string $name An option name
384      *
385      * @return mixed The option value or null when not given
386      */
387     public function getOption($name)
388     {
389         return isset($this->options[$name]) ? $this->options[$name] : null;
390     }
391
392     /**
393      * Checks if an option has been set.
394      *
395      * @param string $name An option name
396      *
397      * @return bool true if the option is set, false otherwise
398      */
399     public function hasOption($name)
400     {
401         return array_key_exists($name, $this->options);
402     }
403
404     /**
405      * Returns the defaults.
406      *
407      * @return array The defaults
408      */
409     public function getDefaults()
410     {
411         return $this->defaults;
412     }
413
414     /**
415      * Sets the defaults.
416      *
417      * This method implements a fluent interface.
418      *
419      * @param array $defaults The defaults
420      *
421      * @return $this
422      */
423     public function setDefaults(array $defaults)
424     {
425         $this->defaults = array();
426
427         return $this->addDefaults($defaults);
428     }
429
430     /**
431      * Adds defaults.
432      *
433      * This method implements a fluent interface.
434      *
435      * @param array $defaults The defaults
436      *
437      * @return $this
438      */
439     public function addDefaults(array $defaults)
440     {
441         foreach ($defaults as $name => $default) {
442             $this->defaults[$name] = $default;
443         }
444         $this->compiled = null;
445
446         return $this;
447     }
448
449     /**
450      * Gets a default value.
451      *
452      * @param string $name A variable name
453      *
454      * @return mixed The default value or null when not given
455      */
456     public function getDefault($name)
457     {
458         return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
459     }
460
461     /**
462      * Checks if a default value is set for the given variable.
463      *
464      * @param string $name A variable name
465      *
466      * @return bool true if the default value is set, false otherwise
467      */
468     public function hasDefault($name)
469     {
470         return array_key_exists($name, $this->defaults);
471     }
472
473     /**
474      * Sets a default value.
475      *
476      * @param string $name    A variable name
477      * @param mixed  $default The default value
478      *
479      * @return $this
480      */
481     public function setDefault($name, $default)
482     {
483         $this->defaults[$name] = $default;
484         $this->compiled = null;
485
486         return $this;
487     }
488
489     /**
490      * Returns the requirements.
491      *
492      * @return array The requirements
493      */
494     public function getRequirements()
495     {
496         return $this->requirements;
497     }
498
499     /**
500      * Sets the requirements.
501      *
502      * This method implements a fluent interface.
503      *
504      * @param array $requirements The requirements
505      *
506      * @return $this
507      */
508     public function setRequirements(array $requirements)
509     {
510         $this->requirements = array();
511
512         return $this->addRequirements($requirements);
513     }
514
515     /**
516      * Adds requirements.
517      *
518      * This method implements a fluent interface.
519      *
520      * @param array $requirements The requirements
521      *
522      * @return $this
523      */
524     public function addRequirements(array $requirements)
525     {
526         foreach ($requirements as $key => $regex) {
527             $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
528         }
529         $this->compiled = null;
530
531         return $this;
532     }
533
534     /**
535      * Returns the requirement for the given key.
536      *
537      * @param string $key The key
538      *
539      * @return string|null The regex or null when not given
540      */
541     public function getRequirement($key)
542     {
543         if ('_scheme' === $key) {
544             @trigger_error('The "_scheme" requirement is deprecated since version 2.2 and will be removed in 3.0. Use getSchemes() instead.', E_USER_DEPRECATED);
545         } elseif ('_method' === $key) {
546             @trigger_error('The "_method" requirement is deprecated since version 2.2 and will be removed in 3.0. Use getMethods() instead.', E_USER_DEPRECATED);
547         }
548
549         return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
550     }
551
552     /**
553      * Checks if a requirement is set for the given key.
554      *
555      * @param string $key A variable name
556      *
557      * @return bool true if a requirement is specified, false otherwise
558      */
559     public function hasRequirement($key)
560     {
561         return array_key_exists($key, $this->requirements);
562     }
563
564     /**
565      * Sets a requirement for the given key.
566      *
567      * @param string $key   The key
568      * @param string $regex The regex
569      *
570      * @return $this
571      */
572     public function setRequirement($key, $regex)
573     {
574         $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
575         $this->compiled = null;
576
577         return $this;
578     }
579
580     /**
581      * Returns the condition.
582      *
583      * @return string The condition
584      */
585     public function getCondition()
586     {
587         return $this->condition;
588     }
589
590     /**
591      * Sets the condition.
592      *
593      * This method implements a fluent interface.
594      *
595      * @param string $condition The condition
596      *
597      * @return $this
598      */
599     public function setCondition($condition)
600     {
601         $this->condition = (string) $condition;
602         $this->compiled = null;
603
604         return $this;
605     }
606
607     /**
608      * Compiles the route.
609      *
610      * @return CompiledRoute A CompiledRoute instance
611      *
612      * @throws \LogicException If the Route cannot be compiled because the
613      *                         path or host pattern is invalid
614      *
615      * @see RouteCompiler which is responsible for the compilation process
616      */
617     public function compile()
618     {
619         if (null !== $this->compiled) {
620             return $this->compiled;
621         }
622
623         $class = $this->getOption('compiler_class');
624
625         return $this->compiled = $class::compile($this);
626     }
627
628     private function sanitizeRequirement($key, $regex)
629     {
630         if (!is_string($regex)) {
631             throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.', $key));
632         }
633
634         if ('' !== $regex && '^' === $regex[0]) {
635             $regex = (string) substr($regex, 1); // returns false for a single character
636         }
637
638         if ('$' === substr($regex, -1)) {
639             $regex = substr($regex, 0, -1);
640         }
641
642         if ('' === $regex) {
643             throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
644         }
645
646         // this is to keep BC and will be removed in a future version
647         if ('_scheme' === $key) {
648             @trigger_error('The "_scheme" requirement is deprecated since version 2.2 and will be removed in 3.0. Use the setSchemes() method instead.', E_USER_DEPRECATED);
649
650             $this->setSchemes(explode('|', $regex));
651         } elseif ('_method' === $key) {
652             @trigger_error('The "_method" requirement is deprecated since version 2.2 and will be removed in 3.0. Use the setMethods() method instead.', E_USER_DEPRECATED);
653
654             $this->setMethods(explode('|', $regex));
655         }
656
657         return $regex;
658     }
659 }