aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/symfony/routing
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/symfony/routing')
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/.gitignore4
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php156
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md162
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php134
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php46
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php24
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php25
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php55
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php45
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php41
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php123
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php322
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php87
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/LICENSE19
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php246
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php77
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php122
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php52
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php62
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php238
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php212
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd64
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php94
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php252
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php159
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php108
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php64
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php45
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php37
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php378
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php61
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php35
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php39
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php121
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php208
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php43
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/README.md34
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php315
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php36
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Route.php594
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php271
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php233
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php32
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Router.php289
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php32
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php49
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php26
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php16
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php19
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php16
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php26
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php30
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache163
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php310
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache7
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php340
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php43
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml0
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml2
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml8
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml8
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml13
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml11
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml1
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml1
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml8
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml13
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml2
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php23
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml21
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml17
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml12
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml7
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml3
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php117
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php635
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php38
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php119
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php53
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php47
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php55
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php55
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php127
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php113
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php137
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php196
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php33
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php123
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php261
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php58
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php66
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php383
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php255
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php253
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php192
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php138
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/composer.json42
-rw-r--r--vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist29
107 files changed, 10594 insertions, 0 deletions
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/.gitignore b/vendor/symfony/routing/Symfony/Component/Routing/.gitignore
new file mode 100644
index 00000000..44de97a3
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/.gitignore
@@ -0,0 +1,4 @@
1vendor/
2composer.lock
3phpunit.xml
4
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php b/vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php
new file mode 100644
index 00000000..abdbea27
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php
@@ -0,0 +1,156 @@
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
12namespace Symfony\Component\Routing\Annotation;
13
14/**
15 * Annotation class for @Route().
16 *
17 * @Annotation
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21class Route
22{
23 private $path;
24 private $name;
25 private $requirements;
26 private $options;
27 private $defaults;
28 private $host;
29 private $methods;
30 private $schemes;
31
32 /**
33 * Constructor.
34 *
35 * @param array $data An array of key/value parameters.
36 *
37 * @throws \BadMethodCallException
38 */
39 public function __construct(array $data)
40 {
41 $this->requirements = array();
42 $this->options = array();
43 $this->defaults = array();
44 $this->methods = array();
45 $this->schemes = array();
46
47 if (isset($data['value'])) {
48 $data['path'] = $data['value'];
49 unset($data['value']);
50 }
51
52 foreach ($data as $key => $value) {
53 $method = 'set'.str_replace('_', '', $key);
54 if (!method_exists($this, $method)) {
55 throw new \BadMethodCallException(sprintf("Unknown property '%s' on annotation '%s'.", $key, get_class($this)));
56 }
57 $this->$method($value);
58 }
59 }
60
61 /**
62 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
63 */
64 public function setPattern($pattern)
65 {
66 $this->path = $pattern;
67 }
68
69 /**
70 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
71 */
72 public function getPattern()
73 {
74 return $this->path;
75 }
76
77 public function setPath($path)
78 {
79 $this->path = $path;
80 }
81
82 public function getPath()
83 {
84 return $this->path;
85 }
86
87 public function setHost($pattern)
88 {
89 $this->host = $pattern;
90 }
91
92 public function getHost()
93 {
94 return $this->host;
95 }
96
97 public function setName($name)
98 {
99 $this->name = $name;
100 }
101
102 public function getName()
103 {
104 return $this->name;
105 }
106
107 public function setRequirements($requirements)
108 {
109 $this->requirements = $requirements;
110 }
111
112 public function getRequirements()
113 {
114 return $this->requirements;
115 }
116
117 public function setOptions($options)
118 {
119 $this->options = $options;
120 }
121
122 public function getOptions()
123 {
124 return $this->options;
125 }
126
127 public function setDefaults($defaults)
128 {
129 $this->defaults = $defaults;
130 }
131
132 public function getDefaults()
133 {
134 return $this->defaults;
135 }
136
137 public function setSchemes($schemes)
138 {
139 $this->schemes = is_array($schemes) ? $schemes : array($schemes);
140 }
141
142 public function getSchemes()
143 {
144 return $this->schemes;
145 }
146
147 public function setMethods($methods)
148 {
149 $this->methods = is_array($methods) ? $methods : array($methods);
150 }
151
152 public function getMethods()
153 {
154 return $this->methods;
155 }
156}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md b/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md
new file mode 100644
index 00000000..f0c616d0
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md
@@ -0,0 +1,162 @@
1CHANGELOG
2=========
3
42.3.0
5-----
6
7 * added RequestContext::getQueryString()
8
92.2.0
10-----
11
12 * [DEPRECATION] Several route settings have been renamed (the old ones will be removed in 3.0):
13
14 * The `pattern` setting for a route has been deprecated in favor of `path`
15 * The `_scheme` and `_method` requirements have been moved to the `schemes` and `methods` settings
16
17 Before:
18
19 ```
20 article_edit:
21 pattern: /article/{id}
22 requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' }
23
24 <route id="article_edit" pattern="/article/{id}">
25 <requirement key="_method">POST|PUT</requirement>
26 <requirement key="_scheme">https</requirement>
27 <requirement key="id">\d+</requirement>
28 </route>
29
30 $route = new Route();
31 $route->setPattern('/article/{id}');
32 $route->setRequirement('_method', 'POST|PUT');
33 $route->setRequirement('_scheme', 'https');
34 ```
35
36 After:
37
38 ```
39 article_edit:
40 path: /article/{id}
41 methods: [POST, PUT]
42 schemes: https
43 requirements: { 'id': '\d+' }
44
45 <route id="article_edit" pattern="/article/{id}" methods="POST PUT" schemes="https">
46 <requirement key="id">\d+</requirement>
47 </route>
48
49 $route = new Route();
50 $route->setPath('/article/{id}');
51 $route->setMethods(array('POST', 'PUT'));
52 $route->setSchemes('https');
53 ```
54
55 * [BC BREAK] RouteCollection does not behave like a tree structure anymore but as
56 a flat array of Routes. So when using PHP to build the RouteCollection, you must
57 make sure to add routes to the sub-collection before adding it to the parent
58 collection (this is not relevant when using YAML or XML for Route definitions).
59
60 Before:
61
62 ```
63 $rootCollection = new RouteCollection();
64 $subCollection = new RouteCollection();
65 $rootCollection->addCollection($subCollection);
66 $subCollection->add('foo', new Route('/foo'));
67 ```
68
69 After:
70
71 ```
72 $rootCollection = new RouteCollection();
73 $subCollection = new RouteCollection();
74 $subCollection->add('foo', new Route('/foo'));
75 $rootCollection->addCollection($subCollection);
76 ```
77
78 Also one must call `addCollection` from the bottom to the top hierarchy.
79 So the correct sequence is the following (and not the reverse):
80
81 ```
82 $childCollection->->addCollection($grandchildCollection);
83 $rootCollection->addCollection($childCollection);
84 ```
85
86 * [DEPRECATION] The methods `RouteCollection::getParent()` and `RouteCollection::getRoot()`
87 have been deprecated and will be removed in Symfony 2.3.
88 * [BC BREAK] Misusing the `RouteCollection::addPrefix` method to add defaults, requirements
89 or options without adding a prefix is not supported anymore. So if you called `addPrefix`
90 with an empty prefix or `/` only (both have no relevance), like
91 `addPrefix('', $defaultsArray, $requirementsArray, $optionsArray)`
92 you need to use the new dedicated methods `addDefaults($defaultsArray)`,
93 `addRequirements($requirementsArray)` or `addOptions($optionsArray)` instead.
94 * [DEPRECATION] The `$options` parameter to `RouteCollection::addPrefix()` has been deprecated
95 because adding options has nothing to do with adding a path prefix. If you want to add options
96 to all child routes of a RouteCollection, you can use `addOptions()`.
97 * [DEPRECATION] The method `RouteCollection::getPrefix()` has been deprecated
98 because it suggested that all routes in the collection would have this prefix, which is
99 not necessarily true. On top of that, since there is no tree structure anymore, this method
100 is also useless. Don't worry about performance, prefix optimization for matching is still done
101 in the dumper, which was also improved in 2.2.0 to find even more grouping possibilities.
102 * [DEPRECATION] `RouteCollection::addCollection(RouteCollection $collection)` should now only be
103 used with a single parameter. The other params `$prefix`, `$default`, `$requirements` and `$options`
104 will still work, but have been deprecated. The `addPrefix` method should be used for this
105 use-case instead.
106 Before: `$parentCollection->addCollection($collection, '/prefix', array(...), array(...))`
107 After:
108 ```
109 $collection->addPrefix('/prefix', array(...), array(...));
110 $parentCollection->addCollection($collection);
111 ```
112 * added support for the method default argument values when defining a @Route
113 * Adjacent placeholders without separator work now, e.g. `/{x}{y}{z}.{_format}`.
114 * Characters that function as separator between placeholders are now whitelisted
115 to fix routes with normal text around a variable, e.g. `/prefix{var}suffix`.
116 * [BC BREAK] The default requirement of a variable has been changed slightly.
117 Previously it disallowed the previous and the next char around a variable. Now
118 it disallows the slash (`/`) and the next char. Using the previous char added
119 no value and was problematic because the route `/index.{_format}` would be
120 matched by `/index.ht/ml`.
121 * The default requirement now uses possessive quantifiers when possible which
122 improves matching performance by up to 20% because it prevents backtracking
123 when it's not needed.
124 * The ConfigurableRequirementsInterface can now also be used to disable the requirements
125 check on URL generation completely by calling `setStrictRequirements(null)`. It
126 improves performance in production environment as you should know that params always
127 pass the requirements (otherwise it would break your link anyway).
128 * There is no restriction on the route name anymore. So non-alphanumeric characters
129 are now also allowed.
130 * [BC BREAK] `RouteCompilerInterface::compile(Route $route)` was made static
131 (only relevant if you implemented your own RouteCompiler).
132 * Added possibility to generate relative paths and network paths in the UrlGenerator, e.g.
133 "../parent-file" and "//example.com/dir/file". The third parameter in
134 `UrlGeneratorInterface::generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)`
135 now accepts more values and you should use the constants defined in `UrlGeneratorInterface` for
136 claritiy. The old method calls with a Boolean parameter will continue to work because they
137 equal the signature using the constants.
138
1392.1.0
140-----
141
142 * added RequestMatcherInterface
143 * added RequestContext::fromRequest()
144 * the UrlMatcher does not throw a \LogicException anymore when the required
145 scheme is not the current one
146 * added TraceableUrlMatcher
147 * added the possibility to define options, default values and requirements
148 for placeholders in prefix, including imported routes
149 * added RouterInterface::getRouteCollection
150 * [BC BREAK] the UrlMatcher urldecodes the route parameters only once, they
151 were decoded twice before. Note that the `urldecode()` calls have been
152 changed for a single `rawurldecode()` in order to support `+` for input
153 paths.
154 * added RouteCollection::getRoot method to retrieve the root of a
155 RouteCollection tree
156 * [BC BREAK] made RouteCollection::setParent private which could not have
157 been used anyway without creating inconsistencies
158 * [BC BREAK] RouteCollection::remove also removes a route from parent
159 collections (not only from its children)
160 * added ConfigurableRequirementsInterface that allows to disable exceptions
161 (and generate empty URLs instead) when generating a route with an invalid
162 parameter value
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php b/vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php
new file mode 100644
index 00000000..78784554
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php
@@ -0,0 +1,134 @@
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
12namespace Symfony\Component\Routing;
13
14/**
15 * CompiledRoutes are returned by the RouteCompiler class.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19class CompiledRoute
20{
21 private $variables;
22 private $tokens;
23 private $staticPrefix;
24 private $regex;
25 private $pathVariables;
26 private $hostVariables;
27 private $hostRegex;
28 private $hostTokens;
29
30 /**
31 * Constructor.
32 *
33 * @param string $staticPrefix The static prefix of the compiled route
34 * @param string $regex The regular expression to use to match this route
35 * @param array $tokens An array of tokens to use to generate URL for this route
36 * @param array $pathVariables An array of path variables
37 * @param string|null $hostRegex Host regex
38 * @param array $hostTokens Host tokens
39 * @param array $hostVariables An array of host variables
40 * @param array $variables An array of variables (variables defined in the path and in the host patterns)
41 */
42 public function __construct($staticPrefix, $regex, array $tokens, array $pathVariables, $hostRegex = null, array $hostTokens = array(), array $hostVariables = array(), array $variables = array())
43 {
44 $this->staticPrefix = (string) $staticPrefix;
45 $this->regex = $regex;
46 $this->tokens = $tokens;
47 $this->pathVariables = $pathVariables;
48 $this->hostRegex = $hostRegex;
49 $this->hostTokens = $hostTokens;
50 $this->hostVariables = $hostVariables;
51 $this->variables = $variables;
52 }
53
54 /**
55 * Returns the static prefix.
56 *
57 * @return string The static prefix
58 */
59 public function getStaticPrefix()
60 {
61 return $this->staticPrefix;
62 }
63
64 /**
65 * Returns the regex.
66 *
67 * @return string The regex
68 */
69 public function getRegex()
70 {
71 return $this->regex;
72 }
73
74 /**
75 * Returns the host regex
76 *
77 * @return string|null The host regex or null
78 */
79 public function getHostRegex()
80 {
81 return $this->hostRegex;
82 }
83
84 /**
85 * Returns the tokens.
86 *
87 * @return array The tokens
88 */
89 public function getTokens()
90 {
91 return $this->tokens;
92 }
93
94 /**
95 * Returns the host tokens.
96 *
97 * @return array The tokens
98 */
99 public function getHostTokens()
100 {
101 return $this->hostTokens;
102 }
103
104 /**
105 * Returns the variables.
106 *
107 * @return array The variables
108 */
109 public function getVariables()
110 {
111 return $this->variables;
112 }
113
114 /**
115 * Returns the path variables.
116 *
117 * @return array The variables
118 */
119 public function getPathVariables()
120 {
121 return $this->pathVariables;
122 }
123
124 /**
125 * Returns the host variables.
126 *
127 * @return array The variables
128 */
129 public function getHostVariables()
130 {
131 return $this->hostVariables;
132 }
133
134}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php
new file mode 100644
index 00000000..5289f525
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.php
@@ -0,0 +1,23 @@
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
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * ExceptionInterface
16 *
17 * @author Alexandre Salomé <alexandre.salome@gmail.com>
18 *
19 * @api
20 */
21interface ExceptionInterface
22{
23}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php
new file mode 100644
index 00000000..4f124695
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php
@@ -0,0 +1,23 @@
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
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * Exception thrown when a parameter is not valid
16 *
17 * @author Alexandre Salomé <alexandre.salome@gmail.com>
18 *
19 * @api
20 */
21class InvalidParameterException extends \InvalidArgumentException implements ExceptionInterface
22{
23}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php
new file mode 100644
index 00000000..32f10913
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.php
@@ -0,0 +1,46 @@
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
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * The resource was found but the request method is not allowed.
16 *
17 * This exception should trigger an HTTP 405 response in your application code.
18 *
19 * @author Kris Wallsmith <kris@symfony.com>
20 *
21 * @api
22 */
23class MethodNotAllowedException extends \RuntimeException implements ExceptionInterface
24{
25 /**
26 * @var array
27 */
28 protected $allowedMethods = array();
29
30 public function __construct(array $allowedMethods, $message = null, $code = 0, \Exception $previous = null)
31 {
32 $this->allowedMethods = array_map('strtoupper', $allowedMethods);
33
34 parent::__construct($message, $code, $previous);
35 }
36
37 /**
38 * Gets the allowed HTTP methods.
39 *
40 * @return array
41 */
42 public function getAllowedMethods()
43 {
44 return $this->allowedMethods;
45 }
46}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php
new file mode 100644
index 00000000..5a523fa5
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php
@@ -0,0 +1,24 @@
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
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * Exception thrown when a route cannot be generated because of missing
16 * mandatory parameters.
17 *
18 * @author Alexandre Salomé <alexandre.salome@gmail.com>
19 *
20 * @api
21 */
22class MissingMandatoryParametersException extends \InvalidArgumentException implements ExceptionInterface
23{
24}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php
new file mode 100644
index 00000000..362a0d61
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php
@@ -0,0 +1,25 @@
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
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * The resource was not found.
16 *
17 * This exception should trigger an HTTP 404 response in your application code.
18 *
19 * @author Kris Wallsmith <kris@symfony.com>
20 *
21 * @api
22 */
23class ResourceNotFoundException extends \RuntimeException implements ExceptionInterface
24{
25}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php b/vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php
new file mode 100644
index 00000000..4d5f288e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php
@@ -0,0 +1,23 @@
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
12namespace Symfony\Component\Routing\Exception;
13
14/**
15 * Exception thrown when a route does not exists
16 *
17 * @author Alexandre Salomé <alexandre.salome@gmail.com>
18 *
19 * @api
20 */
21class RouteNotFoundException extends \InvalidArgumentException implements ExceptionInterface
22{
23}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php
new file mode 100644
index 00000000..5925838c
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php
@@ -0,0 +1,55 @@
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
12namespace Symfony\Component\Routing\Generator;
13
14/**
15 * ConfigurableRequirementsInterface must be implemented by URL generators that
16 * can be configured whether an exception should be generated when the parameters
17 * do not match the requirements. It is also possible to disable the requirements
18 * check for URL generation completely.
19 *
20 * The possible configurations and use-cases:
21 * - setStrictRequirements(true): Throw an exception for mismatching requirements. This
22 * is mostly useful in development environment.
23 * - setStrictRequirements(false): Don't throw an exception but return null as URL for
24 * mismatching requirements and log the problem. Useful when you cannot control all
25 * params because they come from third party libs but don't want to have a 404 in
26 * production environment. It should log the mismatch so one can review it.
27 * - setStrictRequirements(null): Return the URL with the given parameters without
28 * checking the requirements at all. When generating an URL you should either trust
29 * your params or you validated them beforehand because otherwise it would break your
30 * link anyway. So in production environment you should know that params always pass
31 * the requirements. Thus this option allows to disable the check on URL generation for
32 * performance reasons (saving a preg_match for each requirement every time a URL is
33 * generated).
34 *
35 * @author Fabien Potencier <fabien@symfony.com>
36 * @author Tobias Schultze <http://tobion.de>
37 */
38interface ConfigurableRequirementsInterface
39{
40 /**
41 * Enables or disables the exception on incorrect parameters.
42 * Passing null will deactivate the requirements check completely.
43 *
44 * @param Boolean|null $enabled
45 */
46 public function setStrictRequirements($enabled);
47
48 /**
49 * Returns whether to throw an exception on incorrect parameters.
50 * Null means the requirements check is deactivated completely.
51 *
52 * @return Boolean|null
53 */
54 public function isStrictRequirements();
55}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php
new file mode 100644
index 00000000..4739bd83
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.php
@@ -0,0 +1,45 @@
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
12namespace Symfony\Component\Routing\Generator\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15
16/**
17 * GeneratorDumper is the base class for all built-in generator dumpers.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21abstract class GeneratorDumper implements GeneratorDumperInterface
22{
23 /**
24 * @var RouteCollection
25 */
26 private $routes;
27
28 /**
29 * Constructor.
30 *
31 * @param RouteCollection $routes The RouteCollection to dump
32 */
33 public function __construct(RouteCollection $routes)
34 {
35 $this->routes = $routes;
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getRoutes()
42 {
43 return $this->routes;
44 }
45}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php
new file mode 100644
index 00000000..deb0c0a2
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.php
@@ -0,0 +1,41 @@
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
12namespace Symfony\Component\Routing\Generator\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15
16/**
17 * GeneratorDumperInterface is the interface that all generator dumper classes must implement.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23interface GeneratorDumperInterface
24{
25 /**
26 * Dumps a set of routes to a string representation of executable code
27 * that can then be used to generate a URL of such a route.
28 *
29 * @param array $options An array of options
30 *
31 * @return string Executable code
32 */
33 public function dump(array $options = array());
34
35 /**
36 * Gets the routes to dump.
37 *
38 * @return RouteCollection A RouteCollection instance
39 */
40 public function getRoutes();
41}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php
new file mode 100644
index 00000000..42cd9108
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php
@@ -0,0 +1,123 @@
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
12namespace Symfony\Component\Routing\Generator\Dumper;
13
14/**
15 * PhpGeneratorDumper creates a PHP class able to generate URLs for a given set of routes.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @author Tobias Schultze <http://tobion.de>
19 *
20 * @api
21 */
22class PhpGeneratorDumper extends GeneratorDumper
23{
24 /**
25 * Dumps a set of routes to a PHP class.
26 *
27 * Available options:
28 *
29 * * class: The class name
30 * * base_class: The base class name
31 *
32 * @param array $options An array of options
33 *
34 * @return string A PHP class representing the generator class
35 *
36 * @api
37 */
38 public function dump(array $options = array())
39 {
40 $options = array_merge(array(
41 'class' => 'ProjectUrlGenerator',
42 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
43 ), $options);
44
45 return <<<EOF
46<?php
47
48use Symfony\Component\Routing\RequestContext;
49use Symfony\Component\Routing\Exception\RouteNotFoundException;
50use Psr\Log\LoggerInterface;
51
52/**
53 * {$options['class']}
54 *
55 * This class has been auto-generated
56 * by the Symfony Routing Component.
57 */
58class {$options['class']} extends {$options['base_class']}
59{
60 static private \$declaredRoutes = {$this->generateDeclaredRoutes()};
61
62 /**
63 * Constructor.
64 */
65 public function __construct(RequestContext \$context, LoggerInterface \$logger = null)
66 {
67 \$this->context = \$context;
68 \$this->logger = \$logger;
69 }
70
71{$this->generateGenerateMethod()}
72}
73
74EOF;
75 }
76
77 /**
78 * Generates PHP code representing an array of defined routes
79 * together with the routes properties (e.g. requirements).
80 *
81 * @return string PHP code
82 */
83 private function generateDeclaredRoutes()
84 {
85 $routes = "array(\n";
86 foreach ($this->getRoutes()->all() as $name => $route) {
87 $compiledRoute = $route->compile();
88
89 $properties = array();
90 $properties[] = $compiledRoute->getVariables();
91 $properties[] = $route->getDefaults();
92 $properties[] = $route->getRequirements();
93 $properties[] = $compiledRoute->getTokens();
94 $properties[] = $compiledRoute->getHostTokens();
95
96 $routes .= sprintf(" '%s' => %s,\n", $name, str_replace("\n", '', var_export($properties, true)));
97 }
98 $routes .= ' )';
99
100 return $routes;
101 }
102
103 /**
104 * Generates PHP code representing the `generate` method that implements the UrlGeneratorInterface.
105 *
106 * @return string PHP code
107 */
108 private function generateGenerateMethod()
109 {
110 return <<<EOF
111 public function generate(\$name, \$parameters = array(), \$referenceType = self::ABSOLUTE_PATH)
112 {
113 if (!isset(self::\$declaredRoutes[\$name])) {
114 throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', \$name));
115 }
116
117 list(\$variables, \$defaults, \$requirements, \$tokens, \$hostTokens) = self::\$declaredRoutes[\$name];
118
119 return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostTokens);
120 }
121EOF;
122 }
123}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
new file mode 100644
index 00000000..f224cb3f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.php
@@ -0,0 +1,322 @@
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
12namespace Symfony\Component\Routing\Generator;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\RequestContext;
16use Symfony\Component\Routing\Exception\InvalidParameterException;
17use Symfony\Component\Routing\Exception\RouteNotFoundException;
18use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
19use Psr\Log\LoggerInterface;
20
21/**
22 * UrlGenerator can generate a URL or a path for any route in the RouteCollection
23 * based on the passed parameters.
24 *
25 * @author Fabien Potencier <fabien@symfony.com>
26 * @author Tobias Schultze <http://tobion.de>
27 *
28 * @api
29 */
30class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInterface
31{
32 /**
33 * @var RouteCollection
34 */
35 protected $routes;
36
37 /**
38 * @var RequestContext
39 */
40 protected $context;
41
42 /**
43 * @var Boolean|null
44 */
45 protected $strictRequirements = true;
46
47 /**
48 * @var LoggerInterface|null
49 */
50 protected $logger;
51
52 /**
53 * This array defines the characters (besides alphanumeric ones) that will not be percent-encoded in the path segment of the generated URL.
54 *
55 * PHP's rawurlencode() encodes all chars except "a-zA-Z0-9-._~" according to RFC 3986. But we want to allow some chars
56 * to be used in their literal form (reasons below). Other chars inside the path must of course be encoded, e.g.
57 * "?" and "#" (would be interpreted wrongly as query and fragment identifier),
58 * "'" and """ (are used as delimiters in HTML).
59 */
60 protected $decodedChars = array(
61 // the slash can be used to designate a hierarchical structure and we want allow using it with this meaning
62 // some webservers don't allow the slash in encoded form in the path for security reasons anyway
63 // see http://stackoverflow.com/questions/4069002/http-400-if-2f-part-of-get-url-in-jboss
64 '%2F' => '/',
65 // the following chars are general delimiters in the URI specification but have only special meaning in the authority component
66 // so they can safely be used in the path in unencoded form
67 '%40' => '@',
68 '%3A' => ':',
69 // these chars are only sub-delimiters that have no predefined meaning and can therefore be used literally
70 // so URI producing applications can use these chars to delimit subcomponents in a path segment without being encoded for better readability
71 '%3B' => ';',
72 '%2C' => ',',
73 '%3D' => '=',
74 '%2B' => '+',
75 '%21' => '!',
76 '%2A' => '*',
77 '%7C' => '|',
78 );
79
80 /**
81 * Constructor.
82 *
83 * @param RouteCollection $routes A RouteCollection instance
84 * @param RequestContext $context The context
85 * @param LoggerInterface|null $logger A logger instance
86 *
87 * @api
88 */
89 public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
90 {
91 $this->routes = $routes;
92 $this->context = $context;
93 $this->logger = $logger;
94 }
95
96 /**
97 * {@inheritdoc}
98 */
99 public function setContext(RequestContext $context)
100 {
101 $this->context = $context;
102 }
103
104 /**
105 * {@inheritdoc}
106 */
107 public function getContext()
108 {
109 return $this->context;
110 }
111
112 /**
113 * {@inheritdoc}
114 */
115 public function setStrictRequirements($enabled)
116 {
117 $this->strictRequirements = null === $enabled ? null : (Boolean) $enabled;
118 }
119
120 /**
121 * {@inheritdoc}
122 */
123 public function isStrictRequirements()
124 {
125 return $this->strictRequirements;
126 }
127
128 /**
129 * {@inheritDoc}
130 */
131 public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
132 {
133 if (null === $route = $this->routes->get($name)) {
134 throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
135 }
136
137 // the Route has a cache of its own and is not recompiled as long as it does not get modified
138 $compiledRoute = $route->compile();
139
140 return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens());
141 }
142
143 /**
144 * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
145 * @throws InvalidParameterException When a parameter value for a placeholder is not correct because
146 * it does not match the requirement
147 */
148 protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens)
149 {
150 $variables = array_flip($variables);
151 $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
152
153 // all params must be given
154 if ($diff = array_diff_key($variables, $mergedParams)) {
155 throw new MissingMandatoryParametersException(sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', array_keys($diff)), $name));
156 }
157
158 $url = '';
159 $optional = true;
160 foreach ($tokens as $token) {
161 if ('variable' === $token[0]) {
162 if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
163 // check requirement
164 if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
165 $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
166 if ($this->strictRequirements) {
167 throw new InvalidParameterException($message);
168 }
169
170 if ($this->logger) {
171 $this->logger->error($message);
172 }
173
174 return null;
175 }
176
177 $url = $token[1].$mergedParams[$token[3]].$url;
178 $optional = false;
179 }
180 } else {
181 // static text
182 $url = $token[1].$url;
183 $optional = false;
184 }
185 }
186
187 if ('' === $url) {
188 $url = '/';
189 }
190
191 // the contexts base url is already encoded (see Symfony\Component\HttpFoundation\Request)
192 $url = strtr(rawurlencode($url), $this->decodedChars);
193
194 // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
195 // so we need to encode them as they are not used for this purpose here
196 // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route
197 $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
198 if ('/..' === substr($url, -3)) {
199 $url = substr($url, 0, -2).'%2E%2E';
200 } elseif ('/.' === substr($url, -2)) {
201 $url = substr($url, 0, -1).'%2E';
202 }
203
204 $schemeAuthority = '';
205 if ($host = $this->context->getHost()) {
206 $scheme = $this->context->getScheme();
207 if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) {
208 $referenceType = self::ABSOLUTE_URL;
209 $scheme = $req;
210 }
211
212 if ($hostTokens) {
213 $routeHost = '';
214 foreach ($hostTokens as $token) {
215 if ('variable' === $token[0]) {
216 if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
217 $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
218
219 if ($this->strictRequirements) {
220 throw new InvalidParameterException($message);
221 }
222
223 if ($this->logger) {
224 $this->logger->error($message);
225 }
226
227 return null;
228 }
229
230 $routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
231 } else {
232 $routeHost = $token[1].$routeHost;
233 }
234 }
235
236 if ($routeHost !== $host) {
237 $host = $routeHost;
238 if (self::ABSOLUTE_URL !== $referenceType) {
239 $referenceType = self::NETWORK_PATH;
240 }
241 }
242 }
243
244 if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
245 $port = '';
246 if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
247 $port = ':'.$this->context->getHttpPort();
248 } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
249 $port = ':'.$this->context->getHttpsPort();
250 }
251
252 $schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://";
253 $schemeAuthority .= $host.$port;
254 }
255 }
256
257 if (self::RELATIVE_PATH === $referenceType) {
258 $url = self::getRelativePath($this->context->getPathInfo(), $url);
259 } else {
260 $url = $schemeAuthority.$this->context->getBaseUrl().$url;
261 }
262
263 // add a query string if needed
264 $extra = array_diff_key($parameters, $variables, $defaults);
265 if ($extra && $query = http_build_query($extra, '', '&')) {
266 $url .= '?'.$query;
267 }
268
269 return $url;
270 }
271
272 /**
273 * Returns the target path as relative reference from the base path.
274 *
275 * Only the URIs path component (no schema, host etc.) is relevant and must be given, starting with a slash.
276 * Both paths must be absolute and not contain relative parts.
277 * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
278 * Furthermore, they can be used to reduce the link size in documents.
279 *
280 * Example target paths, given a base path of "/a/b/c/d":
281 * - "/a/b/c/d" -> ""
282 * - "/a/b/c/" -> "./"
283 * - "/a/b/" -> "../"
284 * - "/a/b/c/other" -> "other"
285 * - "/a/x/y" -> "../../x/y"
286 *
287 * @param string $basePath The base path
288 * @param string $targetPath The target path
289 *
290 * @return string The relative target path
291 */
292 public static function getRelativePath($basePath, $targetPath)
293 {
294 if ($basePath === $targetPath) {
295 return '';
296 }
297
298 $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
299 $targetDirs = explode('/', isset($targetPath[0]) && '/' === $targetPath[0] ? substr($targetPath, 1) : $targetPath);
300 array_pop($sourceDirs);
301 $targetFile = array_pop($targetDirs);
302
303 foreach ($sourceDirs as $i => $dir) {
304 if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
305 unset($sourceDirs[$i], $targetDirs[$i]);
306 } else {
307 break;
308 }
309 }
310
311 $targetDirs[] = $targetFile;
312 $path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
313
314 // A reference to the same base directory or an empty subdirectory must be prefixed with "./".
315 // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
316 // as the first segment of a relative-path reference, as it would be mistaken for a scheme name
317 // (see http://tools.ietf.org/html/rfc3986#section-4.2).
318 return '' === $path || '/' === $path[0]
319 || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
320 ? "./$path" : $path;
321 }
322}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php
new file mode 100644
index 00000000..8e3b2778
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php
@@ -0,0 +1,87 @@
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
12namespace Symfony\Component\Routing\Generator;
13
14use Symfony\Component\Routing\Exception\InvalidParameterException;
15use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
16use Symfony\Component\Routing\Exception\RouteNotFoundException;
17use Symfony\Component\Routing\RequestContextAwareInterface;
18
19/**
20 * UrlGeneratorInterface is the interface that all URL generator classes must implement.
21 *
22 * The constants in this interface define the different types of resource references that
23 * are declared in RFC 3986: http://tools.ietf.org/html/rfc3986
24 * We are using the term "URL" instead of "URI" as this is more common in web applications
25 * and we do not need to distinguish them as the difference is mostly semantical and
26 * less technical. Generating URIs, i.e. representation-independent resource identifiers,
27 * is also possible.
28 *
29 * @author Fabien Potencier <fabien@symfony.com>
30 * @author Tobias Schultze <http://tobion.de>
31 *
32 * @api
33 */
34interface UrlGeneratorInterface extends RequestContextAwareInterface
35{
36 /**
37 * Generates an absolute URL, e.g. "http://example.com/dir/file".
38 */
39 const ABSOLUTE_URL = true;
40
41 /**
42 * Generates an absolute path, e.g. "/dir/file".
43 */
44 const ABSOLUTE_PATH = false;
45
46 /**
47 * Generates a relative path based on the current request path, e.g. "../parent-file".
48 * @see UrlGenerator::getRelativePath()
49 */
50 const RELATIVE_PATH = 'relative';
51
52 /**
53 * Generates a network path, e.g. "//example.com/dir/file".
54 * Such reference reuses the current scheme but specifies the host.
55 */
56 const NETWORK_PATH = 'network';
57
58 /**
59 * Generates a URL or path for a specific route based on the given parameters.
60 *
61 * Parameters that reference placeholders in the route pattern will substitute them in the
62 * path or host. Extra params are added as query string to the URL.
63 *
64 * When the passed reference type cannot be generated for the route because it requires a different
65 * host or scheme than the current one, the method will return a more comprehensive reference
66 * that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH
67 * but the route requires the https scheme whereas the current scheme is http, it will instead return an
68 * ABSOLUTE_URL with the https scheme and the current host. This makes sure the generated URL matches
69 * the route in any case.
70 *
71 * If there is no route with the given name, the generator must throw the RouteNotFoundException.
72 *
73 * @param string $name The name of the route
74 * @param mixed $parameters An array of parameters
75 * @param Boolean|string $referenceType The type of reference to be generated (one of the constants)
76 *
77 * @return string The generated URL
78 *
79 * @throws RouteNotFoundException If the named route doesn't exist
80 * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
81 * @throws InvalidParameterException When a parameter value for a placeholder is not correct because
82 * it does not match the requirement
83 *
84 * @api
85 */
86 public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH);
87}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/LICENSE b/vendor/symfony/routing/Symfony/Component/Routing/LICENSE
new file mode 100644
index 00000000..88a57f8d
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/LICENSE
@@ -0,0 +1,19 @@
1Copyright (c) 2004-2013 Fabien Potencier
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
new file mode 100644
index 00000000..9831d85a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
@@ -0,0 +1,246 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Doctrine\Common\Annotations\Reader;
15use Symfony\Component\Config\Resource\FileResource;
16use Symfony\Component\Routing\Route;
17use Symfony\Component\Routing\RouteCollection;
18use Symfony\Component\Config\Loader\LoaderInterface;
19use Symfony\Component\Config\Loader\LoaderResolverInterface;
20
21/**
22 * AnnotationClassLoader loads routing information from a PHP class and its methods.
23 *
24 * You need to define an implementation for the getRouteDefaults() method. Most of the
25 * time, this method should define some PHP callable to be called for the route
26 * (a controller in MVC speak).
27 *
28 * The @Route annotation can be set on the class (for global parameters),
29 * and on each method.
30 *
31 * The @Route annotation main value is the route path. The annotation also
32 * recognizes several parameters: requirements, options, defaults, schemes,
33 * methods, host, and name. The name parameter is mandatory.
34 * Here is an example of how you should be able to use it:
35 *
36 * /**
37 * * @Route("/Blog")
38 * * /
39 * class Blog
40 * {
41 * /**
42 * * @Route("/", name="blog_index")
43 * * /
44 * public function index()
45 * {
46 * }
47 *
48 * /**
49 * * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
50 * * /
51 * public function show()
52 * {
53 * }
54 * }
55 *
56 * @author Fabien Potencier <fabien@symfony.com>
57 */
58abstract class AnnotationClassLoader implements LoaderInterface
59{
60 /**
61 * @var Reader
62 */
63 protected $reader;
64
65 /**
66 * @var string
67 */
68 protected $routeAnnotationClass = 'Symfony\\Component\\Routing\\Annotation\\Route';
69
70 /**
71 * @var integer
72 */
73 protected $defaultRouteIndex = 0;
74
75 /**
76 * Constructor.
77 *
78 * @param Reader $reader
79 */
80 public function __construct(Reader $reader)
81 {
82 $this->reader = $reader;
83 }
84
85 /**
86 * Sets the annotation class to read route properties from.
87 *
88 * @param string $class A fully-qualified class name
89 */
90 public function setRouteAnnotationClass($class)
91 {
92 $this->routeAnnotationClass = $class;
93 }
94
95 /**
96 * Loads from annotations from a class.
97 *
98 * @param string $class A class name
99 * @param string|null $type The resource type
100 *
101 * @return RouteCollection A RouteCollection instance
102 *
103 * @throws \InvalidArgumentException When route can't be parsed
104 */
105 public function load($class, $type = null)
106 {
107 if (!class_exists($class)) {
108 throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
109 }
110
111 $globals = array(
112 'path' => '',
113 'requirements' => array(),
114 'options' => array(),
115 'defaults' => array(),
116 'schemes' => array(),
117 'methods' => array(),
118 'host' => '',
119 );
120
121 $class = new \ReflectionClass($class);
122 if ($class->isAbstract()) {
123 throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class));
124 }
125
126 if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) {
127 // for BC reasons
128 if (null !== $annot->getPath()) {
129 $globals['path'] = $annot->getPath();
130 } elseif (null !== $annot->getPattern()) {
131 $globals['path'] = $annot->getPattern();
132 }
133
134 if (null !== $annot->getRequirements()) {
135 $globals['requirements'] = $annot->getRequirements();
136 }
137
138 if (null !== $annot->getOptions()) {
139 $globals['options'] = $annot->getOptions();
140 }
141
142 if (null !== $annot->getDefaults()) {
143 $globals['defaults'] = $annot->getDefaults();
144 }
145
146 if (null !== $annot->getSchemes()) {
147 $globals['schemes'] = $annot->getSchemes();
148 }
149
150 if (null !== $annot->getMethods()) {
151 $globals['methods'] = $annot->getMethods();
152 }
153
154 if (null !== $annot->getHost()) {
155 $globals['host'] = $annot->getHost();
156 }
157 }
158
159 $collection = new RouteCollection();
160 $collection->addResource(new FileResource($class->getFileName()));
161
162 foreach ($class->getMethods() as $method) {
163 $this->defaultRouteIndex = 0;
164 foreach ($this->reader->getMethodAnnotations($method) as $annot) {
165 if ($annot instanceof $this->routeAnnotationClass) {
166 $this->addRoute($collection, $annot, $globals, $class, $method);
167 }
168 }
169 }
170
171 return $collection;
172 }
173
174 protected function addRoute(RouteCollection $collection, $annot, $globals, \ReflectionClass $class, \ReflectionMethod $method)
175 {
176 $name = $annot->getName();
177 if (null === $name) {
178 $name = $this->getDefaultRouteName($class, $method);
179 }
180
181 $defaults = array_replace($globals['defaults'], $annot->getDefaults());
182 foreach ($method->getParameters() as $param) {
183 if ($param->isOptional()) {
184 $defaults[$param->getName()] = $param->getDefaultValue();
185 }
186 }
187 $requirements = array_replace($globals['requirements'], $annot->getRequirements());
188 $options = array_replace($globals['options'], $annot->getOptions());
189 $schemes = array_replace($globals['schemes'], $annot->getSchemes());
190 $methods = array_replace($globals['methods'], $annot->getMethods());
191
192 $host = $annot->getHost();
193 if (null === $host) {
194 $host = $globals['host'];
195 }
196
197 $route = new Route($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $host, $schemes, $methods);
198
199 $this->configureRoute($route, $class, $method, $annot);
200
201 $collection->add($name, $route);
202 }
203
204 /**
205 * {@inheritdoc}
206 */
207 public function supports($resource, $type = null)
208 {
209 return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type);
210 }
211
212 /**
213 * {@inheritdoc}
214 */
215 public function setResolver(LoaderResolverInterface $resolver)
216 {
217 }
218
219 /**
220 * {@inheritdoc}
221 */
222 public function getResolver()
223 {
224 }
225
226 /**
227 * Gets the default route name for a class method.
228 *
229 * @param \ReflectionClass $class
230 * @param \ReflectionMethod $method
231 *
232 * @return string
233 */
234 protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method)
235 {
236 $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name);
237 if ($this->defaultRouteIndex > 0) {
238 $name .= '_'.$this->defaultRouteIndex;
239 }
240 $this->defaultRouteIndex++;
241
242 return $name;
243 }
244
245 abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot);
246}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
new file mode 100644
index 00000000..abd68ed6
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
@@ -0,0 +1,77 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Config\Resource\DirectoryResource;
16
17/**
18 * AnnotationDirectoryLoader loads routing information from annotations set
19 * on PHP classes and methods.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23class AnnotationDirectoryLoader extends AnnotationFileLoader
24{
25 /**
26 * Loads from annotations from a directory.
27 *
28 * @param string $path A directory path
29 * @param string|null $type The resource type
30 *
31 * @return RouteCollection A RouteCollection instance
32 *
33 * @throws \InvalidArgumentException When the directory does not exist or its routes cannot be parsed
34 */
35 public function load($path, $type = null)
36 {
37 $dir = $this->locator->locate($path);
38
39 $collection = new RouteCollection();
40 $collection->addResource(new DirectoryResource($dir, '/\.php$/'));
41 $files = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY));
42 usort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
43 return (string) $a > (string) $b ? 1 : -1;
44 });
45
46 foreach ($files as $file) {
47 if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) {
48 continue;
49 }
50
51 if ($class = $this->findClass($file)) {
52 $refl = new \ReflectionClass($class);
53 if ($refl->isAbstract()) {
54 continue;
55 }
56
57 $collection->addCollection($this->loader->load($class, $type));
58 }
59 }
60
61 return $collection;
62 }
63
64 /**
65 * {@inheritdoc}
66 */
67 public function supports($resource, $type = null)
68 {
69 try {
70 $path = $this->locator->locate($resource);
71 } catch (\Exception $e) {
72 return false;
73 }
74
75 return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type);
76 }
77}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
new file mode 100644
index 00000000..33776fdc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
@@ -0,0 +1,122 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Config\Resource\FileResource;
16use Symfony\Component\Config\Loader\FileLoader;
17use Symfony\Component\Config\FileLocatorInterface;
18
19/**
20 * AnnotationFileLoader loads routing information from annotations set
21 * on a PHP class and its methods.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 */
25class AnnotationFileLoader extends FileLoader
26{
27 protected $loader;
28
29 /**
30 * Constructor.
31 *
32 * @param FileLocatorInterface $locator A FileLocator instance
33 * @param AnnotationClassLoader $loader An AnnotationClassLoader instance
34 * @param string|array $paths A path or an array of paths where to look for resources
35 *
36 * @throws \RuntimeException
37 */
38 public function __construct(FileLocatorInterface $locator, AnnotationClassLoader $loader, $paths = array())
39 {
40 if (!function_exists('token_get_all')) {
41 throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.');
42 }
43
44 parent::__construct($locator, $paths);
45
46 $this->loader = $loader;
47 }
48
49 /**
50 * Loads from annotations from a file.
51 *
52 * @param string $file A PHP file path
53 * @param string|null $type The resource type
54 *
55 * @return RouteCollection A RouteCollection instance
56 *
57 * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
58 */
59 public function load($file, $type = null)
60 {
61 $path = $this->locator->locate($file);
62
63 $collection = new RouteCollection();
64 if ($class = $this->findClass($path)) {
65 $collection->addResource(new FileResource($path));
66 $collection->addCollection($this->loader->load($class, $type));
67 }
68
69 return $collection;
70 }
71
72 /**
73 * {@inheritdoc}
74 */
75 public function supports($resource, $type = null)
76 {
77 return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
78 }
79
80 /**
81 * Returns the full class name for the first class in the file.
82 *
83 * @param string $file A PHP file path
84 *
85 * @return string|false Full class name if found, false otherwise
86 */
87 protected function findClass($file)
88 {
89 $class = false;
90 $namespace = false;
91 $tokens = token_get_all(file_get_contents($file));
92 for ($i = 0, $count = count($tokens); $i < $count; $i++) {
93 $token = $tokens[$i];
94
95 if (!is_array($token)) {
96 continue;
97 }
98
99 if (true === $class && T_STRING === $token[0]) {
100 return $namespace.'\\'.$token[1];
101 }
102
103 if (true === $namespace && T_STRING === $token[0]) {
104 $namespace = '';
105 do {
106 $namespace .= $token[1];
107 $token = $tokens[++$i];
108 } while ($i < $count && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
109 }
110
111 if (T_CLASS === $token[0]) {
112 $class = true;
113 }
114
115 if (T_NAMESPACE === $token[0]) {
116 $namespace = true;
117 }
118 }
119
120 return false;
121 }
122}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php
new file mode 100644
index 00000000..8212c291
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php
@@ -0,0 +1,52 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Config\Loader\Loader;
15use Symfony\Component\Routing\RouteCollection;
16
17/**
18 * ClosureLoader loads routes from a PHP closure.
19 *
20 * The Closure must return a RouteCollection instance.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 *
24 * @api
25 */
26class ClosureLoader extends Loader
27{
28 /**
29 * Loads a Closure.
30 *
31 * @param \Closure $closure A Closure
32 * @param string|null $type The resource type
33 *
34 * @return RouteCollection A RouteCollection instance
35 *
36 * @api
37 */
38 public function load($closure, $type = null)
39 {
40 return call_user_func($closure);
41 }
42
43 /**
44 * {@inheritdoc}
45 *
46 * @api
47 */
48 public function supports($resource, $type = null)
49 {
50 return $resource instanceof \Closure && (!$type || 'closure' === $type);
51 }
52}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php
new file mode 100644
index 00000000..98b7efbf
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php
@@ -0,0 +1,62 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Config\Loader\FileLoader;
15use Symfony\Component\Config\Resource\FileResource;
16use Symfony\Component\Routing\RouteCollection;
17
18/**
19 * PhpFileLoader loads routes from a PHP file.
20 *
21 * The file must return a RouteCollection instance.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 *
25 * @api
26 */
27class PhpFileLoader extends FileLoader
28{
29 /**
30 * Loads a PHP file.
31 *
32 * @param string $file A PHP file path
33 * @param string|null $type The resource type
34 *
35 * @return RouteCollection A RouteCollection instance
36 *
37 * @api
38 */
39 public function load($file, $type = null)
40 {
41 // the loader variable is exposed to the included file below
42 $loader = $this;
43
44 $path = $this->locator->locate($file);
45 $this->setCurrentDir(dirname($path));
46
47 $collection = include $path;
48 $collection->addResource(new FileResource($path));
49
50 return $collection;
51 }
52
53 /**
54 * {@inheritdoc}
55 *
56 * @api
57 */
58 public function supports($resource, $type = null)
59 {
60 return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type);
61 }
62}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php
new file mode 100644
index 00000000..da7b33d8
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.php
@@ -0,0 +1,238 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Config\Resource\FileResource;
17use Symfony\Component\Config\Loader\FileLoader;
18use Symfony\Component\Config\Util\XmlUtils;
19
20/**
21 * XmlFileLoader loads XML routing files.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 * @author Tobias Schultze <http://tobion.de>
25 *
26 * @api
27 */
28class XmlFileLoader extends FileLoader
29{
30 const NAMESPACE_URI = 'http://symfony.com/schema/routing';
31 const SCHEME_PATH = '/schema/routing/routing-1.0.xsd';
32
33 /**
34 * Loads an XML file.
35 *
36 * @param string $file An XML file path
37 * @param string|null $type The resource type
38 *
39 * @return RouteCollection A RouteCollection instance
40 *
41 * @throws \InvalidArgumentException When the file cannot be loaded or when the XML cannot be
42 * parsed because it does not validate against the scheme.
43 *
44 * @api
45 */
46 public function load($file, $type = null)
47 {
48 $path = $this->locator->locate($file);
49
50 $xml = $this->loadFile($path);
51
52 $collection = new RouteCollection();
53 $collection->addResource(new FileResource($path));
54
55 // process routes and imports
56 foreach ($xml->documentElement->childNodes as $node) {
57 if (!$node instanceof \DOMElement) {
58 continue;
59 }
60
61 $this->parseNode($collection, $node, $path, $file);
62 }
63
64 return $collection;
65 }
66
67 /**
68 * Parses a node from a loaded XML file.
69 *
70 * @param RouteCollection $collection Collection to associate with the node
71 * @param \DOMElement $node Element to parse
72 * @param string $path Full path of the XML file being processed
73 * @param string $file Loaded file name
74 *
75 * @throws \InvalidArgumentException When the XML is invalid
76 */
77 protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file)
78 {
79 if (self::NAMESPACE_URI !== $node->namespaceURI) {
80 return;
81 }
82
83 switch ($node->localName) {
84 case 'route':
85 $this->parseRoute($collection, $node, $path);
86 break;
87 case 'import':
88 $this->parseImport($collection, $node, $path, $file);
89 break;
90 default:
91 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path));
92 }
93 }
94
95 /**
96 * {@inheritdoc}
97 *
98 * @api
99 */
100 public function supports($resource, $type = null)
101 {
102 return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type);
103 }
104
105 /**
106 * Parses a route and adds it to the RouteCollection.
107 *
108 * @param RouteCollection $collection RouteCollection instance
109 * @param \DOMElement $node Element to parse that represents a Route
110 * @param string $path Full path of the XML file being processed
111 *
112 * @throws \InvalidArgumentException When the XML is invalid
113 */
114 protected function parseRoute(RouteCollection $collection, \DOMElement $node, $path)
115 {
116 if ('' === ($id = $node->getAttribute('id')) || (!$node->hasAttribute('pattern') && !$node->hasAttribute('path'))) {
117 throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" and a "path" attribute.', $path));
118 }
119
120 if ($node->hasAttribute('pattern')) {
121 if ($node->hasAttribute('path')) {
122 throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
123 }
124
125 $node->setAttribute('path', $node->getAttribute('pattern'));
126 $node->removeAttribute('pattern');
127 }
128
129 $schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
130 $methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
131
132 list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
133
134 $route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods);
135 $collection->add($id, $route);
136 }
137
138 /**
139 * Parses an import and adds the routes in the resource to the RouteCollection.
140 *
141 * @param RouteCollection $collection RouteCollection instance
142 * @param \DOMElement $node Element to parse that represents a Route
143 * @param string $path Full path of the XML file being processed
144 * @param string $file Loaded file name
145 *
146 * @throws \InvalidArgumentException When the XML is invalid
147 */
148 protected function parseImport(RouteCollection $collection, \DOMElement $node, $path, $file)
149 {
150 if ('' === $resource = $node->getAttribute('resource')) {
151 throw new \InvalidArgumentException(sprintf('The <import> element in file "%s" must have a "resource" attribute.', $path));
152 }
153
154 $type = $node->getAttribute('type');
155 $prefix = $node->getAttribute('prefix');
156 $host = $node->hasAttribute('host') ? $node->getAttribute('host') : null;
157 $schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
158 $methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
159
160 list($defaults, $requirements, $options) = $this->parseConfigs($node, $path);
161
162 $this->setCurrentDir(dirname($path));
163
164 $subCollection = $this->import($resource, ('' !== $type ? $type : null), false, $file);
165 /* @var $subCollection RouteCollection */
166 $subCollection->addPrefix($prefix);
167 if (null !== $host) {
168 $subCollection->setHost($host);
169 }
170 if (null !== $schemes) {
171 $subCollection->setSchemes($schemes);
172 }
173 if (null !== $methods) {
174 $subCollection->setMethods($methods);
175 }
176 $subCollection->addDefaults($defaults);
177 $subCollection->addRequirements($requirements);
178 $subCollection->addOptions($options);
179
180 $collection->addCollection($subCollection);
181 }
182
183 /**
184 * Loads an XML file.
185 *
186 * @param string $file An XML file path
187 *
188 * @return \DOMDocument
189 *
190 * @throws \InvalidArgumentException When loading of XML file fails because of syntax errors
191 * or when the XML structure is not as expected by the scheme -
192 * see validate()
193 */
194 protected function loadFile($file)
195 {
196 return XmlUtils::loadFile($file, __DIR__.static::SCHEME_PATH);
197 }
198
199 /**
200 * Parses the config elements (default, requirement, option).
201 *
202 * @param \DOMElement $node Element to parse that contains the configs
203 * @param string $path Full path of the XML file being processed
204 *
205 * @return array An array with the defaults as first item, requirements as second and options as third.
206 *
207 * @throws \InvalidArgumentException When the XML is invalid
208 */
209 private function parseConfigs(\DOMElement $node, $path)
210 {
211 $defaults = array();
212 $requirements = array();
213 $options = array();
214
215 foreach ($node->getElementsByTagNameNS(self::NAMESPACE_URI, '*') as $n) {
216 switch ($n->localName) {
217 case 'default':
218 if ($n->hasAttribute('xsi:nil') && 'true' == $n->getAttribute('xsi:nil')) {
219 $defaults[$n->getAttribute('key')] = null;
220 } else {
221 $defaults[$n->getAttribute('key')] = trim($n->textContent);
222 }
223
224 break;
225 case 'requirement':
226 $requirements[$n->getAttribute('key')] = trim($n->textContent);
227 break;
228 case 'option':
229 $options[$n->getAttribute('key')] = trim($n->textContent);
230 break;
231 default:
232 throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement" or "option".', $n->localName, $path));
233 }
234 }
235
236 return array($defaults, $requirements, $options);
237 }
238}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php
new file mode 100644
index 00000000..9deea7fe
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.php
@@ -0,0 +1,212 @@
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
12namespace Symfony\Component\Routing\Loader;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Config\Resource\FileResource;
17use Symfony\Component\Yaml\Parser as YamlParser;
18use Symfony\Component\Config\Loader\FileLoader;
19
20/**
21 * YamlFileLoader loads Yaml routing files.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 * @author Tobias Schultze <http://tobion.de>
25 *
26 * @api
27 */
28class YamlFileLoader extends FileLoader
29{
30 private static $availableKeys = array(
31 'resource', 'type', 'prefix', 'pattern', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options',
32 );
33 private $yamlParser;
34
35 /**
36 * Loads a Yaml file.
37 *
38 * @param string $file A Yaml file path
39 * @param string|null $type The resource type
40 *
41 * @return RouteCollection A RouteCollection instance
42 *
43 * @throws \InvalidArgumentException When a route can't be parsed because YAML is invalid
44 *
45 * @api
46 */
47 public function load($file, $type = null)
48 {
49 $path = $this->locator->locate($file);
50
51 if (!stream_is_local($path)) {
52 throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path));
53 }
54
55 if (!file_exists($path)) {
56 throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path));
57 }
58
59 if (null === $this->yamlParser) {
60 $this->yamlParser = new YamlParser();
61 }
62
63 $config = $this->yamlParser->parse(file_get_contents($path));
64
65 $collection = new RouteCollection();
66 $collection->addResource(new FileResource($path));
67
68 // empty file
69 if (null === $config) {
70 return $collection;
71 }
72
73 // not an array
74 if (!is_array($config)) {
75 throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
76 }
77
78 foreach ($config as $name => $config) {
79 if (isset($config['pattern'])) {
80 if (isset($config['path'])) {
81 throw new \InvalidArgumentException(sprintf('The file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".', $path));
82 }
83
84 $config['path'] = $config['pattern'];
85 unset($config['pattern']);
86 }
87
88 $this->validate($config, $name, $path);
89
90 if (isset($config['resource'])) {
91 $this->parseImport($collection, $config, $path, $file);
92 } else {
93 $this->parseRoute($collection, $name, $config, $path);
94 }
95 }
96
97 return $collection;
98 }
99
100 /**
101 * {@inheritdoc}
102 *
103 * @api
104 */
105 public function supports($resource, $type = null)
106 {
107 return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'yaml' === $type);
108 }
109
110 /**
111 * Parses a route and adds it to the RouteCollection.
112 *
113 * @param RouteCollection $collection A RouteCollection instance
114 * @param string $name Route name
115 * @param array $config Route definition
116 * @param string $path Full path of the YAML file being processed
117 */
118 protected function parseRoute(RouteCollection $collection, $name, array $config, $path)
119 {
120 $defaults = isset($config['defaults']) ? $config['defaults'] : array();
121 $requirements = isset($config['requirements']) ? $config['requirements'] : array();
122 $options = isset($config['options']) ? $config['options'] : array();
123 $host = isset($config['host']) ? $config['host'] : '';
124 $schemes = isset($config['schemes']) ? $config['schemes'] : array();
125 $methods = isset($config['methods']) ? $config['methods'] : array();
126
127 $route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods);
128
129 $collection->add($name, $route);
130 }
131
132 /**
133 * Parses an import and adds the routes in the resource to the RouteCollection.
134 *
135 * @param RouteCollection $collection A RouteCollection instance
136 * @param array $config Route definition
137 * @param string $path Full path of the YAML file being processed
138 * @param string $file Loaded file name
139 */
140 protected function parseImport(RouteCollection $collection, array $config, $path, $file)
141 {
142 $type = isset($config['type']) ? $config['type'] : null;
143 $prefix = isset($config['prefix']) ? $config['prefix'] : '';
144 $defaults = isset($config['defaults']) ? $config['defaults'] : array();
145 $requirements = isset($config['requirements']) ? $config['requirements'] : array();
146 $options = isset($config['options']) ? $config['options'] : array();
147 $host = isset($config['host']) ? $config['host'] : null;
148 $schemes = isset($config['schemes']) ? $config['schemes'] : null;
149 $methods = isset($config['methods']) ? $config['methods'] : null;
150
151 $this->setCurrentDir(dirname($path));
152
153 $subCollection = $this->import($config['resource'], $type, false, $file);
154 /* @var $subCollection RouteCollection */
155 $subCollection->addPrefix($prefix);
156 if (null !== $host) {
157 $subCollection->setHost($host);
158 }
159 if (null !== $schemes) {
160 $subCollection->setSchemes($schemes);
161 }
162 if (null !== $methods) {
163 $subCollection->setMethods($methods);
164 }
165 $subCollection->addDefaults($defaults);
166 $subCollection->addRequirements($requirements);
167 $subCollection->addOptions($options);
168
169 $collection->addCollection($subCollection);
170 }
171
172 /**
173 * Validates the route configuration.
174 *
175 * @param array $config A resource config
176 * @param string $name The config key
177 * @param string $path The loaded file path
178 *
179 * @throws \InvalidArgumentException If one of the provided config keys is not supported,
180 * something is missing or the combination is nonsense
181 */
182 protected function validate($config, $name, $path)
183 {
184 if (!is_array($config)) {
185 throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path));
186 }
187 if ($extraKeys = array_diff(array_keys($config), self::$availableKeys)) {
188 throw new \InvalidArgumentException(sprintf(
189 'The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".',
190 $path, $name, implode('", "', $extraKeys), implode('", "', self::$availableKeys)
191 ));
192 }
193 if (isset($config['resource']) && isset($config['path'])) {
194 throw new \InvalidArgumentException(sprintf(
195 'The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.',
196 $path, $name
197 ));
198 }
199 if (!isset($config['resource']) && isset($config['type'])) {
200 throw new \InvalidArgumentException(sprintf(
201 'The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.',
202 $name, $path
203 ));
204 }
205 if (!isset($config['resource']) && !isset($config['path'])) {
206 throw new \InvalidArgumentException(sprintf(
207 'You must define a "path" for the route "%s" in file "%s".',
208 $name, $path
209 ));
210 }
211 }
212}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
new file mode 100644
index 00000000..daea8143
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
@@ -0,0 +1,64 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<xsd:schema xmlns="http://symfony.com/schema/routing"
4 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
5 targetNamespace="http://symfony.com/schema/routing"
6 elementFormDefault="qualified">
7
8 <xsd:annotation>
9 <xsd:documentation><![CDATA[
10 Symfony XML Routing Schema, version 1.0
11 Authors: Fabien Potencier, Tobias Schultze
12
13 This scheme defines the elements and attributes that can be used to define
14 routes. A route maps an HTTP request to a set of configuration variables.
15 ]]></xsd:documentation>
16 </xsd:annotation>
17
18 <xsd:element name="routes" type="routes" />
19
20 <xsd:complexType name="routes">
21 <xsd:choice minOccurs="0" maxOccurs="unbounded">
22 <xsd:element name="import" type="import" />
23 <xsd:element name="route" type="route" />
24 </xsd:choice>
25 </xsd:complexType>
26
27 <xsd:group name="configs">
28 <xsd:choice>
29 <xsd:element name="default" nillable="true" type="element" />
30 <xsd:element name="requirement" type="element" />
31 <xsd:element name="option" type="element" />
32 </xsd:choice>
33 </xsd:group>
34
35 <xsd:complexType name="route">
36 <xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
37
38 <xsd:attribute name="id" type="xsd:string" use="required" />
39 <xsd:attribute name="path" type="xsd:string" />
40 <xsd:attribute name="pattern" type="xsd:string" />
41 <xsd:attribute name="host" type="xsd:string" />
42 <xsd:attribute name="schemes" type="xsd:string" />
43 <xsd:attribute name="methods" type="xsd:string" />
44 </xsd:complexType>
45
46 <xsd:complexType name="import">
47 <xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
48
49 <xsd:attribute name="resource" type="xsd:string" use="required" />
50 <xsd:attribute name="type" type="xsd:string" />
51 <xsd:attribute name="prefix" type="xsd:string" />
52 <xsd:attribute name="host" type="xsd:string" />
53 <xsd:attribute name="schemes" type="xsd:string" />
54 <xsd:attribute name="methods" type="xsd:string" />
55 </xsd:complexType>
56
57 <xsd:complexType name="element">
58 <xsd:simpleContent>
59 <xsd:extension base="xsd:string">
60 <xsd:attribute name="key" type="xsd:string" use="required" />
61 </xsd:extension>
62 </xsd:simpleContent>
63 </xsd:complexType>
64</xsd:schema>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php
new file mode 100644
index 00000000..76612e61
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php
@@ -0,0 +1,94 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15
16/**
17 * ApacheUrlMatcher matches URL based on Apache mod_rewrite matching (see ApacheMatcherDumper).
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
21 */
22class ApacheUrlMatcher extends UrlMatcher
23{
24 /**
25 * Tries to match a URL based on Apache mod_rewrite matching.
26 *
27 * Returns false if no route matches the URL.
28 *
29 * @param string $pathinfo The pathinfo to be parsed
30 *
31 * @return array An array of parameters
32 *
33 * @throws MethodNotAllowedException If the current method is not allowed
34 */
35 public function match($pathinfo)
36 {
37 $parameters = array();
38 $defaults = array();
39 $allow = array();
40 $route = null;
41
42 foreach ($_SERVER as $key => $value) {
43 $name = $key;
44
45 // skip non-routing variables
46 // this improves performance when $_SERVER contains many usual
47 // variables like HTTP_*, DOCUMENT_ROOT, REQUEST_URI, ...
48 if (false === strpos($name, '_ROUTING_')) {
49 continue;
50 }
51
52 while (0 === strpos($name, 'REDIRECT_')) {
53 $name = substr($name, 9);
54 }
55
56 // expect _ROUTING_<type>_<name>
57 // or _ROUTING_<type>
58
59 if (0 !== strpos($name, '_ROUTING_')) {
60 continue;
61 }
62 if (false !== $pos = strpos($name, '_', 9)) {
63 $type = substr($name, 9, $pos-9);
64 $name = substr($name, $pos+1);
65 } else {
66 $type = substr($name, 9);
67 }
68
69 if ('param' === $type) {
70 if ('' !== $value) {
71 $parameters[$name] = $value;
72 }
73 } elseif ('default' === $type) {
74 $defaults[$name] = $value;
75 } elseif ('route' === $type) {
76 $route = $value;
77 } elseif ('allow' === $type) {
78 $allow[] = $name;
79 }
80
81 unset($_SERVER[$key]);
82 }
83
84 if (null !== $route) {
85 $parameters['_route'] = $route;
86
87 return $this->mergeDefaults($parameters, $defaults);
88 } elseif (0 < count($allow)) {
89 throw new MethodNotAllowedException($allow);
90 } else {
91 return parent::match($pathinfo);
92 }
93 }
94}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
new file mode 100644
index 00000000..804da19d
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php
@@ -0,0 +1,252 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15
16/**
17 * Dumps a set of Apache mod_rewrite rules.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 * @author Kris Wallsmith <kris@symfony.com>
21 */
22class ApacheMatcherDumper extends MatcherDumper
23{
24 /**
25 * Dumps a set of Apache mod_rewrite rules.
26 *
27 * Available options:
28 *
29 * * script_name: The script name (app.php by default)
30 * * base_uri: The base URI ("" by default)
31 *
32 * @param array $options An array of options
33 *
34 * @return string A string to be used as Apache rewrite rules
35 *
36 * @throws \LogicException When the route regex is invalid
37 */
38 public function dump(array $options = array())
39 {
40 $options = array_merge(array(
41 'script_name' => 'app.php',
42 'base_uri' => '',
43 ), $options);
44
45 $options['script_name'] = self::escape($options['script_name'], ' ', '\\');
46
47 $rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]");
48 $methodVars = array();
49 $hostRegexUnique = 0;
50 $prevHostRegex = '';
51
52 foreach ($this->getRoutes()->all() as $name => $route) {
53
54 $compiledRoute = $route->compile();
55 $hostRegex = $compiledRoute->getHostRegex();
56
57 if (null !== $hostRegex && $prevHostRegex !== $hostRegex) {
58 $prevHostRegex = $hostRegex;
59 $hostRegexUnique++;
60
61 $rule = array();
62
63 $regex = $this->regexToApacheRegex($hostRegex);
64 $regex = self::escape($regex, ' ', '\\');
65
66 $rule[] = sprintf('RewriteCond %%{HTTP:Host} %s', $regex);
67
68 $variables = array();
69 $variables[] = sprintf('E=__ROUTING_host_%s:1', $hostRegexUnique);
70
71 foreach ($compiledRoute->getHostVariables() as $i => $variable) {
72 $variables[] = sprintf('E=__ROUTING_host_%s_%s:%%%d', $hostRegexUnique, $variable, $i+1);
73 }
74
75 $variables = implode(',', $variables);
76
77 $rule[] = sprintf('RewriteRule .? - [%s]', $variables);
78
79 $rules[] = implode("\n", $rule);
80 }
81
82 $rules[] = $this->dumpRoute($name, $route, $options, $hostRegexUnique);
83
84 if ($req = $route->getRequirement('_method')) {
85 $methods = explode('|', strtoupper($req));
86 $methodVars = array_merge($methodVars, $methods);
87 }
88 }
89 if (0 < count($methodVars)) {
90 $rule = array('# 405 Method Not Allowed');
91 $methodVars = array_values(array_unique($methodVars));
92 if (in_array('GET', $methodVars) && !in_array('HEAD', $methodVars)) {
93 $methodVars[] = 'HEAD';
94 }
95 foreach ($methodVars as $i => $methodVar) {
96 $rule[] = sprintf('RewriteCond %%{ENV:_ROUTING__allow_%s} =1%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : '');
97 }
98 $rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']);
99
100 $rules[] = implode("\n", $rule);
101 }
102
103 return implode("\n\n", $rules)."\n";
104 }
105
106 /**
107 * Dumps a single route
108 *
109 * @param string $name Route name
110 * @param Route $route The route
111 * @param array $options Options
112 * @param bool $hostRegexUnique Unique identifier for the host regex
113 *
114 * @return string The compiled route
115 */
116 private function dumpRoute($name, $route, array $options, $hostRegexUnique)
117 {
118 $compiledRoute = $route->compile();
119
120 // prepare the apache regex
121 $regex = $this->regexToApacheRegex($compiledRoute->getRegex());
122 $regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\');
123
124 $methods = $this->getRouteMethods($route);
125
126 $hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex;
127
128 $variables = array('E=_ROUTING_route:'.$name);
129 foreach ($compiledRoute->getHostVariables() as $variable) {
130 $variables[] = sprintf('E=_ROUTING_param_%s:%%{ENV:__ROUTING_host_%s_%s}', $variable, $hostRegexUnique, $variable);
131 }
132 foreach ($compiledRoute->getPathVariables() as $i => $variable) {
133 $variables[] = 'E=_ROUTING_param_'.$variable.':%'.($i + 1);
134 }
135 foreach ($route->getDefaults() as $key => $value) {
136 $variables[] = 'E=_ROUTING_default_'.$key.':'.strtr($value, array(
137 ':' => '\\:',
138 '=' => '\\=',
139 '\\' => '\\\\',
140 ' ' => '\\ ',
141 ));
142 }
143 $variables = implode(',', $variables);
144
145 $rule = array("# $name");
146
147 // method mismatch
148 if (0 < count($methods)) {
149 $allow = array();
150 foreach ($methods as $method) {
151 $allow[] = 'E=_ROUTING_allow_'.$method.':1';
152 }
153
154 if ($hostRegex = $compiledRoute->getHostRegex()) {
155 $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
156 }
157
158 $rule[] = "RewriteCond %{REQUEST_URI} $regex";
159 $rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods));
160 $rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow));
161 }
162
163 // redirect with trailing slash appended
164 if ($hasTrailingSlash) {
165
166 if ($hostRegex = $compiledRoute->getHostRegex()) {
167 $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
168 }
169
170 $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$';
171 $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]';
172 }
173
174 // the main rule
175
176 if ($hostRegex = $compiledRoute->getHostRegex()) {
177 $rule[] = sprintf("RewriteCond %%{ENV:__ROUTING_host_%s} =1", $hostRegexUnique);
178 }
179
180 $rule[] = "RewriteCond %{REQUEST_URI} $regex";
181 $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]";
182
183 return implode("\n", $rule);
184 }
185
186 /**
187 * Returns methods allowed for a route
188 *
189 * @param Route $route The route
190 *
191 * @return array The methods
192 */
193 private function getRouteMethods(Route $route)
194 {
195 $methods = array();
196 if ($req = $route->getRequirement('_method')) {
197 $methods = explode('|', strtoupper($req));
198 // GET and HEAD are equivalent
199 if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
200 $methods[] = 'HEAD';
201 }
202 }
203
204 return $methods;
205 }
206
207 /**
208 * Converts a regex to make it suitable for mod_rewrite
209 *
210 * @param string $regex The regex
211 *
212 * @return string The converted regex
213 */
214 private function regexToApacheRegex($regex)
215 {
216 $regexPatternEnd = strrpos($regex, $regex[0]);
217
218 return preg_replace('/\?P<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1));
219 }
220
221 /**
222 * Escapes a string.
223 *
224 * @param string $string The string to be escaped
225 * @param string $char The character to be escaped
226 * @param string $with The character to be used for escaping
227 *
228 * @return string The escaped string
229 */
230 private static function escape($string, $char, $with)
231 {
232 $escaped = false;
233 $output = '';
234 foreach (str_split($string) as $symbol) {
235 if ($escaped) {
236 $output .= $symbol;
237 $escaped = false;
238 continue;
239 }
240 if ($symbol === $char) {
241 $output .= $with.$char;
242 continue;
243 }
244 if ($symbol === $with) {
245 $escaped = true;
246 }
247 $output .= $symbol;
248 }
249
250 return $output;
251 }
252}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php
new file mode 100644
index 00000000..612ac0d2
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php
@@ -0,0 +1,159 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14/**
15 * Collection of routes.
16 *
17 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
18 */
19class DumperCollection implements \IteratorAggregate
20{
21 /**
22 * @var DumperCollection|null
23 */
24 private $parent;
25
26 /**
27 * @var (DumperCollection|DumperRoute)[]
28 */
29 private $children = array();
30
31 /**
32 * @var array
33 */
34 private $attributes = array();
35
36 /**
37 * Returns the children routes and collections.
38 *
39 * @return (DumperCollection|DumperRoute)[] Array of DumperCollection|DumperRoute
40 */
41 public function all()
42 {
43 return $this->children;
44 }
45
46 /**
47 * Adds a route or collection
48 *
49 * @param DumperRoute|DumperCollection The route or collection
50 */
51 public function add($child)
52 {
53 if ($child instanceof DumperCollection) {
54 $child->setParent($this);
55 }
56 $this->children[] = $child;
57 }
58
59 /**
60 * Sets children.
61 *
62 * @param array $children The children
63 */
64 public function setAll(array $children)
65 {
66 foreach ($children as $child) {
67 if ($child instanceof DumperCollection) {
68 $child->setParent($this);
69 }
70 }
71 $this->children = $children;
72 }
73
74 /**
75 * Returns an iterator over the children.
76 *
77 * @return \Iterator The iterator
78 */
79 public function getIterator()
80 {
81 return new \ArrayIterator($this->children);
82 }
83
84 /**
85 * Returns the root of the collection.
86 *
87 * @return DumperCollection The root collection
88 */
89 public function getRoot()
90 {
91 return (null !== $this->parent) ? $this->parent->getRoot() : $this;
92 }
93
94 /**
95 * Returns the parent collection.
96 *
97 * @return DumperCollection|null The parent collection or null if the collection has no parent
98 */
99 protected function getParent()
100 {
101 return $this->parent;
102 }
103
104 /**
105 * Sets the parent collection.
106 *
107 * @param DumperCollection $parent The parent collection
108 */
109 protected function setParent(DumperCollection $parent)
110 {
111 $this->parent = $parent;
112 }
113
114 /**
115 * Returns true if the attribute is defined.
116 *
117 * @param string $name The attribute name
118 *
119 * @return Boolean true if the attribute is defined, false otherwise
120 */
121 public function hasAttribute($name)
122 {
123 return array_key_exists($name, $this->attributes);
124 }
125
126 /**
127 * Returns an attribute by name.
128 *
129 * @param string $name The attribute name
130 * @param mixed $default Default value is the attribute doesn't exist
131 *
132 * @return mixed The attribute value
133 */
134 public function getAttribute($name, $default = null)
135 {
136 return $this->hasAttribute($name) ? $this->attributes[$name] : $default;
137 }
138
139 /**
140 * Sets an attribute by name.
141 *
142 * @param string $name The attribute name
143 * @param mixed $value The attribute value
144 */
145 public function setAttribute($name, $value)
146 {
147 $this->attributes[$name] = $value;
148 }
149
150 /**
151 * Sets multiple attributes.
152 *
153 * @param array $attributes The attributes
154 */
155 public function setAttributes($attributes)
156 {
157 $this->attributes = $attributes;
158 }
159}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php
new file mode 100644
index 00000000..26382b0b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperPrefixCollection.php
@@ -0,0 +1,108 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14/**
15 * Prefix tree of routes preserving routes order.
16 *
17 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
18 */
19class DumperPrefixCollection extends DumperCollection
20{
21 /**
22 * @var string
23 */
24 private $prefix = '';
25
26 /**
27 * Returns the prefix.
28 *
29 * @return string The prefix
30 */
31 public function getPrefix()
32 {
33 return $this->prefix;
34 }
35
36 /**
37 * Sets the prefix.
38 *
39 * @param string $prefix The prefix
40 */
41 public function setPrefix($prefix)
42 {
43 $this->prefix = $prefix;
44 }
45
46 /**
47 * Adds a route in the tree.
48 *
49 * @param DumperRoute $route The route
50 *
51 * @return DumperPrefixCollection The node the route was added to
52 *
53 * @throws \LogicException
54 */
55 public function addPrefixRoute(DumperRoute $route)
56 {
57 $prefix = $route->getRoute()->compile()->getStaticPrefix();
58
59 // Same prefix, add to current leave
60 if ($this->prefix === $prefix) {
61 $this->add($route);
62
63 return $this;
64 }
65
66 // Prefix starts with route's prefix
67 if ('' === $this->prefix || 0 === strpos($prefix, $this->prefix)) {
68 $collection = new DumperPrefixCollection();
69 $collection->setPrefix(substr($prefix, 0, strlen($this->prefix)+1));
70 $this->add($collection);
71
72 return $collection->addPrefixRoute($route);
73 }
74
75 // No match, fallback to parent (recursively)
76
77 if (null === $parent = $this->getParent()) {
78 throw new \LogicException("The collection root must not have a prefix");
79 }
80
81 return $parent->addPrefixRoute($route);
82 }
83
84 /**
85 * Merges nodes whose prefix ends with a slash
86 *
87 * Children of a node whose prefix ends with a slash are moved to the parent node
88 */
89 public function mergeSlashNodes()
90 {
91 $children = array();
92
93 foreach ($this as $child) {
94 if ($child instanceof self) {
95 $child->mergeSlashNodes();
96 if ('/' === substr($child->prefix, -1)) {
97 $children = array_merge($children, $child->all());
98 } else {
99 $children[] = $child;
100 }
101 } else {
102 $children[] = $child;
103 }
104 }
105
106 $this->setAll($children);
107 }
108}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php
new file mode 100644
index 00000000..2928cdcc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/DumperRoute.php
@@ -0,0 +1,64 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15
16/**
17 * Container for a Route.
18 *
19 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
20 */
21class DumperRoute
22{
23 /**
24 * @var string
25 */
26 private $name;
27
28 /**
29 * @var Route
30 */
31 private $route;
32
33 /**
34 * Constructor.
35 *
36 * @param string $name The route name
37 * @param Route $route The route
38 */
39 public function __construct($name, Route $route)
40 {
41 $this->name = $name;
42 $this->route = $route;
43 }
44
45 /**
46 * Returns the route name.
47 *
48 * @return string The route name
49 */
50 public function getName()
51 {
52 return $this->name;
53 }
54
55 /**
56 * Returns the route.
57 *
58 * @return Route The route
59 */
60 public function getRoute()
61 {
62 return $this->route;
63 }
64}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php
new file mode 100644
index 00000000..52edc017
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.php
@@ -0,0 +1,45 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15
16/**
17 * MatcherDumper is the abstract class for all built-in matcher dumpers.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 */
21abstract class MatcherDumper implements MatcherDumperInterface
22{
23 /**
24 * @var RouteCollection
25 */
26 private $routes;
27
28 /**
29 * Constructor.
30 *
31 * @param RouteCollection $routes The RouteCollection to dump
32 */
33 public function __construct(RouteCollection $routes)
34 {
35 $this->routes = $routes;
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 public function getRoutes()
42 {
43 return $this->routes;
44 }
45}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php
new file mode 100644
index 00000000..f85e4cef
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.php
@@ -0,0 +1,37 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14/**
15 * MatcherDumperInterface is the interface that all matcher dumper classes must implement.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19interface MatcherDumperInterface
20{
21 /**
22 * Dumps a set of routes to a string representation of executable code
23 * that can then be used to match a request against these routes.
24 *
25 * @param array $options An array of options
26 *
27 * @return string Executable code
28 */
29 public function dump(array $options = array());
30
31 /**
32 * Gets the routes to dump.
33 *
34 * @return RouteCollection A RouteCollection instance
35 */
36 public function getRoutes();
37}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
new file mode 100644
index 00000000..dc17ffbe
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
@@ -0,0 +1,378 @@
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
12namespace Symfony\Component\Routing\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16
17/**
18 * PhpMatcherDumper creates a PHP class able to match URLs for a given set of routes.
19 *
20 * @author Fabien Potencier <fabien@symfony.com>
21 * @author Tobias Schultze <http://tobion.de>
22 * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
23 */
24class PhpMatcherDumper extends MatcherDumper
25{
26 /**
27 * Dumps a set of routes to a PHP class.
28 *
29 * Available options:
30 *
31 * * class: The class name
32 * * base_class: The base class name
33 *
34 * @param array $options An array of options
35 *
36 * @return string A PHP class representing the matcher class
37 */
38 public function dump(array $options = array())
39 {
40 $options = array_replace(array(
41 'class' => 'ProjectUrlMatcher',
42 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
43 ), $options);
44
45 // trailing slash support is only enabled if we know how to redirect the user
46 $interfaces = class_implements($options['base_class']);
47 $supportsRedirections = isset($interfaces['Symfony\\Component\\Routing\\Matcher\\RedirectableUrlMatcherInterface']);
48
49 return <<<EOF
50<?php
51
52use Symfony\Component\Routing\Exception\MethodNotAllowedException;
53use Symfony\Component\Routing\Exception\ResourceNotFoundException;
54use Symfony\Component\Routing\RequestContext;
55
56/**
57 * {$options['class']}
58 *
59 * This class has been auto-generated
60 * by the Symfony Routing Component.
61 */
62class {$options['class']} extends {$options['base_class']}
63{
64 /**
65 * Constructor.
66 */
67 public function __construct(RequestContext \$context)
68 {
69 \$this->context = \$context;
70 }
71
72{$this->generateMatchMethod($supportsRedirections)}
73}
74
75EOF;
76 }
77
78 /**
79 * Generates the code for the match method implementing UrlMatcherInterface.
80 *
81 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
82 *
83 * @return string Match method as PHP code
84 */
85 private function generateMatchMethod($supportsRedirections)
86 {
87 $code = rtrim($this->compileRoutes($this->getRoutes(), $supportsRedirections), "\n");
88
89 return <<<EOF
90 public function match(\$pathinfo)
91 {
92 \$allow = array();
93 \$pathinfo = rawurldecode(\$pathinfo);
94
95$code
96
97 throw 0 < count(\$allow) ? new MethodNotAllowedException(array_unique(\$allow)) : new ResourceNotFoundException();
98 }
99EOF;
100 }
101
102 /**
103 * Generates PHP code to match a RouteCollection with all its routes.
104 *
105 * @param RouteCollection $routes A RouteCollection instance
106 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
107 *
108 * @return string PHP code
109 */
110 private function compileRoutes(RouteCollection $routes, $supportsRedirections)
111 {
112 $fetchedHost = false;
113
114 $groups = $this->groupRoutesByHostRegex($routes);
115 $code = '';
116
117 foreach ($groups as $collection) {
118 if (null !== $regex = $collection->getAttribute('host_regex')) {
119 if (!$fetchedHost) {
120 $code .= " \$host = \$this->context->getHost();\n\n";
121 $fetchedHost = true;
122 }
123
124 $code .= sprintf(" if (preg_match(%s, \$host, \$hostMatches)) {\n", var_export($regex, true));
125 }
126
127 $tree = $this->buildPrefixTree($collection);
128 $groupCode = $this->compilePrefixRoutes($tree, $supportsRedirections);
129
130 if (null !== $regex) {
131 // apply extra indention at each line (except empty ones)
132 $groupCode = preg_replace('/^.{2,}$/m', ' $0', $groupCode);
133 $code .= $groupCode;
134 $code .= " }\n\n";
135 } else {
136 $code .= $groupCode;
137 }
138 }
139
140 return $code;
141 }
142
143 /**
144 * Generates PHP code recursively to match a tree of routes
145 *
146 * @param DumperPrefixCollection $collection A DumperPrefixCollection instance
147 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
148 * @param string $parentPrefix Prefix of the parent collection
149 *
150 * @return string PHP code
151 */
152 private function compilePrefixRoutes(DumperPrefixCollection $collection, $supportsRedirections, $parentPrefix = '')
153 {
154 $code = '';
155 $prefix = $collection->getPrefix();
156 $optimizable = 1 < strlen($prefix) && 1 < count($collection->all());
157 $optimizedPrefix = $parentPrefix;
158
159 if ($optimizable) {
160 $optimizedPrefix = $prefix;
161
162 $code .= sprintf(" if (0 === strpos(\$pathinfo, %s)) {\n", var_export($prefix, true));
163 }
164
165 foreach ($collection as $route) {
166 if ($route instanceof DumperCollection) {
167 $code .= $this->compilePrefixRoutes($route, $supportsRedirections, $optimizedPrefix);
168 } else {
169 $code .= $this->compileRoute($route->getRoute(), $route->getName(), $supportsRedirections, $optimizedPrefix)."\n";
170 }
171 }
172
173 if ($optimizable) {
174 $code .= " }\n\n";
175 // apply extra indention at each line (except empty ones)
176 $code = preg_replace('/^.{2,}$/m', ' $0', $code);
177 }
178
179 return $code;
180 }
181
182 /**
183 * Compiles a single Route to PHP code used to match it against the path info.
184 *
185 * @param Route $route A Route instance
186 * @param string $name The name of the Route
187 * @param Boolean $supportsRedirections Whether redirections are supported by the base class
188 * @param string|null $parentPrefix The prefix of the parent collection used to optimize the code
189 *
190 * @return string PHP code
191 *
192 * @throws \LogicException
193 */
194 private function compileRoute(Route $route, $name, $supportsRedirections, $parentPrefix = null)
195 {
196 $code = '';
197 $compiledRoute = $route->compile();
198 $conditions = array();
199 $hasTrailingSlash = false;
200 $matches = false;
201 $hostMatches = false;
202 $methods = array();
203
204 if ($req = $route->getRequirement('_method')) {
205 $methods = explode('|', strtoupper($req));
206 // GET and HEAD are equivalent
207 if (in_array('GET', $methods) && !in_array('HEAD', $methods)) {
208 $methods[] = 'HEAD';
209 }
210 }
211
212 $supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods));
213
214 if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
215 if ($supportsTrailingSlash && substr($m['url'], -1) === '/') {
216 $conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true));
217 $hasTrailingSlash = true;
218 } else {
219 $conditions[] = sprintf("\$pathinfo === %s", var_export(str_replace('\\', '', $m['url']), true));
220 }
221 } else {
222 if ($compiledRoute->getStaticPrefix() && $compiledRoute->getStaticPrefix() !== $parentPrefix) {
223 $conditions[] = sprintf("0 === strpos(\$pathinfo, %s)", var_export($compiledRoute->getStaticPrefix(), true));
224 }
225
226 $regex = $compiledRoute->getRegex();
227 if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
228 $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
229 $hasTrailingSlash = true;
230 }
231 $conditions[] = sprintf("preg_match(%s, \$pathinfo, \$matches)", var_export($regex, true));
232
233 $matches = true;
234 }
235
236 if ($compiledRoute->getHostVariables()) {
237 $hostMatches = true;
238 }
239
240 $conditions = implode(' && ', $conditions);
241
242 $code .= <<<EOF
243 // $name
244 if ($conditions) {
245
246EOF;
247
248 if ($methods) {
249 $gotoname = 'not_'.preg_replace('/[^A-Za-z0-9_]/', '', $name);
250
251 if (1 === count($methods)) {
252 $code .= <<<EOF
253 if (\$this->context->getMethod() != '$methods[0]') {
254 \$allow[] = '$methods[0]';
255 goto $gotoname;
256 }
257
258
259EOF;
260 } else {
261 $methods = implode("', '", $methods);
262 $code .= <<<EOF
263 if (!in_array(\$this->context->getMethod(), array('$methods'))) {
264 \$allow = array_merge(\$allow, array('$methods'));
265 goto $gotoname;
266 }
267
268
269EOF;
270 }
271 }
272
273 if ($hasTrailingSlash) {
274 $code .= <<<EOF
275 if (substr(\$pathinfo, -1) !== '/') {
276 return \$this->redirect(\$pathinfo.'/', '$name');
277 }
278
279
280EOF;
281 }
282
283 if ($scheme = $route->getRequirement('_scheme')) {
284 if (!$supportsRedirections) {
285 throw new \LogicException('The "_scheme" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.');
286 }
287
288 $code .= <<<EOF
289 if (\$this->context->getScheme() !== '$scheme') {
290 return \$this->redirect(\$pathinfo, '$name', '$scheme');
291 }
292
293
294EOF;
295 }
296
297 // optimize parameters array
298 if ($matches || $hostMatches) {
299 $vars = array();
300 if ($hostMatches) {
301 $vars[] = '$hostMatches';
302 }
303 if ($matches) {
304 $vars[] = '$matches';
305 }
306 $vars[] = "array('_route' => '$name')";
307
308 $code .= sprintf(" return \$this->mergeDefaults(array_replace(%s), %s);\n"
309 , implode(', ', $vars), str_replace("\n", '', var_export($route->getDefaults(), true)));
310
311 } elseif ($route->getDefaults()) {
312 $code .= sprintf(" return %s;\n", str_replace("\n", '', var_export(array_replace($route->getDefaults(), array('_route' => $name)), true)));
313 } else {
314 $code .= sprintf(" return array('_route' => '%s');\n", $name);
315 }
316 $code .= " }\n";
317
318 if ($methods) {
319 $code .= " $gotoname:\n";
320 }
321
322 return $code;
323 }
324
325 /**
326 * Groups consecutive routes having the same host regex.
327 *
328 * The result is a collection of collections of routes having the same host regex.
329 *
330 * @param RouteCollection $routes A flat RouteCollection
331 *
332 * @return DumperCollection A collection with routes grouped by host regex in sub-collections
333 */
334 private function groupRoutesByHostRegex(RouteCollection $routes)
335 {
336 $groups = new DumperCollection();
337
338 $currentGroup = new DumperCollection();
339 $currentGroup->setAttribute('host_regex', null);
340 $groups->add($currentGroup);
341
342 foreach ($routes as $name => $route) {
343 $hostRegex = $route->compile()->getHostRegex();
344 if ($currentGroup->getAttribute('host_regex') !== $hostRegex) {
345 $currentGroup = new DumperCollection();
346 $currentGroup->setAttribute('host_regex', $hostRegex);
347 $groups->add($currentGroup);
348 }
349 $currentGroup->add(new DumperRoute($name, $route));
350 }
351
352 return $groups;
353 }
354
355 /**
356 * Organizes the routes into a prefix tree.
357 *
358 * Routes order is preserved such that traversing the tree will traverse the
359 * routes in the origin order.
360 *
361 * @param DumperCollection $collection A collection of routes
362 *
363 * @return DumperPrefixCollection
364 */
365 private function buildPrefixTree(DumperCollection $collection)
366 {
367 $tree = new DumperPrefixCollection();
368 $current = $tree;
369
370 foreach ($collection as $route) {
371 $current = $current->addPrefixRoute($route);
372 }
373
374 $tree->mergeSlashNodes();
375
376 return $tree;
377 }
378}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
new file mode 100644
index 00000000..51e80057
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.php
@@ -0,0 +1,61 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\ResourceNotFoundException;
15use Symfony\Component\Routing\Route;
16
17/**
18 * @author Fabien Potencier <fabien@symfony.com>
19 *
20 * @api
21 */
22abstract class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
23{
24 /**
25 * {@inheritdoc}
26 */
27 public function match($pathinfo)
28 {
29 try {
30 $parameters = parent::match($pathinfo);
31 } catch (ResourceNotFoundException $e) {
32 if ('/' === substr($pathinfo, -1) || !in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
33 throw $e;
34 }
35
36 try {
37 parent::match($pathinfo.'/');
38
39 return $this->redirect($pathinfo.'/', null);
40 } catch (ResourceNotFoundException $e2) {
41 throw $e;
42 }
43 }
44
45 return $parameters;
46 }
47
48 /**
49 * {@inheritDoc}
50 */
51 protected function handleRouteRequirements($pathinfo, $name, Route $route)
52 {
53 // check HTTP scheme requirement
54 $scheme = $route->getRequirement('_scheme');
55 if ($scheme && $this->context->getScheme() !== $scheme) {
56 return array(self::ROUTE_MATCH, $this->redirect($pathinfo, $name, $scheme));
57 }
58
59 return array(self::REQUIREMENT_MATCH, null);
60 }
61}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php
new file mode 100644
index 00000000..ea91e075
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php
@@ -0,0 +1,35 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14/**
15 * RedirectableUrlMatcherInterface knows how to redirect the user.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 *
19 * @api
20 */
21interface RedirectableUrlMatcherInterface
22{
23 /**
24 * Redirects the user to another URL.
25 *
26 * @param string $path The path info to redirect to.
27 * @param string $route The route name that matched
28 * @param string|null $scheme The URL scheme (null to keep the current one)
29 *
30 * @return array An array of parameters
31 *
32 * @api
33 */
34 public function redirect($path, $route, $scheme = null);
35}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php
new file mode 100644
index 00000000..b5def3d4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php
@@ -0,0 +1,39 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\HttpFoundation\Request;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\Exception\MethodNotAllowedException;
17
18/**
19 * RequestMatcherInterface is the interface that all request matcher classes must implement.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 */
23interface RequestMatcherInterface
24{
25 /**
26 * Tries to match a request with a set of routes.
27 *
28 * If the matcher can not find information, it must throw one of the exceptions documented
29 * below.
30 *
31 * @param Request $request The request to match
32 *
33 * @return array An array of parameters
34 *
35 * @throws ResourceNotFoundException If no matching resource could be found
36 * @throws MethodNotAllowedException If a matching resource was found but the request method is not allowed
37 */
38 public function matchRequest(Request $request);
39}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
new file mode 100644
index 00000000..c09f83e8
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php
@@ -0,0 +1,121 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\ExceptionInterface;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\RouteCollection;
17use Symfony\Component\Routing\Matcher\UrlMatcher;
18
19/**
20 * TraceableUrlMatcher helps debug path info matching by tracing the match.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 */
24class TraceableUrlMatcher extends UrlMatcher
25{
26 const ROUTE_DOES_NOT_MATCH = 0;
27 const ROUTE_ALMOST_MATCHES = 1;
28 const ROUTE_MATCHES = 2;
29
30 protected $traces;
31
32 public function getTraces($pathinfo)
33 {
34 $this->traces = array();
35
36 try {
37 $this->match($pathinfo);
38 } catch (ExceptionInterface $e) {
39 }
40
41 return $this->traces;
42 }
43
44 protected function matchCollection($pathinfo, RouteCollection $routes)
45 {
46 foreach ($routes as $name => $route) {
47 $compiledRoute = $route->compile();
48
49 if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
50 // does it match without any requirements?
51 $r = new Route($route->getPath(), $route->getDefaults(), array(), $route->getOptions());
52 $cr = $r->compile();
53 if (!preg_match($cr->getRegex(), $pathinfo)) {
54 $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
55
56 continue;
57 }
58
59 foreach ($route->getRequirements() as $n => $regex) {
60 $r = new Route($route->getPath(), $route->getDefaults(), array($n => $regex), $route->getOptions());
61 $cr = $r->compile();
62
63 if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
64 $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
65
66 continue 2;
67 }
68 }
69
70 continue;
71 }
72
73 // check host requirement
74 $hostMatches = array();
75 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
76 $this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
77
78 return true;
79 }
80
81 // check HTTP method requirement
82 if ($req = $route->getRequirement('_method')) {
83 // HEAD and GET are equivalent as per RFC
84 if ('HEAD' === $method = $this->context->getMethod()) {
85 $method = 'GET';
86 }
87
88 if (!in_array($method, $req = explode('|', strtoupper($req)))) {
89 $this->allow = array_merge($this->allow, $req);
90
91 $this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context->getMethod(), implode(', ', $req)), self::ROUTE_ALMOST_MATCHES, $name, $route);
92
93 continue;
94 }
95 }
96
97 // check HTTP scheme requirement
98 if ($scheme = $route->getRequirement('_scheme')) {
99 if ($this->context->getScheme() !== $scheme) {
100 $this->addTrace(sprintf('Scheme "%s" does not match the requirement ("%s"); the user will be redirected', $this->context->getScheme(), $scheme), self::ROUTE_ALMOST_MATCHES, $name, $route);
101
102 return true;
103 }
104 }
105
106 $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route);
107
108 return true;
109 }
110 }
111
112 private function addTrace($log, $level = self::ROUTE_DOES_NOT_MATCH, $name = null, $route = null)
113 {
114 $this->traces[] = array(
115 'log' => $log,
116 'name' => $name,
117 'level' => $level,
118 'path' => null !== $route ? $route->getPath() : null,
119 );
120 }
121}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php
new file mode 100644
index 00000000..db18ec4e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.php
@@ -0,0 +1,208 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\RouteCollection;
17use Symfony\Component\Routing\RequestContext;
18use Symfony\Component\Routing\Route;
19
20/**
21 * UrlMatcher matches URL based on a set of routes.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 *
25 * @api
26 */
27class UrlMatcher implements UrlMatcherInterface
28{
29 const REQUIREMENT_MATCH = 0;
30 const REQUIREMENT_MISMATCH = 1;
31 const ROUTE_MATCH = 2;
32
33 /**
34 * @var RequestContext
35 */
36 protected $context;
37
38 /**
39 * @var array
40 */
41 protected $allow = array();
42
43 /**
44 * @var RouteCollection
45 */
46 protected $routes;
47
48 /**
49 * Constructor.
50 *
51 * @param RouteCollection $routes A RouteCollection instance
52 * @param RequestContext $context The context
53 *
54 * @api
55 */
56 public function __construct(RouteCollection $routes, RequestContext $context)
57 {
58 $this->routes = $routes;
59 $this->context = $context;
60 }
61
62 /**
63 * {@inheritdoc}
64 */
65 public function setContext(RequestContext $context)
66 {
67 $this->context = $context;
68 }
69
70 /**
71 * {@inheritdoc}
72 */
73 public function getContext()
74 {
75 return $this->context;
76 }
77
78 /**
79 * {@inheritdoc}
80 */
81 public function match($pathinfo)
82 {
83 $this->allow = array();
84
85 if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
86 return $ret;
87 }
88
89 throw 0 < count($this->allow)
90 ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow)))
91 : new ResourceNotFoundException();
92 }
93
94 /**
95 * Tries to match a URL with a set of routes.
96 *
97 * @param string $pathinfo The path info to be parsed
98 * @param RouteCollection $routes The set of routes
99 *
100 * @return array An array of parameters
101 *
102 * @throws ResourceNotFoundException If the resource could not be found
103 * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
104 */
105 protected function matchCollection($pathinfo, RouteCollection $routes)
106 {
107 foreach ($routes as $name => $route) {
108 $compiledRoute = $route->compile();
109
110 // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
111 if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
112 continue;
113 }
114
115 if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
116 continue;
117 }
118
119 $hostMatches = array();
120 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
121 continue;
122 }
123
124 // check HTTP method requirement
125 if ($req = $route->getRequirement('_method')) {
126 // HEAD and GET are equivalent as per RFC
127 if ('HEAD' === $method = $this->context->getMethod()) {
128 $method = 'GET';
129 }
130
131 if (!in_array($method, $req = explode('|', strtoupper($req)))) {
132 $this->allow = array_merge($this->allow, $req);
133
134 continue;
135 }
136 }
137
138 $status = $this->handleRouteRequirements($pathinfo, $name, $route);
139
140 if (self::ROUTE_MATCH === $status[0]) {
141 return $status[1];
142 }
143
144 if (self::REQUIREMENT_MISMATCH === $status[0]) {
145 continue;
146 }
147
148 return $this->getAttributes($route, $name, array_replace($matches, $hostMatches));
149 }
150 }
151
152 /**
153 * Returns an array of values to use as request attributes.
154 *
155 * As this method requires the Route object, it is not available
156 * in matchers that do not have access to the matched Route instance
157 * (like the PHP and Apache matcher dumpers).
158 *
159 * @param Route $route The route we are matching against
160 * @param string $name The name of the route
161 * @param array $attributes An array of attributes from the matcher
162 *
163 * @return array An array of parameters
164 */
165 protected function getAttributes(Route $route, $name, array $attributes)
166 {
167 $attributes['_route'] = $name;
168
169 return $this->mergeDefaults($attributes, $route->getDefaults());
170 }
171
172 /**
173 * Handles specific route requirements.
174 *
175 * @param string $pathinfo The path
176 * @param string $name The route name
177 * @param Route $route The route
178 *
179 * @return array The first element represents the status, the second contains additional information
180 */
181 protected function handleRouteRequirements($pathinfo, $name, Route $route)
182 {
183 // check HTTP scheme requirement
184 $scheme = $route->getRequirement('_scheme');
185 $status = $scheme && $scheme !== $this->context->getScheme() ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
186
187 return array($status, null);
188 }
189
190 /**
191 * Get merged default parameters.
192 *
193 * @param array $params The parameters
194 * @param array $defaults The defaults
195 *
196 * @return array Merged default parameters
197 */
198 protected function mergeDefaults($params, $defaults)
199 {
200 foreach ($params as $key => $value) {
201 if (!is_int($key)) {
202 $defaults[$key] = $value;
203 }
204 }
205
206 return $defaults;
207 }
208}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php
new file mode 100644
index 00000000..dd718b15
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.php
@@ -0,0 +1,43 @@
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
12namespace Symfony\Component\Routing\Matcher;
13
14use Symfony\Component\Routing\RequestContextAwareInterface;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\Exception\MethodNotAllowedException;
17
18/**
19 * UrlMatcherInterface is the interface that all URL matcher classes must implement.
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 *
23 * @api
24 */
25interface UrlMatcherInterface extends RequestContextAwareInterface
26{
27 /**
28 * Tries to match a URL path with a set of routes.
29 *
30 * If the matcher can not find information, it must throw one of the exceptions documented
31 * below.
32 *
33 * @param string $pathinfo The path info to be parsed (raw format, i.e. not urldecoded)
34 *
35 * @return array An array of parameters
36 *
37 * @throws ResourceNotFoundException If the resource could not be found
38 * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
39 *
40 * @api
41 */
42 public function match($pathinfo);
43}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/README.md b/vendor/symfony/routing/Symfony/Component/Routing/README.md
new file mode 100644
index 00000000..663844a6
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/README.md
@@ -0,0 +1,34 @@
1Routing Component
2=================
3
4Routing associates a request with the code that will convert it to a response.
5
6The example below demonstrates how you can set up a fully working routing
7system:
8
9 use Symfony\Component\HttpFoundation\Request;
10 use Symfony\Component\Routing\Matcher\UrlMatcher;
11 use Symfony\Component\Routing\RequestContext;
12 use Symfony\Component\Routing\RouteCollection;
13 use Symfony\Component\Routing\Route;
14
15 $routes = new RouteCollection();
16 $routes->add('hello', new Route('/hello', array('controller' => 'foo')));
17
18 $context = new RequestContext();
19
20 // this is optional and can be done without a Request instance
21 $context->fromRequest(Request::createFromGlobals());
22
23 $matcher = new UrlMatcher($routes, $context);
24
25 $parameters = $matcher->match('/hello');
26
27Resources
28---------
29
30You can run the unit tests with the following command:
31
32 $ cd path/to/Symfony/Component/Routing/
33 $ composer.phar install --dev
34 $ phpunit
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php b/vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php
new file mode 100644
index 00000000..cb536968
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RequestContext.php
@@ -0,0 +1,315 @@
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
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\HttpFoundation\Request;
15
16/**
17 * Holds information about the current request.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @api
22 */
23class RequestContext
24{
25 private $baseUrl;
26 private $pathInfo;
27 private $method;
28 private $host;
29 private $scheme;
30 private $httpPort;
31 private $httpsPort;
32 private $queryString;
33
34 /**
35 * @var array
36 */
37 private $parameters = array();
38
39 /**
40 * Constructor.
41 *
42 * @param string $baseUrl The base URL
43 * @param string $method The HTTP method
44 * @param string $host The HTTP host name
45 * @param string $scheme The HTTP scheme
46 * @param integer $httpPort The HTTP port
47 * @param integer $httpsPort The HTTPS port
48 * @param string $path The path
49 * @param string $queryString The query string
50 *
51 * @api
52 */
53 public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443, $path = '/', $queryString = '')
54 {
55 $this->baseUrl = $baseUrl;
56 $this->method = strtoupper($method);
57 $this->host = $host;
58 $this->scheme = strtolower($scheme);
59 $this->httpPort = $httpPort;
60 $this->httpsPort = $httpsPort;
61 $this->pathInfo = $path;
62 $this->queryString = $queryString;
63 }
64
65 public function fromRequest(Request $request)
66 {
67 $this->setBaseUrl($request->getBaseUrl());
68 $this->setPathInfo($request->getPathInfo());
69 $this->setMethod($request->getMethod());
70 $this->setHost($request->getHost());
71 $this->setScheme($request->getScheme());
72 $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort());
73 $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort);
74 $this->setQueryString($request->server->get('QUERY_STRING'));
75 }
76
77 /**
78 * Gets the base URL.
79 *
80 * @return string The base URL
81 */
82 public function getBaseUrl()
83 {
84 return $this->baseUrl;
85 }
86
87 /**
88 * Sets the base URL.
89 *
90 * @param string $baseUrl The base URL
91 *
92 * @api
93 */
94 public function setBaseUrl($baseUrl)
95 {
96 $this->baseUrl = $baseUrl;
97 }
98
99 /**
100 * Gets the path info.
101 *
102 * @return string The path info
103 */
104 public function getPathInfo()
105 {
106 return $this->pathInfo;
107 }
108
109 /**
110 * Sets the path info.
111 *
112 * @param string $pathInfo The path info
113 */
114 public function setPathInfo($pathInfo)
115 {
116 $this->pathInfo = $pathInfo;
117 }
118
119 /**
120 * Gets the HTTP method.
121 *
122 * The method is always an uppercased string.
123 *
124 * @return string The HTTP method
125 */
126 public function getMethod()
127 {
128 return $this->method;
129 }
130
131 /**
132 * Sets the HTTP method.
133 *
134 * @param string $method The HTTP method
135 *
136 * @api
137 */
138 public function setMethod($method)
139 {
140 $this->method = strtoupper($method);
141 }
142
143 /**
144 * Gets the HTTP host.
145 *
146 * @return string The HTTP host
147 */
148 public function getHost()
149 {
150 return $this->host;
151 }
152
153 /**
154 * Sets the HTTP host.
155 *
156 * @param string $host The HTTP host
157 *
158 * @api
159 */
160 public function setHost($host)
161 {
162 $this->host = $host;
163 }
164
165 /**
166 * Gets the HTTP scheme.
167 *
168 * @return string The HTTP scheme
169 */
170 public function getScheme()
171 {
172 return $this->scheme;
173 }
174
175 /**
176 * Sets the HTTP scheme.
177 *
178 * @param string $scheme The HTTP scheme
179 *
180 * @api
181 */
182 public function setScheme($scheme)
183 {
184 $this->scheme = strtolower($scheme);
185 }
186
187 /**
188 * Gets the HTTP port.
189 *
190 * @return string The HTTP port
191 */
192 public function getHttpPort()
193 {
194 return $this->httpPort;
195 }
196
197 /**
198 * Sets the HTTP port.
199 *
200 * @param string $httpPort The HTTP port
201 *
202 * @api
203 */
204 public function setHttpPort($httpPort)
205 {
206 $this->httpPort = $httpPort;
207 }
208
209 /**
210 * Gets the HTTPS port.
211 *
212 * @return string The HTTPS port
213 */
214 public function getHttpsPort()
215 {
216 return $this->httpsPort;
217 }
218
219 /**
220 * Sets the HTTPS port.
221 *
222 * @param string $httpsPort The HTTPS port
223 *
224 * @api
225 */
226 public function setHttpsPort($httpsPort)
227 {
228 $this->httpsPort = $httpsPort;
229 }
230
231 /**
232 * Gets the query string.
233 *
234 * @return string The query string
235 */
236 public function getQueryString()
237 {
238 return $this->queryString;
239 }
240
241 /**
242 * Sets the query string.
243 *
244 * @param string $queryString The query string
245 *
246 * @api
247 */
248 public function setQueryString($queryString)
249 {
250 $this->queryString = $queryString;
251 }
252
253 /**
254 * Returns the parameters.
255 *
256 * @return array The parameters
257 */
258 public function getParameters()
259 {
260 return $this->parameters;
261 }
262
263 /**
264 * Sets the parameters.
265 *
266 * This method implements a fluent interface.
267 *
268 * @param array $parameters The parameters
269 *
270 * @return Route The current Route instance
271 */
272 public function setParameters(array $parameters)
273 {
274 $this->parameters = $parameters;
275
276 return $this;
277 }
278
279 /**
280 * Gets a parameter value.
281 *
282 * @param string $name A parameter name
283 *
284 * @return mixed The parameter value
285 */
286 public function getParameter($name)
287 {
288 return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
289 }
290
291 /**
292 * Checks if a parameter value is set for the given parameter.
293 *
294 * @param string $name A parameter name
295 *
296 * @return Boolean true if the parameter value is set, false otherwise
297 */
298 public function hasParameter($name)
299 {
300 return array_key_exists($name, $this->parameters);
301 }
302
303 /**
304 * Sets a parameter value.
305 *
306 * @param string $name A parameter name
307 * @param mixed $parameter The parameter value
308 *
309 * @api
310 */
311 public function setParameter($name, $parameter)
312 {
313 $this->parameters[$name] = $parameter;
314 }
315}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php
new file mode 100644
index 00000000..daf52549
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php
@@ -0,0 +1,36 @@
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
12namespace Symfony\Component\Routing;
13
14/**
15 * @api
16 */
17interface RequestContextAwareInterface
18{
19 /**
20 * Sets the request context.
21 *
22 * @param RequestContext $context The context
23 *
24 * @api
25 */
26 public function setContext(RequestContext $context);
27
28 /**
29 * Gets the request context.
30 *
31 * @return RequestContext The context
32 *
33 * @api
34 */
35 public function getContext();
36}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Route.php b/vendor/symfony/routing/Symfony/Component/Routing/Route.php
new file mode 100644
index 00000000..060e9781
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Route.php
@@ -0,0 +1,594 @@
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
12namespace 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 * @api
21 */
22class Route implements \Serializable
23{
24 /**
25 * @var string
26 */
27 private $path = '/';
28
29 /**
30 * @var string
31 */
32 private $host = '';
33
34 /**
35 * @var array
36 */
37 private $schemes = array();
38
39 /**
40 * @var array
41 */
42 private $methods = array();
43
44 /**
45 * @var array
46 */
47 private $defaults = array();
48
49 /**
50 * @var array
51 */
52 private $requirements = array();
53
54 /**
55 * @var array
56 */
57 private $options = array();
58
59 /**
60 * @var null|RouteCompiler
61 */
62 private $compiled;
63
64 /**
65 * Constructor.
66 *
67 * Available options:
68 *
69 * * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
70 *
71 * @param string $path The path pattern to match
72 * @param array $defaults An array of default parameter values
73 * @param array $requirements An array of requirements for parameters (regexes)
74 * @param array $options An array of options
75 * @param string $host The host pattern to match
76 * @param string|array $schemes A required URI scheme or an array of restricted schemes
77 * @param string|array $methods A required HTTP method or an array of restricted methods
78 *
79 * @api
80 */
81 public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array())
82 {
83 $this->setPath($path);
84 $this->setDefaults($defaults);
85 $this->setRequirements($requirements);
86 $this->setOptions($options);
87 $this->setHost($host);
88 // The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement.
89 // They can be removed when the BC layer is removed.
90 if ($schemes) {
91 $this->setSchemes($schemes);
92 }
93 if ($methods) {
94 $this->setMethods($methods);
95 }
96 }
97
98 public function serialize()
99 {
100 return serialize(array(
101 'path' => $this->path,
102 'host' => $this->host,
103 'defaults' => $this->defaults,
104 'requirements' => $this->requirements,
105 'options' => $this->options,
106 'schemes' => $this->schemes,
107 'methods' => $this->methods,
108 ));
109 }
110
111 public function unserialize($data)
112 {
113 $data = unserialize($data);
114 $this->path = $data['path'];
115 $this->host = $data['host'];
116 $this->defaults = $data['defaults'];
117 $this->requirements = $data['requirements'];
118 $this->options = $data['options'];
119 $this->schemes = $data['schemes'];
120 $this->methods = $data['methods'];
121 }
122
123 /**
124 * Returns the pattern for the path.
125 *
126 * @return string The pattern
127 *
128 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
129 */
130 public function getPattern()
131 {
132 return $this->path;
133 }
134
135 /**
136 * Sets the pattern for the path.
137 *
138 * This method implements a fluent interface.
139 *
140 * @param string $pattern The path pattern
141 *
142 * @return Route The current Route instance
143 *
144 * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
145 */
146 public function setPattern($pattern)
147 {
148 return $this->setPath($pattern);
149 }
150
151 /**
152 * Returns the pattern for the path.
153 *
154 * @return string The path pattern
155 */
156 public function getPath()
157 {
158 return $this->path;
159 }
160
161 /**
162 * Sets the pattern for the path.
163 *
164 * This method implements a fluent interface.
165 *
166 * @param string $pattern The path pattern
167 *
168 * @return Route The current Route instance
169 */
170 public function setPath($pattern)
171 {
172 // A pattern must start with a slash and must not have multiple slashes at the beginning because the
173 // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
174 $this->path = '/'.ltrim(trim($pattern), '/');
175 $this->compiled = null;
176
177 return $this;
178 }
179
180 /**
181 * Returns the pattern for the host.
182 *
183 * @return string The host pattern
184 */
185 public function getHost()
186 {
187 return $this->host;
188 }
189
190 /**
191 * Sets the pattern for the host.
192 *
193 * This method implements a fluent interface.
194 *
195 * @param string $pattern The host pattern
196 *
197 * @return Route The current Route instance
198 */
199 public function setHost($pattern)
200 {
201 $this->host = (string) $pattern;
202 $this->compiled = null;
203
204 return $this;
205 }
206
207 /**
208 * Returns the lowercased schemes this route is restricted to.
209 * So an empty array means that any scheme is allowed.
210 *
211 * @return array The schemes
212 */
213 public function getSchemes()
214 {
215 return $this->schemes;
216 }
217
218 /**
219 * Sets the schemes (e.g. 'https') this route is restricted to.
220 * So an empty array means that any scheme is allowed.
221 *
222 * This method implements a fluent interface.
223 *
224 * @param string|array $schemes The scheme or an array of schemes
225 *
226 * @return Route The current Route instance
227 */
228 public function setSchemes($schemes)
229 {
230 $this->schemes = array_map('strtolower', (array) $schemes);
231
232 // this is to keep BC and will be removed in a future version
233 if ($this->schemes) {
234 $this->requirements['_scheme'] = implode('|', $this->schemes);
235 } else {
236 unset($this->requirements['_scheme']);
237 }
238
239 $this->compiled = null;
240
241 return $this;
242 }
243
244 /**
245 * Returns the uppercased HTTP methods this route is restricted to.
246 * So an empty array means that any method is allowed.
247 *
248 * @return array The schemes
249 */
250 public function getMethods()
251 {
252 return $this->methods;
253 }
254
255 /**
256 * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
257 * So an empty array means that any method is allowed.
258 *
259 * This method implements a fluent interface.
260 *
261 * @param string|array $methods The method or an array of methods
262 *
263 * @return Route The current Route instance
264 */
265 public function setMethods($methods)
266 {
267 $this->methods = array_map('strtoupper', (array) $methods);
268
269 // this is to keep BC and will be removed in a future version
270 if ($this->methods) {
271 $this->requirements['_method'] = implode('|', $this->methods);
272 } else {
273 unset($this->requirements['_method']);
274 }
275
276 $this->compiled = null;
277
278 return $this;
279 }
280
281 /**
282 * Returns the options.
283 *
284 * @return array The options
285 */
286 public function getOptions()
287 {
288 return $this->options;
289 }
290
291 /**
292 * Sets the options.
293 *
294 * This method implements a fluent interface.
295 *
296 * @param array $options The options
297 *
298 * @return Route The current Route instance
299 */
300 public function setOptions(array $options)
301 {
302 $this->options = array(
303 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
304 );
305
306 return $this->addOptions($options);
307 }
308
309 /**
310 * Adds options.
311 *
312 * This method implements a fluent interface.
313 *
314 * @param array $options The options
315 *
316 * @return Route The current Route instance
317 */
318 public function addOptions(array $options)
319 {
320 foreach ($options as $name => $option) {
321 $this->options[$name] = $option;
322 }
323 $this->compiled = null;
324
325 return $this;
326 }
327
328 /**
329 * Sets an option value.
330 *
331 * This method implements a fluent interface.
332 *
333 * @param string $name An option name
334 * @param mixed $value The option value
335 *
336 * @return Route The current Route instance
337 *
338 * @api
339 */
340 public function setOption($name, $value)
341 {
342 $this->options[$name] = $value;
343 $this->compiled = null;
344
345 return $this;
346 }
347
348 /**
349 * Get an option value.
350 *
351 * @param string $name An option name
352 *
353 * @return mixed The option value or null when not given
354 */
355 public function getOption($name)
356 {
357 return isset($this->options[$name]) ? $this->options[$name] : null;
358 }
359
360 /**
361 * Checks if an option has been set
362 *
363 * @param string $name An option name
364 *
365 * @return Boolean true if the option is set, false otherwise
366 */
367 public function hasOption($name)
368 {
369 return array_key_exists($name, $this->options);
370 }
371
372 /**
373 * Returns the defaults.
374 *
375 * @return array The defaults
376 */
377 public function getDefaults()
378 {
379 return $this->defaults;
380 }
381
382 /**
383 * Sets the defaults.
384 *
385 * This method implements a fluent interface.
386 *
387 * @param array $defaults The defaults
388 *
389 * @return Route The current Route instance
390 */
391 public function setDefaults(array $defaults)
392 {
393 $this->defaults = array();
394
395 return $this->addDefaults($defaults);
396 }
397
398 /**
399 * Adds defaults.
400 *
401 * This method implements a fluent interface.
402 *
403 * @param array $defaults The defaults
404 *
405 * @return Route The current Route instance
406 */
407 public function addDefaults(array $defaults)
408 {
409 foreach ($defaults as $name => $default) {
410 $this->defaults[$name] = $default;
411 }
412 $this->compiled = null;
413
414 return $this;
415 }
416
417 /**
418 * Gets a default value.
419 *
420 * @param string $name A variable name
421 *
422 * @return mixed The default value or null when not given
423 */
424 public function getDefault($name)
425 {
426 return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
427 }
428
429 /**
430 * Checks if a default value is set for the given variable.
431 *
432 * @param string $name A variable name
433 *
434 * @return Boolean true if the default value is set, false otherwise
435 */
436 public function hasDefault($name)
437 {
438 return array_key_exists($name, $this->defaults);
439 }
440
441 /**
442 * Sets a default value.
443 *
444 * @param string $name A variable name
445 * @param mixed $default The default value
446 *
447 * @return Route The current Route instance
448 *
449 * @api
450 */
451 public function setDefault($name, $default)
452 {
453 $this->defaults[$name] = $default;
454 $this->compiled = null;
455
456 return $this;
457 }
458
459 /**
460 * Returns the requirements.
461 *
462 * @return array The requirements
463 */
464 public function getRequirements()
465 {
466 return $this->requirements;
467 }
468
469 /**
470 * Sets the requirements.
471 *
472 * This method implements a fluent interface.
473 *
474 * @param array $requirements The requirements
475 *
476 * @return Route The current Route instance
477 */
478 public function setRequirements(array $requirements)
479 {
480 $this->requirements = array();
481
482 return $this->addRequirements($requirements);
483 }
484
485 /**
486 * Adds requirements.
487 *
488 * This method implements a fluent interface.
489 *
490 * @param array $requirements The requirements
491 *
492 * @return Route The current Route instance
493 */
494 public function addRequirements(array $requirements)
495 {
496 foreach ($requirements as $key => $regex) {
497 $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
498 }
499 $this->compiled = null;
500
501 return $this;
502 }
503
504 /**
505 * Returns the requirement for the given key.
506 *
507 * @param string $key The key
508 *
509 * @return string|null The regex or null when not given
510 */
511 public function getRequirement($key)
512 {
513 return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
514 }
515
516 /**
517 * Checks if a requirement is set for the given key.
518 *
519 * @param string $key A variable name
520 *
521 * @return Boolean true if a requirement is specified, false otherwise
522 */
523 public function hasRequirement($key)
524 {
525 return array_key_exists($key, $this->requirements);
526 }
527
528 /**
529 * Sets a requirement for the given key.
530 *
531 * @param string $key The key
532 * @param string $regex The regex
533 *
534 * @return Route The current Route instance
535 *
536 * @api
537 */
538 public function setRequirement($key, $regex)
539 {
540 $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
541 $this->compiled = null;
542
543 return $this;
544 }
545
546 /**
547 * Compiles the route.
548 *
549 * @return CompiledRoute A CompiledRoute instance
550 *
551 * @throws \LogicException If the Route cannot be compiled because the
552 * path or host pattern is invalid
553 *
554 * @see RouteCompiler which is responsible for the compilation process
555 */
556 public function compile()
557 {
558 if (null !== $this->compiled) {
559 return $this->compiled;
560 }
561
562 $class = $this->getOption('compiler_class');
563
564 return $this->compiled = $class::compile($this);
565 }
566
567 private function sanitizeRequirement($key, $regex)
568 {
569 if (!is_string($regex)) {
570 throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.', $key));
571 }
572
573 if ('' !== $regex && '^' === $regex[0]) {
574 $regex = (string) substr($regex, 1); // returns false for a single character
575 }
576
577 if ('$' === substr($regex, -1)) {
578 $regex = substr($regex, 0, -1);
579 }
580
581 if ('' === $regex) {
582 throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
583 }
584
585 // this is to keep BC and will be removed in a future version
586 if ('_scheme' === $key) {
587 $this->setSchemes(explode('|', $regex));
588 } elseif ('_method' === $key) {
589 $this->setMethods(explode('|', $regex));
590 }
591
592 return $regex;
593 }
594}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php b/vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php
new file mode 100644
index 00000000..499fe0f0
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php
@@ -0,0 +1,271 @@
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
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\Config\Resource\ResourceInterface;
15
16/**
17 * A RouteCollection represents a set of Route instances.
18 *
19 * When adding a route at the end of the collection, an existing route
20 * with the same name is removed first. So there can only be one route
21 * with a given name.
22 *
23 * @author Fabien Potencier <fabien@symfony.com>
24 * @author Tobias Schultze <http://tobion.de>
25 *
26 * @api
27 */
28class RouteCollection implements \IteratorAggregate, \Countable
29{
30 /**
31 * @var Route[]
32 */
33 private $routes = array();
34
35 /**
36 * @var array
37 */
38 private $resources = array();
39
40 public function __clone()
41 {
42 foreach ($this->routes as $name => $route) {
43 $this->routes[$name] = clone $route;
44 }
45 }
46
47 /**
48 * Gets the current RouteCollection as an Iterator that includes all routes.
49 *
50 * It implements \IteratorAggregate.
51 *
52 * @see all()
53 *
54 * @return \ArrayIterator An \ArrayIterator object for iterating over routes
55 */
56 public function getIterator()
57 {
58 return new \ArrayIterator($this->routes);
59 }
60
61 /**
62 * Gets the number of Routes in this collection.
63 *
64 * @return int The number of routes
65 */
66 public function count()
67 {
68 return count($this->routes);
69 }
70
71 /**
72 * Adds a route.
73 *
74 * @param string $name The route name
75 * @param Route $route A Route instance
76 *
77 * @api
78 */
79 public function add($name, Route $route)
80 {
81 unset($this->routes[$name]);
82
83 $this->routes[$name] = $route;
84 }
85
86 /**
87 * Returns all routes in this collection.
88 *
89 * @return Route[] An array of routes
90 */
91 public function all()
92 {
93 return $this->routes;
94 }
95
96 /**
97 * Gets a route by name.
98 *
99 * @param string $name The route name
100 *
101 * @return Route|null A Route instance or null when not found
102 */
103 public function get($name)
104 {
105 return isset($this->routes[$name]) ? $this->routes[$name] : null;
106 }
107
108 /**
109 * Removes a route or an array of routes by name from the collection
110 *
111 * @param string|array $name The route name or an array of route names
112 */
113 public function remove($name)
114 {
115 foreach ((array) $name as $n) {
116 unset($this->routes[$n]);
117 }
118 }
119
120 /**
121 * Adds a route collection at the end of the current set by appending all
122 * routes of the added collection.
123 *
124 * @param RouteCollection $collection A RouteCollection instance
125 *
126 * @api
127 */
128 public function addCollection(RouteCollection $collection)
129 {
130 // we need to remove all routes with the same names first because just replacing them
131 // would not place the new route at the end of the merged array
132 foreach ($collection->all() as $name => $route) {
133 unset($this->routes[$name]);
134 $this->routes[$name] = $route;
135 }
136
137 $this->resources = array_merge($this->resources, $collection->getResources());
138 }
139
140 /**
141 * Adds a prefix to the path of all child routes.
142 *
143 * @param string $prefix An optional prefix to add before each pattern of the route collection
144 * @param array $defaults An array of default values
145 * @param array $requirements An array of requirements
146 *
147 * @api
148 */
149 public function addPrefix($prefix, array $defaults = array(), array $requirements = array())
150 {
151 $prefix = trim(trim($prefix), '/');
152
153 if ('' === $prefix) {
154 return;
155 }
156
157 foreach ($this->routes as $route) {
158 $route->setPath('/'.$prefix.$route->getPath());
159 $route->addDefaults($defaults);
160 $route->addRequirements($requirements);
161 }
162 }
163
164 /**
165 * Sets the host pattern on all routes.
166 *
167 * @param string $pattern The pattern
168 * @param array $defaults An array of default values
169 * @param array $requirements An array of requirements
170 */
171 public function setHost($pattern, array $defaults = array(), array $requirements = array())
172 {
173 foreach ($this->routes as $route) {
174 $route->setHost($pattern);
175 $route->addDefaults($defaults);
176 $route->addRequirements($requirements);
177 }
178 }
179
180 /**
181 * Adds defaults to all routes.
182 *
183 * An existing default value under the same name in a route will be overridden.
184 *
185 * @param array $defaults An array of default values
186 */
187 public function addDefaults(array $defaults)
188 {
189 if ($defaults) {
190 foreach ($this->routes as $route) {
191 $route->addDefaults($defaults);
192 }
193 }
194 }
195
196 /**
197 * Adds requirements to all routes.
198 *
199 * An existing requirement under the same name in a route will be overridden.
200 *
201 * @param array $requirements An array of requirements
202 */
203 public function addRequirements(array $requirements)
204 {
205 if ($requirements) {
206 foreach ($this->routes as $route) {
207 $route->addRequirements($requirements);
208 }
209 }
210 }
211
212 /**
213 * Adds options to all routes.
214 *
215 * An existing option value under the same name in a route will be overridden.
216 *
217 * @param array $options An array of options
218 */
219 public function addOptions(array $options)
220 {
221 if ($options) {
222 foreach ($this->routes as $route) {
223 $route->addOptions($options);
224 }
225 }
226 }
227
228 /**
229 * Sets the schemes (e.g. 'https') all child routes are restricted to.
230 *
231 * @param string|array $schemes The scheme or an array of schemes
232 */
233 public function setSchemes($schemes)
234 {
235 foreach ($this->routes as $route) {
236 $route->setSchemes($schemes);
237 }
238 }
239
240 /**
241 * Sets the HTTP methods (e.g. 'POST') all child routes are restricted to.
242 *
243 * @param string|array $methods The method or an array of methods
244 */
245 public function setMethods($methods)
246 {
247 foreach ($this->routes as $route) {
248 $route->setMethods($methods);
249 }
250 }
251
252 /**
253 * Returns an array of resources loaded to build this collection.
254 *
255 * @return ResourceInterface[] An array of resources
256 */
257 public function getResources()
258 {
259 return array_unique($this->resources);
260 }
261
262 /**
263 * Adds a resource for this collection.
264 *
265 * @param ResourceInterface $resource A resource instance
266 */
267 public function addResource(ResourceInterface $resource)
268 {
269 $this->resources[] = $resource;
270 }
271}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php
new file mode 100644
index 00000000..7ced4b3a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.php
@@ -0,0 +1,233 @@
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
12namespace Symfony\Component\Routing;
13
14/**
15 * RouteCompiler compiles Route instances to CompiledRoute instances.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 * @author Tobias Schultze <http://tobion.de>
19 */
20class RouteCompiler implements RouteCompilerInterface
21{
22 const REGEX_DELIMITER = '#';
23
24 /**
25 * This string defines the characters that are automatically considered separators in front of
26 * optional placeholders (with default and no static text following). Such a single separator
27 * can be left out together with the optional placeholder from matching and generating URLs.
28 */
29 const SEPARATORS = '/,;.:-_~+*=@|';
30
31 /**
32 * {@inheritDoc}
33 *
34 * @throws \LogicException If a variable is referenced more than once
35 * @throws \DomainException If a variable name is numeric because PHP raises an error for such
36 * subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
37 */
38 public static function compile(Route $route)
39 {
40 $staticPrefix = null;
41 $hostVariables = array();
42 $pathVariables = array();
43 $variables = array();
44 $tokens = array();
45 $regex = null;
46 $hostRegex = null;
47 $hostTokens = array();
48
49 if ('' !== $host = $route->getHost()) {
50 $result = self::compilePattern($route, $host, true);
51
52 $hostVariables = $result['variables'];
53 $variables = array_merge($variables, $hostVariables);
54
55 $hostTokens = $result['tokens'];
56 $hostRegex = $result['regex'];
57 }
58
59 $path = $route->getPath();
60
61 $result = self::compilePattern($route, $path, false);
62
63 $staticPrefix = $result['staticPrefix'];
64
65 $pathVariables = $result['variables'];
66 $variables = array_merge($variables, $pathVariables);
67
68 $tokens = $result['tokens'];
69 $regex = $result['regex'];
70
71 return new CompiledRoute(
72 $staticPrefix,
73 $regex,
74 $tokens,
75 $pathVariables,
76 $hostRegex,
77 $hostTokens,
78 $hostVariables,
79 array_unique($variables)
80 );
81 }
82
83 private static function compilePattern(Route $route, $pattern, $isHost)
84 {
85 $tokens = array();
86 $variables = array();
87 $matches = array();
88 $pos = 0;
89 $defaultSeparator = $isHost ? '.' : '/';
90
91 // Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable
92 // in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself.
93 preg_match_all('#\{\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
94 foreach ($matches as $match) {
95 $varName = substr($match[0][0], 1, -1);
96 // get all static text preceding the current variable
97 $precedingText = substr($pattern, $pos, $match[0][1] - $pos);
98 $pos = $match[0][1] + strlen($match[0][0]);
99 $precedingChar = strlen($precedingText) > 0 ? substr($precedingText, -1) : '';
100 $isSeparator = '' !== $precedingChar && false !== strpos(static::SEPARATORS, $precedingChar);
101
102 if (is_numeric($varName)) {
103 throw new \DomainException(sprintf('Variable name "%s" cannot be numeric in route pattern "%s". Please use a different name.', $varName, $pattern));
104 }
105 if (in_array($varName, $variables)) {
106 throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName));
107 }
108
109 if ($isSeparator && strlen($precedingText) > 1) {
110 $tokens[] = array('text', substr($precedingText, 0, -1));
111 } elseif (!$isSeparator && strlen($precedingText) > 0) {
112 $tokens[] = array('text', $precedingText);
113 }
114
115 $regexp = $route->getRequirement($varName);
116 if (null === $regexp) {
117 $followingPattern = (string) substr($pattern, $pos);
118 // Find the next static character after the variable that functions as a separator. By default, this separator and '/'
119 // are disallowed for the variable. This default requirement makes sure that optional variables can be matched at all
120 // and that the generating-matching-combination of URLs unambiguous, i.e. the params used for generating the URL are
121 // the same that will be matched. Example: new Route('/{page}.{_format}', array('_format' => 'html'))
122 // If {page} would also match the separating dot, {_format} would never match as {page} will eagerly consume everything.
123 // Also even if {_format} was not optional the requirement prevents that {page} matches something that was originally
124 // part of {_format} when generating the URL, e.g. _format = 'mobile.html'.
125 $nextSeparator = self::findNextSeparator($followingPattern);
126 $regexp = sprintf(
127 '[^%s%s]+',
128 preg_quote($defaultSeparator, self::REGEX_DELIMITER),
129 $defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator, self::REGEX_DELIMITER) : ''
130 );
131 if (('' !== $nextSeparator && !preg_match('#^\{\w+\}#', $followingPattern)) || '' === $followingPattern) {
132 // When we have a separator, which is disallowed for the variable, we can optimize the regex with a possessive
133 // quantifier. This prevents useless backtracking of PCRE and improves performance by 20% for matching those patterns.
134 // Given the above example, there is no point in backtracking into {page} (that forbids the dot) when a dot must follow
135 // after it. This optimization cannot be applied when the next char is no real separator or when the next variable is
136 // directly adjacent, e.g. '/{x}{y}'.
137 $regexp .= '+';
138 }
139 }
140
141 $tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName);
142 $variables[] = $varName;
143 }
144
145 if ($pos < strlen($pattern)) {
146 $tokens[] = array('text', substr($pattern, $pos));
147 }
148
149 // find the first optional token
150 $firstOptional = PHP_INT_MAX;
151 if (!$isHost) {
152 for ($i = count($tokens) - 1; $i >= 0; $i--) {
153 $token = $tokens[$i];
154 if ('variable' === $token[0] && $route->hasDefault($token[3])) {
155 $firstOptional = $i;
156 } else {
157 break;
158 }
159 }
160 }
161
162 // compute the matching regexp
163 $regexp = '';
164 for ($i = 0, $nbToken = count($tokens); $i < $nbToken; $i++) {
165 $regexp .= self::computeRegexp($tokens, $i, $firstOptional);
166 }
167
168 return array(
169 'staticPrefix' => 'text' === $tokens[0][0] ? $tokens[0][1] : '',
170 'regex' => self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'s',
171 'tokens' => array_reverse($tokens),
172 'variables' => $variables,
173 );
174 }
175
176 /**
177 * Returns the next static character in the Route pattern that will serve as a separator.
178 *
179 * @param string $pattern The route pattern
180 *
181 * @return string The next static character that functions as separator (or empty string when none available)
182 */
183 private static function findNextSeparator($pattern)
184 {
185 if ('' == $pattern) {
186 // return empty string if pattern is empty or false (false which can be returned by substr)
187 return '';
188 }
189 // first remove all placeholders from the pattern so we can find the next real static character
190 $pattern = preg_replace('#\{\w+\}#', '', $pattern);
191
192 return isset($pattern[0]) && false !== strpos(static::SEPARATORS, $pattern[0]) ? $pattern[0] : '';
193 }
194
195 /**
196 * Computes the regexp used to match a specific token. It can be static text or a subpattern.
197 *
198 * @param array $tokens The route tokens
199 * @param integer $index The index of the current token
200 * @param integer $firstOptional The index of the first optional token
201 *
202 * @return string The regexp pattern for a single token
203 */
204 private static function computeRegexp(array $tokens, $index, $firstOptional)
205 {
206 $token = $tokens[$index];
207 if ('text' === $token[0]) {
208 // Text tokens
209 return preg_quote($token[1], self::REGEX_DELIMITER);
210 } else {
211 // Variable tokens
212 if (0 === $index && 0 === $firstOptional) {
213 // When the only token is an optional variable token, the separator is required
214 return sprintf('%s(?P<%s>%s)?', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]);
215 } else {
216 $regexp = sprintf('%s(?P<%s>%s)', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]);
217 if ($index >= $firstOptional) {
218 // Enclose each optional token in a subpattern to make it optional.
219 // "?:" means it is non-capturing, i.e. the portion of the subject string that
220 // matched the optional subpattern is not passed back.
221 $regexp = "(?:$regexp";
222 $nbTokens = count($tokens);
223 if ($nbTokens - 1 == $index) {
224 // Close the optional subpatterns
225 $regexp .= str_repeat(")?", $nbTokens - $firstOptional - (0 === $firstOptional ? 1 : 0));
226 }
227 }
228
229 return $regexp;
230 }
231 }
232 }
233}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php
new file mode 100644
index 00000000..e6f8ee6d
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php
@@ -0,0 +1,32 @@
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
12namespace Symfony\Component\Routing;
13
14/**
15 * RouteCompilerInterface is the interface that all RouteCompiler classes must implement.
16 *
17 * @author Fabien Potencier <fabien@symfony.com>
18 */
19interface RouteCompilerInterface
20{
21 /**
22 * Compiles the current route instance.
23 *
24 * @param Route $route A Route instance
25 *
26 * @return CompiledRoute A CompiledRoute instance
27 *
28 * @throws \LogicException If the Route cannot be compiled because the
29 * path or host pattern is invalid
30 */
31 public static function compile(Route $route);
32}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Router.php b/vendor/symfony/routing/Symfony/Component/Routing/Router.php
new file mode 100644
index 00000000..d1e28979
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Router.php
@@ -0,0 +1,289 @@
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
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\Config\Loader\LoaderInterface;
15use Symfony\Component\Config\ConfigCache;
16use Psr\Log\LoggerInterface;
17use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface;
18use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
19use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
20
21/**
22 * The Router class is an example of the integration of all pieces of the
23 * routing system for easier use.
24 *
25 * @author Fabien Potencier <fabien@symfony.com>
26 */
27class Router implements RouterInterface
28{
29 /**
30 * @var UrlMatcherInterface|null
31 */
32 protected $matcher;
33
34 /**
35 * @var UrlGeneratorInterface|null
36 */
37 protected $generator;
38
39 /**
40 * @var RequestContext
41 */
42 protected $context;
43
44 /**
45 * @var LoaderInterface
46 */
47 protected $loader;
48
49 /**
50 * @var RouteCollection|null
51 */
52 protected $collection;
53
54 /**
55 * @var mixed
56 */
57 protected $resource;
58
59 /**
60 * @var array
61 */
62 protected $options = array();
63
64 /**
65 * @var LoggerInterface|null
66 */
67 protected $logger;
68
69 /**
70 * Constructor.
71 *
72 * @param LoaderInterface $loader A LoaderInterface instance
73 * @param mixed $resource The main resource to load
74 * @param array $options An array of options
75 * @param RequestContext $context The context
76 * @param LoggerInterface $logger A logger instance
77 */
78 public function __construct(LoaderInterface $loader, $resource, array $options = array(), RequestContext $context = null, LoggerInterface $logger = null)
79 {
80 $this->loader = $loader;
81 $this->resource = $resource;
82 $this->logger = $logger;
83 $this->context = null === $context ? new RequestContext() : $context;
84 $this->setOptions($options);
85 }
86
87 /**
88 * Sets options.
89 *
90 * Available options:
91 *
92 * * cache_dir: The cache directory (or null to disable caching)
93 * * debug: Whether to enable debugging or not (false by default)
94 * * resource_type: Type hint for the main resource (optional)
95 *
96 * @param array $options An array of options
97 *
98 * @throws \InvalidArgumentException When unsupported option is provided
99 */
100 public function setOptions(array $options)
101 {
102 $this->options = array(
103 'cache_dir' => null,
104 'debug' => false,
105 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
106 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
107 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper',
108 'generator_cache_class' => 'ProjectUrlGenerator',
109 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
110 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
111 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper',
112 'matcher_cache_class' => 'ProjectUrlMatcher',
113 'resource_type' => null,
114 'strict_requirements' => true,
115 );
116
117 // check option names and live merge, if errors are encountered Exception will be thrown
118 $invalid = array();
119 foreach ($options as $key => $value) {
120 if (array_key_exists($key, $this->options)) {
121 $this->options[$key] = $value;
122 } else {
123 $invalid[] = $key;
124 }
125 }
126
127 if ($invalid) {
128 throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid)));
129 }
130 }
131
132 /**
133 * Sets an option.
134 *
135 * @param string $key The key
136 * @param mixed $value The value
137 *
138 * @throws \InvalidArgumentException
139 */
140 public function setOption($key, $value)
141 {
142 if (!array_key_exists($key, $this->options)) {
143 throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
144 }
145
146 $this->options[$key] = $value;
147 }
148
149 /**
150 * Gets an option value.
151 *
152 * @param string $key The key
153 *
154 * @return mixed The value
155 *
156 * @throws \InvalidArgumentException
157 */
158 public function getOption($key)
159 {
160 if (!array_key_exists($key, $this->options)) {
161 throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key));
162 }
163
164 return $this->options[$key];
165 }
166
167 /**
168 * {@inheritdoc}
169 */
170 public function getRouteCollection()
171 {
172 if (null === $this->collection) {
173 $this->collection = $this->loader->load($this->resource, $this->options['resource_type']);
174 }
175
176 return $this->collection;
177 }
178
179 /**
180 * {@inheritdoc}
181 */
182 public function setContext(RequestContext $context)
183 {
184 $this->context = $context;
185
186 if (null !== $this->matcher) {
187 $this->getMatcher()->setContext($context);
188 }
189 if (null !== $this->generator) {
190 $this->getGenerator()->setContext($context);
191 }
192 }
193
194 /**
195 * {@inheritdoc}
196 */
197 public function getContext()
198 {
199 return $this->context;
200 }
201
202 /**
203 * {@inheritdoc}
204 */
205 public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
206 {
207 return $this->getGenerator()->generate($name, $parameters, $referenceType);
208 }
209
210 /**
211 * {@inheritdoc}
212 */
213 public function match($pathinfo)
214 {
215 return $this->getMatcher()->match($pathinfo);
216 }
217
218 /**
219 * Gets the UrlMatcher instance associated with this Router.
220 *
221 * @return UrlMatcherInterface A UrlMatcherInterface instance
222 */
223 public function getMatcher()
224 {
225 if (null !== $this->matcher) {
226 return $this->matcher;
227 }
228
229 if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) {
230 return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context);
231 }
232
233 $class = $this->options['matcher_cache_class'];
234 $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
235 if (!$cache->isFresh($class)) {
236 $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection());
237
238 $options = array(
239 'class' => $class,
240 'base_class' => $this->options['matcher_base_class'],
241 );
242
243 $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
244 }
245
246 require_once $cache;
247
248 return $this->matcher = new $class($this->context);
249 }
250
251 /**
252 * Gets the UrlGenerator instance associated with this Router.
253 *
254 * @return UrlGeneratorInterface A UrlGeneratorInterface instance
255 */
256 public function getGenerator()
257 {
258 if (null !== $this->generator) {
259 return $this->generator;
260 }
261
262 if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) {
263 $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->logger);
264 } else {
265 $class = $this->options['generator_cache_class'];
266 $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']);
267 if (!$cache->isFresh($class)) {
268 $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection());
269
270 $options = array(
271 'class' => $class,
272 'base_class' => $this->options['generator_base_class'],
273 );
274
275 $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources());
276 }
277
278 require_once $cache;
279
280 $this->generator = new $class($this->context, $this->logger);
281 }
282
283 if ($this->generator instanceof ConfigurableRequirementsInterface) {
284 $this->generator->setStrictRequirements($this->options['strict_requirements']);
285 }
286
287 return $this->generator;
288 }
289}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php b/vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php
new file mode 100644
index 00000000..a10ae34e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php
@@ -0,0 +1,32 @@
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
12namespace Symfony\Component\Routing;
13
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
16
17/**
18 * RouterInterface is the interface that all Router classes must implement.
19 *
20 * This interface is the concatenation of UrlMatcherInterface and UrlGeneratorInterface.
21 *
22 * @author Fabien Potencier <fabien@symfony.com>
23 */
24interface RouterInterface extends UrlMatcherInterface, UrlGeneratorInterface
25{
26 /**
27 * Gets the RouteCollection instance associated with this Router.
28 *
29 * @return RouteCollection A RouteCollection instance
30 */
31 public function getRouteCollection();
32}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
new file mode 100644
index 00000000..b58869f7
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
@@ -0,0 +1,49 @@
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
12namespace Symfony\Component\Routing\Tests\Annotation;
13
14use Symfony\Component\Routing\Annotation\Route;
15
16class RouteTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @expectedException \BadMethodCallException
20 */
21 public function testInvalidRouteParameter()
22 {
23 $route = new Route(array('foo' => 'bar'));
24 }
25
26 /**
27 * @dataProvider getValidParameters
28 */
29 public function testRouteParameters($parameter, $value, $getter)
30 {
31 $route = new Route(array($parameter => $value));
32 $this->assertEquals($route->$getter(), $value);
33 }
34
35 public function getValidParameters()
36 {
37 return array(
38 array('value', '/Blog', 'getPattern'),
39 array('value', '/Blog', 'getPath'),
40 array('requirements', array('_method' => 'GET'), 'getRequirements'),
41 array('options', array('compiler_class' => 'RouteCompiler'), 'getOptions'),
42 array('name', 'blog_index', 'getName'),
43 array('defaults', array('_controller' => 'MyBlogBundle:Blog:index'), 'getDefaults'),
44 array('schemes', array('https'), 'getSchemes'),
45 array('methods', array('GET', 'POST'), 'getMethods'),
46 array('host', array('{locale}.example.com'), 'getHost')
47 );
48 }
49}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php
new file mode 100644
index 00000000..215ebb70
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/CompiledRouteTest.php
@@ -0,0 +1,26 @@
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
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\CompiledRoute;
15
16class CompiledRouteTest extends \PHPUnit_Framework_TestCase
17{
18 public function testAccessors()
19 {
20 $compiled = new CompiledRoute('prefix', 'regex', array('tokens'), array(), array(), array(), array(), array('variables'));
21 $this->assertEquals('prefix', $compiled->getStaticPrefix(), '__construct() takes a static prefix as its second argument');
22 $this->assertEquals('regex', $compiled->getRegex(), '__construct() takes a regexp as its third argument');
23 $this->assertEquals(array('tokens'), $compiled->getTokens(), '__construct() takes an array of tokens as its fourth argument');
24 $this->assertEquals(array('variables'), $compiled->getVariables(), '__construct() takes an array of variables as its ninth argument');
25 }
26}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php
new file mode 100644
index 00000000..56bcab2a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php
@@ -0,0 +1,16 @@
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
12namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
13
14abstract class AbstractClass
15{
16}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php
new file mode 100644
index 00000000..a3882773
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/BarClass.php
@@ -0,0 +1,19 @@
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
12namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
13
14class BarClass
15{
16 public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3')
17 {
18 }
19}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php
new file mode 100644
index 00000000..320dc350
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooClass.php
@@ -0,0 +1,16 @@
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
12namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
13
14class FooClass
15{
16}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php
new file mode 100644
index 00000000..12a5bedb
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/CustomXmlFileLoader.php
@@ -0,0 +1,26 @@
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
12namespace Symfony\Component\Routing\Tests\Fixtures;
13
14use Symfony\Component\Routing\Loader\XmlFileLoader;
15use Symfony\Component\Config\Util\XmlUtils;
16
17/**
18 * XmlFileLoader with schema validation turned off
19 */
20class CustomXmlFileLoader extends XmlFileLoader
21{
22 protected function loadFile($file)
23 {
24 return XmlUtils::loadFile($file, function() { return true; });
25 }
26}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php
new file mode 100644
index 00000000..e95c1f26
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/RedirectableUrlMatcher.php
@@ -0,0 +1,30 @@
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
12namespace Symfony\Component\Routing\Tests\Fixtures;
13
14use Symfony\Component\Routing\Matcher\UrlMatcher;
15use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
16
17/**
18 * @author Fabien Potencier <fabien@symfony.com>
19 */
20class RedirectableUrlMatcher extends UrlMatcher implements RedirectableUrlMatcherInterface
21{
22 public function redirect($path, $route, $scheme = null)
23 {
24 return array(
25 '_controller' => 'Some controller reference...',
26 'path' => $path,
27 'scheme' => $scheme,
28 );
29 }
30}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/annotated.php
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache
new file mode 100644
index 00000000..26a561cc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache
@@ -0,0 +1,163 @@
1# skip "real" requests
2RewriteCond %{REQUEST_FILENAME} -f
3RewriteRule .* - [QSA,L]
4
5# foo
6RewriteCond %{REQUEST_URI} ^/foo/(baz|symfony)$
7RewriteRule .* app.php [QSA,L,E=_ROUTING_route:foo,E=_ROUTING_param_bar:%1,E=_ROUTING_default_def:test]
8
9# foobar
10RewriteCond %{REQUEST_URI} ^/foo(?:/([^/]++))?$
11RewriteRule .* app.php [QSA,L,E=_ROUTING_route:foobar,E=_ROUTING_param_bar:%1,E=_ROUTING_default_bar:toto]
12
13# bar
14RewriteCond %{REQUEST_URI} ^/bar/([^/]++)$
15RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
16RewriteRule .* - [S=1,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_HEAD:1]
17RewriteCond %{REQUEST_URI} ^/bar/([^/]++)$
18RewriteRule .* app.php [QSA,L,E=_ROUTING_route:bar,E=_ROUTING_param_foo:%1]
19
20# baragain
21RewriteCond %{REQUEST_URI} ^/baragain/([^/]++)$
22RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$ [NC]
23RewriteRule .* - [S=1,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_POST:1,E=_ROUTING_allow_HEAD:1]
24RewriteCond %{REQUEST_URI} ^/baragain/([^/]++)$
25RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baragain,E=_ROUTING_param_foo:%1]
26
27# baz
28RewriteCond %{REQUEST_URI} ^/test/baz$
29RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz]
30
31# baz2
32RewriteCond %{REQUEST_URI} ^/test/baz\.html$
33RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz2]
34
35# baz3
36RewriteCond %{REQUEST_URI} ^/test/baz3$
37RewriteRule .* $0/ [QSA,L,R=301]
38RewriteCond %{REQUEST_URI} ^/test/baz3/$
39RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz3]
40
41# baz4
42RewriteCond %{REQUEST_URI} ^/test/([^/]++)$
43RewriteRule .* $0/ [QSA,L,R=301]
44RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
45RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz4,E=_ROUTING_param_foo:%1]
46
47# baz5
48RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
49RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC]
50RewriteRule .* - [S=2,E=_ROUTING_allow_GET:1,E=_ROUTING_allow_HEAD:1]
51RewriteCond %{REQUEST_URI} ^/test/([^/]++)$
52RewriteRule .* $0/ [QSA,L,R=301]
53RewriteCond %{REQUEST_URI} ^/test/([^/]++)/$
54RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz5,E=_ROUTING_param_foo:%1]
55
56# baz5unsafe
57RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]++)/$
58RewriteCond %{REQUEST_METHOD} !^(POST)$ [NC]
59RewriteRule .* - [S=1,E=_ROUTING_allow_POST:1]
60RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]++)/$
61RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz5unsafe,E=_ROUTING_param_foo:%1]
62
63# baz6
64RewriteCond %{REQUEST_URI} ^/test/baz$
65RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz6,E=_ROUTING_default_foo:bar\ baz]
66
67# baz7
68RewriteCond %{REQUEST_URI} ^/te\ st/baz$
69RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz7]
70
71# baz8
72RewriteCond %{REQUEST_URI} ^/te\\\ st/baz$
73RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz8]
74
75# baz9
76RewriteCond %{REQUEST_URI} ^/test/(te\\\ st)$
77RewriteRule .* app.php [QSA,L,E=_ROUTING_route:baz9,E=_ROUTING_param_baz:%1]
78
79RewriteCond %{HTTP:Host} ^a\.example\.com$
80RewriteRule .? - [E=__ROUTING_host_1:1]
81
82# route1
83RewriteCond %{ENV:__ROUTING_host_1} =1
84RewriteCond %{REQUEST_URI} ^/route1$
85RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route1]
86
87# route2
88RewriteCond %{ENV:__ROUTING_host_1} =1
89RewriteCond %{REQUEST_URI} ^/c2/route2$
90RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route2]
91
92RewriteCond %{HTTP:Host} ^b\.example\.com$
93RewriteRule .? - [E=__ROUTING_host_2:1]
94
95# route3
96RewriteCond %{ENV:__ROUTING_host_2} =1
97RewriteCond %{REQUEST_URI} ^/c2/route3$
98RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route3]
99
100RewriteCond %{HTTP:Host} ^a\.example\.com$
101RewriteRule .? - [E=__ROUTING_host_3:1]
102
103# route4
104RewriteCond %{ENV:__ROUTING_host_3} =1
105RewriteCond %{REQUEST_URI} ^/route4$
106RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route4]
107
108RewriteCond %{HTTP:Host} ^c\.example\.com$
109RewriteRule .? - [E=__ROUTING_host_4:1]
110
111# route5
112RewriteCond %{ENV:__ROUTING_host_4} =1
113RewriteCond %{REQUEST_URI} ^/route5$
114RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route5]
115
116# route6
117RewriteCond %{REQUEST_URI} ^/route6$
118RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route6]
119
120RewriteCond %{HTTP:Host} ^([^\.]++)\.example\.com$
121RewriteRule .? - [E=__ROUTING_host_5:1,E=__ROUTING_host_5_var1:%1]
122
123# route11
124RewriteCond %{ENV:__ROUTING_host_5} =1
125RewriteCond %{REQUEST_URI} ^/route11$
126RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route11,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1}]
127
128# route12
129RewriteCond %{ENV:__ROUTING_host_5} =1
130RewriteCond %{REQUEST_URI} ^/route12$
131RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route12,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_default_var1:val]
132
133# route13
134RewriteCond %{ENV:__ROUTING_host_5} =1
135RewriteCond %{REQUEST_URI} ^/route13/([^/]++)$
136RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route13,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_param_name:%1]
137
138# route14
139RewriteCond %{ENV:__ROUTING_host_5} =1
140RewriteCond %{REQUEST_URI} ^/route14/([^/]++)$
141RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route14,E=_ROUTING_param_var1:%{ENV:__ROUTING_host_5_var1},E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
142
143RewriteCond %{HTTP:Host} ^c\.example\.com$
144RewriteRule .? - [E=__ROUTING_host_6:1]
145
146# route15
147RewriteCond %{ENV:__ROUTING_host_6} =1
148RewriteCond %{REQUEST_URI} ^/route15/([^/]++)$
149RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route15,E=_ROUTING_param_name:%1]
150
151# route16
152RewriteCond %{REQUEST_URI} ^/route16/([^/]++)$
153RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route16,E=_ROUTING_param_name:%1,E=_ROUTING_default_var1:val]
154
155# route17
156RewriteCond %{REQUEST_URI} ^/route17$
157RewriteRule .* app.php [QSA,L,E=_ROUTING_route:route17]
158
159# 405 Method Not Allowed
160RewriteCond %{ENV:_ROUTING__allow_GET} =1 [OR]
161RewriteCond %{ENV:_ROUTING__allow_HEAD} =1 [OR]
162RewriteCond %{ENV:_ROUTING__allow_POST} =1
163RewriteRule .* app.php [QSA,L]
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
new file mode 100644
index 00000000..e5f7665c
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
@@ -0,0 +1,310 @@
1<?php
2
3use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4use Symfony\Component\Routing\Exception\ResourceNotFoundException;
5use Symfony\Component\Routing\RequestContext;
6
7/**
8 * ProjectUrlMatcher
9 *
10 * This class has been auto-generated
11 * by the Symfony Routing Component.
12 */
13class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
14{
15 /**
16 * Constructor.
17 */
18 public function __construct(RequestContext $context)
19 {
20 $this->context = $context;
21 }
22
23 public function match($pathinfo)
24 {
25 $allow = array();
26 $pathinfo = rawurldecode($pathinfo);
27
28 // foo
29 if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
30 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo')), array ( 'def' => 'test',));
31 }
32
33 if (0 === strpos($pathinfo, '/bar')) {
34 // bar
35 if (preg_match('#^/bar/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
36 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
37 $allow = array_merge($allow, array('GET', 'HEAD'));
38 goto not_bar;
39 }
40
41 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar')), array ());
42 }
43 not_bar:
44
45 // barhead
46 if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
47 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
48 $allow = array_merge($allow, array('GET', 'HEAD'));
49 goto not_barhead;
50 }
51
52 return $this->mergeDefaults(array_replace($matches, array('_route' => 'barhead')), array ());
53 }
54 not_barhead:
55
56 }
57
58 if (0 === strpos($pathinfo, '/test')) {
59 if (0 === strpos($pathinfo, '/test/baz')) {
60 // baz
61 if ($pathinfo === '/test/baz') {
62 return array('_route' => 'baz');
63 }
64
65 // baz2
66 if ($pathinfo === '/test/baz.html') {
67 return array('_route' => 'baz2');
68 }
69
70 // baz3
71 if ($pathinfo === '/test/baz3/') {
72 return array('_route' => 'baz3');
73 }
74
75 }
76
77 // baz4
78 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
79 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
80 }
81
82 // baz5
83 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
84 if ($this->context->getMethod() != 'POST') {
85 $allow[] = 'POST';
86 goto not_baz5;
87 }
88
89 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz5')), array ());
90 }
91 not_baz5:
92
93 // baz.baz6
94 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
95 if ($this->context->getMethod() != 'PUT') {
96 $allow[] = 'PUT';
97 goto not_bazbaz6;
98 }
99
100 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz.baz6')), array ());
101 }
102 not_bazbaz6:
103
104 }
105
106 // foofoo
107 if ($pathinfo === '/foofoo') {
108 return array ( 'def' => 'test', '_route' => 'foofoo',);
109 }
110
111 // quoter
112 if (preg_match('#^/(?P<quoter>[\']+)$#s', $pathinfo, $matches)) {
113 return $this->mergeDefaults(array_replace($matches, array('_route' => 'quoter')), array ());
114 }
115
116 // space
117 if ($pathinfo === '/spa ce') {
118 return array('_route' => 'space');
119 }
120
121 if (0 === strpos($pathinfo, '/a')) {
122 if (0 === strpos($pathinfo, '/a/b\'b')) {
123 // foo1
124 if (preg_match('#^/a/b\'b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
125 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo1')), array ());
126 }
127
128 // bar1
129 if (preg_match('#^/a/b\'b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
130 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar1')), array ());
131 }
132
133 }
134
135 // overridden
136 if (preg_match('#^/a/(?P<var>.*)$#s', $pathinfo, $matches)) {
137 return $this->mergeDefaults(array_replace($matches, array('_route' => 'overridden')), array ());
138 }
139
140 if (0 === strpos($pathinfo, '/a/b\'b')) {
141 // foo2
142 if (preg_match('#^/a/b\'b/(?P<foo1>[^/]++)$#s', $pathinfo, $matches)) {
143 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo2')), array ());
144 }
145
146 // bar2
147 if (preg_match('#^/a/b\'b/(?P<bar1>[^/]++)$#s', $pathinfo, $matches)) {
148 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar2')), array ());
149 }
150
151 }
152
153 }
154
155 if (0 === strpos($pathinfo, '/multi')) {
156 // helloWorld
157 if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P<who>[^/]++))?$#s', $pathinfo, $matches)) {
158 return $this->mergeDefaults(array_replace($matches, array('_route' => 'helloWorld')), array ( 'who' => 'World!',));
159 }
160
161 // overridden2
162 if ($pathinfo === '/multi/new') {
163 return array('_route' => 'overridden2');
164 }
165
166 // hey
167 if ($pathinfo === '/multi/hey/') {
168 return array('_route' => 'hey');
169 }
170
171 }
172
173 // foo3
174 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
175 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo3')), array ());
176 }
177
178 // bar3
179 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
180 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar3')), array ());
181 }
182
183 if (0 === strpos($pathinfo, '/aba')) {
184 // ababa
185 if ($pathinfo === '/ababa') {
186 return array('_route' => 'ababa');
187 }
188
189 // foo4
190 if (preg_match('#^/aba/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
191 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo4')), array ());
192 }
193
194 }
195
196 $host = $this->context->getHost();
197
198 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
199 // route1
200 if ($pathinfo === '/route1') {
201 return array('_route' => 'route1');
202 }
203
204 // route2
205 if ($pathinfo === '/c2/route2') {
206 return array('_route' => 'route2');
207 }
208
209 }
210
211 if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
212 // route3
213 if ($pathinfo === '/c2/route3') {
214 return array('_route' => 'route3');
215 }
216
217 }
218
219 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
220 // route4
221 if ($pathinfo === '/route4') {
222 return array('_route' => 'route4');
223 }
224
225 }
226
227 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
228 // route5
229 if ($pathinfo === '/route5') {
230 return array('_route' => 'route5');
231 }
232
233 }
234
235 // route6
236 if ($pathinfo === '/route6') {
237 return array('_route' => 'route6');
238 }
239
240 if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
241 if (0 === strpos($pathinfo, '/route1')) {
242 // route11
243 if ($pathinfo === '/route11') {
244 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route11')), array ());
245 }
246
247 // route12
248 if ($pathinfo === '/route12') {
249 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route12')), array ( 'var1' => 'val',));
250 }
251
252 // route13
253 if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
254 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route13')), array ());
255 }
256
257 // route14
258 if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
259 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route14')), array ( 'var1' => 'val',));
260 }
261
262 }
263
264 }
265
266 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
267 // route15
268 if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
269 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());
270 }
271
272 }
273
274 if (0 === strpos($pathinfo, '/route1')) {
275 // route16
276 if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
277 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route16')), array ( 'var1' => 'val',));
278 }
279
280 // route17
281 if ($pathinfo === '/route17') {
282 return array('_route' => 'route17');
283 }
284
285 }
286
287 if (0 === strpos($pathinfo, '/a')) {
288 // a
289 if ($pathinfo === '/a/a...') {
290 return array('_route' => 'a');
291 }
292
293 if (0 === strpos($pathinfo, '/a/b')) {
294 // b
295 if (preg_match('#^/a/b/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
296 return $this->mergeDefaults(array_replace($matches, array('_route' => 'b')), array ());
297 }
298
299 // c
300 if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
301 return $this->mergeDefaults(array_replace($matches, array('_route' => 'c')), array ());
302 }
303
304 }
305
306 }
307
308 throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
309 }
310}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache
new file mode 100644
index 00000000..309f2ff0
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.apache
@@ -0,0 +1,7 @@
1# skip "real" requests
2RewriteCond %{REQUEST_FILENAME} -f
3RewriteRule .* - [QSA,L]
4
5# foo
6RewriteCond %{REQUEST_URI} ^/foo$
7RewriteRule .* ap\ p_d\ ev.php [QSA,L,E=_ROUTING_route:foo]
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
new file mode 100644
index 00000000..ad157909
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
@@ -0,0 +1,340 @@
1<?php
2
3use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4use Symfony\Component\Routing\Exception\ResourceNotFoundException;
5use Symfony\Component\Routing\RequestContext;
6
7/**
8 * ProjectUrlMatcher
9 *
10 * This class has been auto-generated
11 * by the Symfony Routing Component.
12 */
13class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher
14{
15 /**
16 * Constructor.
17 */
18 public function __construct(RequestContext $context)
19 {
20 $this->context = $context;
21 }
22
23 public function match($pathinfo)
24 {
25 $allow = array();
26 $pathinfo = rawurldecode($pathinfo);
27
28 // foo
29 if (0 === strpos($pathinfo, '/foo') && preg_match('#^/foo/(?P<bar>baz|symfony)$#s', $pathinfo, $matches)) {
30 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo')), array ( 'def' => 'test',));
31 }
32
33 if (0 === strpos($pathinfo, '/bar')) {
34 // bar
35 if (preg_match('#^/bar/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
36 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
37 $allow = array_merge($allow, array('GET', 'HEAD'));
38 goto not_bar;
39 }
40
41 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar')), array ());
42 }
43 not_bar:
44
45 // barhead
46 if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
47 if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) {
48 $allow = array_merge($allow, array('GET', 'HEAD'));
49 goto not_barhead;
50 }
51
52 return $this->mergeDefaults(array_replace($matches, array('_route' => 'barhead')), array ());
53 }
54 not_barhead:
55
56 }
57
58 if (0 === strpos($pathinfo, '/test')) {
59 if (0 === strpos($pathinfo, '/test/baz')) {
60 // baz
61 if ($pathinfo === '/test/baz') {
62 return array('_route' => 'baz');
63 }
64
65 // baz2
66 if ($pathinfo === '/test/baz.html') {
67 return array('_route' => 'baz2');
68 }
69
70 // baz3
71 if (rtrim($pathinfo, '/') === '/test/baz3') {
72 if (substr($pathinfo, -1) !== '/') {
73 return $this->redirect($pathinfo.'/', 'baz3');
74 }
75
76 return array('_route' => 'baz3');
77 }
78
79 }
80
81 // baz4
82 if (preg_match('#^/test/(?P<foo>[^/]++)/?$#s', $pathinfo, $matches)) {
83 if (substr($pathinfo, -1) !== '/') {
84 return $this->redirect($pathinfo.'/', 'baz4');
85 }
86
87 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz4')), array ());
88 }
89
90 // baz5
91 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
92 if ($this->context->getMethod() != 'POST') {
93 $allow[] = 'POST';
94 goto not_baz5;
95 }
96
97 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz5')), array ());
98 }
99 not_baz5:
100
101 // baz.baz6
102 if (preg_match('#^/test/(?P<foo>[^/]++)/$#s', $pathinfo, $matches)) {
103 if ($this->context->getMethod() != 'PUT') {
104 $allow[] = 'PUT';
105 goto not_bazbaz6;
106 }
107
108 return $this->mergeDefaults(array_replace($matches, array('_route' => 'baz.baz6')), array ());
109 }
110 not_bazbaz6:
111
112 }
113
114 // foofoo
115 if ($pathinfo === '/foofoo') {
116 return array ( 'def' => 'test', '_route' => 'foofoo',);
117 }
118
119 // quoter
120 if (preg_match('#^/(?P<quoter>[\']+)$#s', $pathinfo, $matches)) {
121 return $this->mergeDefaults(array_replace($matches, array('_route' => 'quoter')), array ());
122 }
123
124 // space
125 if ($pathinfo === '/spa ce') {
126 return array('_route' => 'space');
127 }
128
129 if (0 === strpos($pathinfo, '/a')) {
130 if (0 === strpos($pathinfo, '/a/b\'b')) {
131 // foo1
132 if (preg_match('#^/a/b\'b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
133 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo1')), array ());
134 }
135
136 // bar1
137 if (preg_match('#^/a/b\'b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
138 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar1')), array ());
139 }
140
141 }
142
143 // overridden
144 if (preg_match('#^/a/(?P<var>.*)$#s', $pathinfo, $matches)) {
145 return $this->mergeDefaults(array_replace($matches, array('_route' => 'overridden')), array ());
146 }
147
148 if (0 === strpos($pathinfo, '/a/b\'b')) {
149 // foo2
150 if (preg_match('#^/a/b\'b/(?P<foo1>[^/]++)$#s', $pathinfo, $matches)) {
151 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo2')), array ());
152 }
153
154 // bar2
155 if (preg_match('#^/a/b\'b/(?P<bar1>[^/]++)$#s', $pathinfo, $matches)) {
156 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar2')), array ());
157 }
158
159 }
160
161 }
162
163 if (0 === strpos($pathinfo, '/multi')) {
164 // helloWorld
165 if (0 === strpos($pathinfo, '/multi/hello') && preg_match('#^/multi/hello(?:/(?P<who>[^/]++))?$#s', $pathinfo, $matches)) {
166 return $this->mergeDefaults(array_replace($matches, array('_route' => 'helloWorld')), array ( 'who' => 'World!',));
167 }
168
169 // overridden2
170 if ($pathinfo === '/multi/new') {
171 return array('_route' => 'overridden2');
172 }
173
174 // hey
175 if (rtrim($pathinfo, '/') === '/multi/hey') {
176 if (substr($pathinfo, -1) !== '/') {
177 return $this->redirect($pathinfo.'/', 'hey');
178 }
179
180 return array('_route' => 'hey');
181 }
182
183 }
184
185 // foo3
186 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
187 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo3')), array ());
188 }
189
190 // bar3
191 if (preg_match('#^/(?P<_locale>[^/]++)/b/(?P<bar>[^/]++)$#s', $pathinfo, $matches)) {
192 return $this->mergeDefaults(array_replace($matches, array('_route' => 'bar3')), array ());
193 }
194
195 if (0 === strpos($pathinfo, '/aba')) {
196 // ababa
197 if ($pathinfo === '/ababa') {
198 return array('_route' => 'ababa');
199 }
200
201 // foo4
202 if (preg_match('#^/aba/(?P<foo>[^/]++)$#s', $pathinfo, $matches)) {
203 return $this->mergeDefaults(array_replace($matches, array('_route' => 'foo4')), array ());
204 }
205
206 }
207
208 $host = $this->context->getHost();
209
210 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
211 // route1
212 if ($pathinfo === '/route1') {
213 return array('_route' => 'route1');
214 }
215
216 // route2
217 if ($pathinfo === '/c2/route2') {
218 return array('_route' => 'route2');
219 }
220
221 }
222
223 if (preg_match('#^b\\.example\\.com$#s', $host, $hostMatches)) {
224 // route3
225 if ($pathinfo === '/c2/route3') {
226 return array('_route' => 'route3');
227 }
228
229 }
230
231 if (preg_match('#^a\\.example\\.com$#s', $host, $hostMatches)) {
232 // route4
233 if ($pathinfo === '/route4') {
234 return array('_route' => 'route4');
235 }
236
237 }
238
239 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
240 // route5
241 if ($pathinfo === '/route5') {
242 return array('_route' => 'route5');
243 }
244
245 }
246
247 // route6
248 if ($pathinfo === '/route6') {
249 return array('_route' => 'route6');
250 }
251
252 if (preg_match('#^(?P<var1>[^\\.]++)\\.example\\.com$#s', $host, $hostMatches)) {
253 if (0 === strpos($pathinfo, '/route1')) {
254 // route11
255 if ($pathinfo === '/route11') {
256 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route11')), array ());
257 }
258
259 // route12
260 if ($pathinfo === '/route12') {
261 return $this->mergeDefaults(array_replace($hostMatches, array('_route' => 'route12')), array ( 'var1' => 'val',));
262 }
263
264 // route13
265 if (0 === strpos($pathinfo, '/route13') && preg_match('#^/route13/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
266 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route13')), array ());
267 }
268
269 // route14
270 if (0 === strpos($pathinfo, '/route14') && preg_match('#^/route14/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
271 return $this->mergeDefaults(array_replace($hostMatches, $matches, array('_route' => 'route14')), array ( 'var1' => 'val',));
272 }
273
274 }
275
276 }
277
278 if (preg_match('#^c\\.example\\.com$#s', $host, $hostMatches)) {
279 // route15
280 if (0 === strpos($pathinfo, '/route15') && preg_match('#^/route15/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
281 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route15')), array ());
282 }
283
284 }
285
286 if (0 === strpos($pathinfo, '/route1')) {
287 // route16
288 if (0 === strpos($pathinfo, '/route16') && preg_match('#^/route16/(?P<name>[^/]++)$#s', $pathinfo, $matches)) {
289 return $this->mergeDefaults(array_replace($matches, array('_route' => 'route16')), array ( 'var1' => 'val',));
290 }
291
292 // route17
293 if ($pathinfo === '/route17') {
294 return array('_route' => 'route17');
295 }
296
297 }
298
299 if (0 === strpos($pathinfo, '/a')) {
300 // a
301 if ($pathinfo === '/a/a...') {
302 return array('_route' => 'a');
303 }
304
305 if (0 === strpos($pathinfo, '/a/b')) {
306 // b
307 if (preg_match('#^/a/b/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
308 return $this->mergeDefaults(array_replace($matches, array('_route' => 'b')), array ());
309 }
310
311 // c
312 if (0 === strpos($pathinfo, '/a/b/c') && preg_match('#^/a/b/c/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
313 return $this->mergeDefaults(array_replace($matches, array('_route' => 'c')), array ());
314 }
315
316 }
317
318 }
319
320 // secure
321 if ($pathinfo === '/secure') {
322 if ($this->context->getScheme() !== 'https') {
323 return $this->redirect($pathinfo, 'secure', 'https');
324 }
325
326 return array('_route' => 'secure');
327 }
328
329 // nonsecure
330 if ($pathinfo === '/nonsecure') {
331 if ($this->context->getScheme() !== 'http') {
332 return $this->redirect($pathinfo, 'nonsecure', 'http');
333 }
334
335 return array('_route' => 'nonsecure');
336 }
337
338 throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
339 }
340}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
new file mode 100644
index 00000000..f2f642eb
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php
@@ -0,0 +1,43 @@
1<?php
2
3use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4use Symfony\Component\Routing\Exception\ResourceNotFoundException;
5use Symfony\Component\Routing\RequestContext;
6
7/**
8 * ProjectUrlMatcher
9 *
10 * This class has been auto-generated
11 * by the Symfony Routing Component.
12 */
13class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
14{
15 /**
16 * Constructor.
17 */
18 public function __construct(RequestContext $context)
19 {
20 $this->context = $context;
21 }
22
23 public function match($pathinfo)
24 {
25 $allow = array();
26 $pathinfo = rawurldecode($pathinfo);
27
28 if (0 === strpos($pathinfo, '/rootprefix')) {
29 // static
30 if ($pathinfo === '/rootprefix/test') {
31 return array('_route' => 'static');
32 }
33
34 // dynamic
35 if (preg_match('#^/rootprefix/(?P<var>[^/]++)$#s', $pathinfo, $matches)) {
36 return $this->mergeDefaults(array_replace($matches, array('_route' => 'dynamic')), array ());
37 }
38
39 }
40
41 throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
42 }
43}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/empty.yml
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo.xml
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/foo1.xml
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml
new file mode 100644
index 00000000..df64d324
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/incomplete.yml
@@ -0,0 +1,2 @@
1blog_show:
2 defaults: { _controller: MyBlogBundle:Blog:show }
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml
new file mode 100644
index 00000000..4ea4115f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_id.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route path="/test"></route>
8</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml
new file mode 100644
index 00000000..ef5bc088
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/missing_path.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="myroute"></route>
8</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml
new file mode 100644
index 00000000..bdd6a473
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/namespaceprefix.xml
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<r:routes xmlns:r="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <r:route id="blog_show" path="/blog/{slug}" host="{_locale}.example.com">
8 <r:default key="_controller">MyBundle:Blog:show</r:default>
9 <requirement xmlns="http://symfony.com/schema/routing" key="slug">\w+</requirement>
10 <r2:requirement xmlns:r2="http://symfony.com/schema/routing" key="_locale">en|fr|de</r2:requirement>
11 <r:option key="compiler_class">RouteCompiler</r:option>
12 </r:route>
13</r:routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml
new file mode 100644
index 00000000..a3e94737
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_resource_plus_path.yml
@@ -0,0 +1,3 @@
1blog_show:
2 resource: validpattern.yml
3 path: /test
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml
new file mode 100644
index 00000000..547cda3b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonesense_type_without_resource.yml
@@ -0,0 +1,3 @@
1blog_show:
2 path: /blog/{slug}
3 type: custom
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml
new file mode 100644
index 00000000..755e4430
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.xml
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="blog_show" path="/blog/{slug}">
8 <default key="_controller">MyBundle:Blog:show</default>
9 <requirement key="_method">GET</requirement>
10 <!-- </route> -->
11</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml
new file mode 100644
index 00000000..257cc564
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid.yml
@@ -0,0 +1 @@
foo
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml
new file mode 100644
index 00000000..cfa9992b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalid2.yml
@@ -0,0 +1 @@
route: string
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml
new file mode 100644
index 00000000..015e270f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidkeys.yml
@@ -0,0 +1,3 @@
1someroute:
2 resource: path/to/some.yml
3 name_prefix: test_
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml
new file mode 100644
index 00000000..863ef03b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidnode.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <foo>bar</foo>
8</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml
new file mode 100644
index 00000000..a46961ee
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/nonvalidroute.xml
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="blog_show" path="/blog/{slug}">
8 <default key="_controller">MyBundle:Blog:show</default>
9 <requirement key="_method">GET</requirement>
10 <option key="compiler_class">RouteCompiler</option>
11 <foo key="bar">baz</foo>
12 </route>
13</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml
new file mode 100644
index 00000000..78be239a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/special_route_name.yml
@@ -0,0 +1,2 @@
1"#$péß^a|":
2 path: "true"
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
new file mode 100644
index 00000000..b8bbbb5f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.php
@@ -0,0 +1,23 @@
1<?php
2use Symfony\Component\Routing\RouteCollection;
3use Symfony\Component\Routing\Route;
4
5$collection = new RouteCollection();
6$collection->add('blog_show', new Route(
7 '/blog/{slug}',
8 array('_controller' => 'MyBlogBundle:Blog:show'),
9 array('locale' => '\w+'),
10 array('compiler_class' => 'RouteCompiler'),
11 '{locale}.example.com',
12 array('https'),
13 array('GET','POST','put','OpTiOnS')
14));
15$collection->add('blog_show_legacy', new Route(
16 '/blog/{slug}',
17 array('_controller' => 'MyBlogBundle:Blog:show'),
18 array('_method' => 'GET|POST|put|OpTiOnS', '_scheme' => 'https', 'locale' => '\w+',),
19 array('compiler_class' => 'RouteCompiler'),
20 '{locale}.example.com'
21));
22
23return $collection;
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
new file mode 100644
index 00000000..b9f22347
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <route id="blog_show" path="/blog/{slug}" host="{locale}.example.com" methods="GET|POST put,OpTiOnS" schemes="hTTps">
8 <default key="_controller">MyBundle:Blog:show</default>
9 <requirement key="locale">\w+</requirement>
10 <option key="compiler_class">RouteCompiler</option>
11 </route>
12
13 <route id="blog_show_legacy" pattern="/blog/{slug}" host="{locale}.example.com">
14 <default key="_controller">MyBundle:Blog:show</default>
15 <default key="slug" xsi:nil="true" />
16 <requirement key="_method">GET|POST|put|OpTiOnS</requirement>
17 <requirement key="_scheme">hTTps</requirement>
18 <requirement key="locale">\w+</requirement>
19 <option key="compiler_class">RouteCompiler</option>
20 </route>
21</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
new file mode 100644
index 00000000..4ada8832
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml
@@ -0,0 +1,17 @@
1blog_show:
2 path: /blog/{slug}
3 defaults: { _controller: "MyBundle:Blog:show" }
4 host: "{locale}.example.com"
5 requirements: { 'locale': '\w+' }
6 methods: ['GET','POST','put','OpTiOnS']
7 schemes: ['https']
8 options:
9 compiler_class: RouteCompiler
10
11blog_show_legacy:
12 pattern: /blog/{slug}
13 defaults: { _controller: "MyBundle:Blog:show" }
14 host: "{locale}.example.com"
15 requirements: { '_method': 'GET|POST|put|OpTiOnS', _scheme: https, 'locale': '\w+' }
16 options:
17 compiler_class: RouteCompiler
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml
new file mode 100644
index 00000000..295c3cc4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.xml
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<routes xmlns="http://symfony.com/schema/routing"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
6
7 <import resource="validpattern.xml" prefix="/{foo}" host="">
8 <default key="foo">123</default>
9 <requirement key="foo">\d+</requirement>
10 <option key="foo">bar</option>
11 </import>
12</routes>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml
new file mode 100644
index 00000000..495ed854
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/validresource.yml
@@ -0,0 +1,7 @@
1_blog:
2 resource: validpattern.yml
3 prefix: /{foo}
4 defaults: { 'foo': '123' }
5 requirements: { 'foo': '\d+' }
6 options: { 'foo': 'bar' }
7 host: ""
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml
new file mode 100644
index 00000000..f217d5bc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Fixtures/withdoctype.xml
@@ -0,0 +1,3 @@
1<?xml version="1.0"?>
2<!DOCTYPE foo>
3<foo></foo>
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
new file mode 100644
index 00000000..ab5f4cda
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
@@ -0,0 +1,117 @@
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
12namespace Symfony\Component\Routing\Tests\Generator\Dumper;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper;
17use Symfony\Component\Routing\RequestContext;
18
19class PhpGeneratorDumperTest extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var RouteCollection
23 */
24 private $routeCollection;
25
26 /**
27 * @var PhpGeneratorDumper
28 */
29 private $generatorDumper;
30
31 /**
32 * @var string
33 */
34 private $testTmpFilepath;
35
36 protected function setUp()
37 {
38 parent::setUp();
39
40 $this->routeCollection = new RouteCollection();
41 $this->generatorDumper = new PhpGeneratorDumper($this->routeCollection);
42 $this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.php';
43 @unlink($this->testTmpFilepath);
44 }
45
46 protected function tearDown()
47 {
48 parent::tearDown();
49
50 @unlink($this->testTmpFilepath);
51
52 $this->routeCollection = null;
53 $this->generatorDumper = null;
54 $this->testTmpFilepath = null;
55 }
56
57 public function testDumpWithRoutes()
58 {
59 $this->routeCollection->add('Test', new Route('/testing/{foo}'));
60 $this->routeCollection->add('Test2', new Route('/testing2'));
61
62 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump());
63 include ($this->testTmpFilepath);
64
65 $projectUrlGenerator = new \ProjectUrlGenerator(new RequestContext('/app.php'));
66
67 $absoluteUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), true);
68 $absoluteUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), true);
69 $relativeUrlWithParameter = $projectUrlGenerator->generate('Test', array('foo' => 'bar'), false);
70 $relativeUrlWithoutParameter = $projectUrlGenerator->generate('Test2', array(), false);
71
72 $this->assertEquals($absoluteUrlWithParameter, 'http://localhost/app.php/testing/bar');
73 $this->assertEquals($absoluteUrlWithoutParameter, 'http://localhost/app.php/testing2');
74 $this->assertEquals($relativeUrlWithParameter, '/app.php/testing/bar');
75 $this->assertEquals($relativeUrlWithoutParameter, '/app.php/testing2');
76 }
77
78 /**
79 * @expectedException \InvalidArgumentException
80 */
81 public function testDumpWithoutRoutes()
82 {
83 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'WithoutRoutesUrlGenerator')));
84 include ($this->testTmpFilepath);
85
86 $projectUrlGenerator = new \WithoutRoutesUrlGenerator(new RequestContext('/app.php'));
87
88 $projectUrlGenerator->generate('Test', array());
89 }
90
91 /**
92 * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
93 */
94 public function testGenerateNonExistingRoute()
95 {
96 $this->routeCollection->add('Test', new Route('/test'));
97
98 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'NonExistingRoutesUrlGenerator')));
99 include ($this->testTmpFilepath);
100
101 $projectUrlGenerator = new \NonExistingRoutesUrlGenerator(new RequestContext());
102 $url = $projectUrlGenerator->generate('NonExisting', array());
103 }
104
105 public function testDumpForRouteWithDefaults()
106 {
107 $this->routeCollection->add('Test', new Route('/testing/{foo}', array('foo' => 'bar')));
108
109 file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump(array('class' => 'DefaultRoutesUrlGenerator')));
110 include ($this->testTmpFilepath);
111
112 $projectUrlGenerator = new \DefaultRoutesUrlGenerator(new RequestContext());
113 $url = $projectUrlGenerator->generate('Test', array());
114
115 $this->assertEquals($url, '/testing');
116 }
117}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
new file mode 100644
index 00000000..5f8ef491
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
@@ -0,0 +1,635 @@
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
12namespace Symfony\Component\Routing\Tests\Generator;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\Generator\UrlGenerator;
17use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
18use Symfony\Component\Routing\RequestContext;
19
20class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
21{
22 public function testAbsoluteUrlWithPort80()
23 {
24 $routes = $this->getRoutes('test', new Route('/testing'));
25 $url = $this->getGenerator($routes)->generate('test', array(), true);
26
27 $this->assertEquals('http://localhost/app.php/testing', $url);
28 }
29
30 public function testAbsoluteSecureUrlWithPort443()
31 {
32 $routes = $this->getRoutes('test', new Route('/testing'));
33 $url = $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', array(), true);
34
35 $this->assertEquals('https://localhost/app.php/testing', $url);
36 }
37
38 public function testAbsoluteUrlWithNonStandardPort()
39 {
40 $routes = $this->getRoutes('test', new Route('/testing'));
41 $url = $this->getGenerator($routes, array('httpPort' => 8080))->generate('test', array(), true);
42
43 $this->assertEquals('http://localhost:8080/app.php/testing', $url);
44 }
45
46 public function testAbsoluteSecureUrlWithNonStandardPort()
47 {
48 $routes = $this->getRoutes('test', new Route('/testing'));
49 $url = $this->getGenerator($routes, array('httpsPort' => 8080, 'scheme' => 'https'))->generate('test', array(), true);
50
51 $this->assertEquals('https://localhost:8080/app.php/testing', $url);
52 }
53
54 public function testRelativeUrlWithoutParameters()
55 {
56 $routes = $this->getRoutes('test', new Route('/testing'));
57 $url = $this->getGenerator($routes)->generate('test', array(), false);
58
59 $this->assertEquals('/app.php/testing', $url);
60 }
61
62 public function testRelativeUrlWithParameter()
63 {
64 $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
65 $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), false);
66
67 $this->assertEquals('/app.php/testing/bar', $url);
68 }
69
70 public function testRelativeUrlWithNullParameter()
71 {
72 $routes = $this->getRoutes('test', new Route('/testing.{format}', array('format' => null)));
73 $url = $this->getGenerator($routes)->generate('test', array(), false);
74
75 $this->assertEquals('/app.php/testing', $url);
76 }
77
78 /**
79 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
80 */
81 public function testRelativeUrlWithNullParameterButNotOptional()
82 {
83 $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', array('foo' => null)));
84 // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params.
85 // Generating path "/testing//bar" would be wrong as matching this route would fail.
86 $this->getGenerator($routes)->generate('test', array(), false);
87 }
88
89 public function testRelativeUrlWithOptionalZeroParameter()
90 {
91 $routes = $this->getRoutes('test', new Route('/testing/{page}'));
92 $url = $this->getGenerator($routes)->generate('test', array('page' => 0), false);
93
94 $this->assertEquals('/app.php/testing/0', $url);
95 }
96
97 public function testNotPassedOptionalParameterInBetween()
98 {
99 $routes = $this->getRoutes('test', new Route('/{slug}/{page}', array('slug' => 'index', 'page' => 0)));
100 $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', array('page' => 1)));
101 $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test'));
102 }
103
104 public function testRelativeUrlWithExtraParameters()
105 {
106 $routes = $this->getRoutes('test', new Route('/testing'));
107 $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), false);
108
109 $this->assertEquals('/app.php/testing?foo=bar', $url);
110 }
111
112 public function testAbsoluteUrlWithExtraParameters()
113 {
114 $routes = $this->getRoutes('test', new Route('/testing'));
115 $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
116
117 $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url);
118 }
119
120 public function testUrlWithNullExtraParameters()
121 {
122 $routes = $this->getRoutes('test', new Route('/testing'));
123 $url = $this->getGenerator($routes)->generate('test', array('foo' => null), true);
124
125 $this->assertEquals('http://localhost/app.php/testing', $url);
126 }
127
128 public function testUrlWithExtraParametersFromGlobals()
129 {
130 $routes = $this->getRoutes('test', new Route('/testing'));
131 $generator = $this->getGenerator($routes);
132 $context = new RequestContext('/app.php');
133 $context->setParameter('bar', 'bar');
134 $generator->setContext($context);
135 $url = $generator->generate('test', array('foo' => 'bar'));
136
137 $this->assertEquals('/app.php/testing?foo=bar', $url);
138 }
139
140 public function testUrlWithGlobalParameter()
141 {
142 $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
143 $generator = $this->getGenerator($routes);
144 $context = new RequestContext('/app.php');
145 $context->setParameter('foo', 'bar');
146 $generator->setContext($context);
147 $url = $generator->generate('test', array());
148
149 $this->assertEquals('/app.php/testing/bar', $url);
150 }
151
152 public function testGlobalParameterHasHigherPriorityThanDefault()
153 {
154 $routes = $this->getRoutes('test', new Route('/{_locale}', array('_locale' => 'en')));
155 $generator = $this->getGenerator($routes);
156 $context = new RequestContext('/app.php');
157 $context->setParameter('_locale', 'de');
158 $generator->setContext($context);
159 $url = $generator->generate('test', array());
160
161 $this->assertSame('/app.php/de', $url);
162 }
163
164 /**
165 * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
166 */
167 public function testGenerateWithoutRoutes()
168 {
169 $routes = $this->getRoutes('foo', new Route('/testing/{foo}'));
170 $this->getGenerator($routes)->generate('test', array(), true);
171 }
172
173 /**
174 * @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
175 */
176 public function testGenerateForRouteWithoutMandatoryParameter()
177 {
178 $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
179 $this->getGenerator($routes)->generate('test', array(), true);
180 }
181
182 /**
183 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
184 */
185 public function testGenerateForRouteWithInvalidOptionalParameter()
186 {
187 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
188 $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
189 }
190
191 /**
192 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
193 */
194 public function testGenerateForRouteWithInvalidParameter()
195 {
196 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '1|2')));
197 $this->getGenerator($routes)->generate('test', array('foo' => '0'), true);
198 }
199
200 public function testGenerateForRouteWithInvalidOptionalParameterNonStrict()
201 {
202 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
203 $generator = $this->getGenerator($routes);
204 $generator->setStrictRequirements(false);
205 $this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
206 }
207
208 public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger()
209 {
210 if (!interface_exists('Psr\Log\LoggerInterface')) {
211 $this->markTestSkipped('The "psr/log" package is not available');
212 }
213
214 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
215 $logger = $this->getMock('Psr\Log\LoggerInterface');
216 $logger->expects($this->once())
217 ->method('error');
218 $generator = $this->getGenerator($routes, array(), $logger);
219 $generator->setStrictRequirements(false);
220 $this->assertNull($generator->generate('test', array('foo' => 'bar'), true));
221 }
222
223 public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck()
224 {
225 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
226 $generator = $this->getGenerator($routes);
227 $generator->setStrictRequirements(null);
228 $this->assertSame('/app.php/testing/bar', $generator->generate('test', array('foo' => 'bar')));
229 }
230
231 /**
232 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
233 */
234 public function testGenerateForRouteWithInvalidMandatoryParameter()
235 {
236 $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => 'd+')));
237 $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), true);
238 }
239
240 /**
241 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
242 */
243 public function testRequiredParamAndEmptyPassed()
244 {
245 $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+')));
246 $this->getGenerator($routes)->generate('test', array('slug' => ''));
247 }
248
249 public function testSchemeRequirementDoesNothingIfSameCurrentScheme()
250 {
251 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'http')));
252 $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test'));
253
254 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'https')));
255 $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
256 }
257
258 public function testSchemeRequirementForcesAbsoluteUrl()
259 {
260 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'https')));
261 $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
262
263 $routes = $this->getRoutes('test', new Route('/', array(), array('_scheme' => 'http')));
264 $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
265 }
266
267 public function testPathWithTwoStartingSlashes()
268 {
269 $routes = $this->getRoutes('test', new Route('//path-and-not-domain'));
270
271 // this must not generate '//path-and-not-domain' because that would be a network path
272 $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test'));
273 }
274
275 public function testNoTrailingSlashForMultipleOptionalParameters()
276 {
277 $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null)));
278
279 $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo')));
280 }
281
282 public function testWithAnIntegerAsADefaultValue()
283 {
284 $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0)));
285
286 $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
287 }
288
289 public function testNullForOptionalParameterIsIgnored()
290 {
291 $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0)));
292
293 $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null)));
294 }
295
296 public function testQueryParamSameAsDefault()
297 {
298 $routes = $this->getRoutes('test', new Route('/test', array('default' => 'value')));
299
300 $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
301 $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'value')));
302 $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
303 }
304
305 public function testGenerateWithSpecialRouteName()
306 {
307 $routes = $this->getRoutes('$péß^a|', new Route('/bar'));
308
309 $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|'));
310 }
311
312 public function testUrlEncoding()
313 {
314 // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986)
315 // and other special ASCII chars. These chars are tested as static text path, variable path and query param.
316 $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id';
317 $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+')));
318 $this->assertSame('/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
319 .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
320 .'?query=%40%3A%5B%5D%2F%28%29%2A%27%22+%2B%2C%3B-._%7E%26%24%3C%3E%7C%7B%7D%25%5C%5E%60%21%3Ffoo%3Dbar%23id',
321 $this->getGenerator($routes)->generate('test', array(
322 'varpath' => $chars,
323 'query' => $chars
324 ))
325 );
326 }
327
328 public function testEncodingOfRelativePathSegments()
329 {
330 $routes = $this->getRoutes('test', new Route('/dir/../dir/..'));
331 $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test'));
332 $routes = $this->getRoutes('test', new Route('/dir/./dir/.'));
333 $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test'));
334 $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...'));
335 $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test'));
336 }
337
338 public function testAdjacentVariables()
339 {
340 $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+')));
341 $generator = $this->getGenerator($routes);
342 $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123')));
343 $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml')));
344
345 // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything
346 // and following optional variables like _format could never match.
347 $this->setExpectedException('Symfony\Component\Routing\Exception\InvalidParameterException');
348 $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml'));
349 }
350
351 public function testOptionalVariableWithNoRealSeparator()
352 {
353 $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All')));
354 $generator = $this->getGenerator($routes);
355
356 $this->assertSame('/app.php/get', $generator->generate('test'));
357 $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites')));
358 }
359
360 public function testRequiredVariableWithNoRealSeparator()
361 {
362 $routes = $this->getRoutes('test', new Route('/get{what}Suffix'));
363 $generator = $this->getGenerator($routes);
364
365 $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites')));
366 }
367
368 public function testDefaultRequirementOfVariable()
369 {
370 $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
371 $generator = $this->getGenerator($routes);
372
373 $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
374 }
375
376 /**
377 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
378 */
379 public function testDefaultRequirementOfVariableDisallowsSlash()
380 {
381 $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
382 $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash'));
383 }
384
385 /**
386 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
387 */
388 public function testDefaultRequirementOfVariableDisallowsNextSeparator()
389 {
390 $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
391 $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
392 }
393
394 public function testWithHostDifferentFromContext()
395 {
396 $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
397
398 $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
399 }
400
401 public function testWithHostSameAsContext()
402 {
403 $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
404
405 $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
406 }
407
408 public function testWithHostSameAsContextAndAbsolute()
409 {
410 $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
411
412 $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' =>'Fabien', 'locale' => 'fr'), true));
413 }
414
415 /**
416 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
417 */
418 public function testUrlWithInvalidParameterInHost()
419 {
420 $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
421 $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
422 }
423
424 /**
425 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
426 */
427 public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue()
428 {
429 $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com'));
430 $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
431 }
432
433 /**
434 * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
435 */
436 public function testUrlWithInvalidParameterEqualsDefaultValueInHost()
437 {
438 $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com'));
439 $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), false);
440 }
441
442 public function testUrlWithInvalidParameterInHostInNonStrictMode()
443 {
444 $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
445 $generator = $this->getGenerator($routes);
446 $generator->setStrictRequirements(false);
447 $this->assertNull($generator->generate('test', array('foo' => 'baz'), false));
448 }
449
450 public function testGenerateNetworkPath()
451 {
452 $routes = $this->getRoutes('test', new Route('/{name}', array(), array('_scheme' => 'http'), array(), '{locale}.example.com'));
453
454 $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
455 array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
456 );
457 $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
458 array('name' =>'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
459 );
460 $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
461 array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
462 );
463 $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
464 array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
465 );
466 }
467
468 public function testGenerateRelativePath()
469 {
470 $routes = new RouteCollection();
471 $routes->add('article', new Route('/{author}/{article}/'));
472 $routes->add('comments', new Route('/{author}/{article}/comments'));
473 $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com'));
474 $routes->add('scheme', new Route('/{author}', array(), array('_scheme' => 'https')));
475 $routes->add('unrelated', new Route('/about'));
476
477 $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/'));
478
479 $this->assertSame('comments', $generator->generate('comments',
480 array('author' =>'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
481 );
482 $this->assertSame('comments?page=2', $generator->generate('comments',
483 array('author' =>'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH)
484 );
485 $this->assertSame('../twig-is-great/', $generator->generate('article',
486 array('author' =>'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
487 );
488 $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article',
489 array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
490 );
491 $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host',
492 array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
493 );
494 $this->assertSame('https://example.com/app.php/bernhard', $generator->generate('scheme',
495 array('author' =>'bernhard'), UrlGeneratorInterface::RELATIVE_PATH)
496 );
497 $this->assertSame('../../about', $generator->generate('unrelated',
498 array(), UrlGeneratorInterface::RELATIVE_PATH)
499 );
500 }
501
502 /**
503 * @dataProvider provideRelativePaths
504 */
505 public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
506 {
507 $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
508 }
509
510 public function provideRelativePaths()
511 {
512 return array(
513 array(
514 '/same/dir/',
515 '/same/dir/',
516 ''
517 ),
518 array(
519 '/same/file',
520 '/same/file',
521 ''
522 ),
523 array(
524 '/',
525 '/file',
526 'file'
527 ),
528 array(
529 '/',
530 '/dir/file',
531 'dir/file'
532 ),
533 array(
534 '/dir/file.html',
535 '/dir/different-file.html',
536 'different-file.html'
537 ),
538 array(
539 '/same/dir/extra-file',
540 '/same/dir/',
541 './'
542 ),
543 array(
544 '/parent/dir/',
545 '/parent/',
546 '../'
547 ),
548 array(
549 '/parent/dir/extra-file',
550 '/parent/',
551 '../'
552 ),
553 array(
554 '/a/b/',
555 '/x/y/z/',
556 '../../x/y/z/'
557 ),
558 array(
559 '/a/b/c/d/e',
560 '/a/c/d',
561 '../../../c/d'
562 ),
563 array(
564 '/a/b/c//',
565 '/a/b/c/',
566 '../'
567 ),
568 array(
569 '/a/b/c/',
570 '/a/b/c//',
571 './/'
572 ),
573 array(
574 '/root/a/b/c/',
575 '/root/x/b/c/',
576 '../../../x/b/c/'
577 ),
578 array(
579 '/a/b/c/d/',
580 '/a',
581 '../../../../a'
582 ),
583 array(
584 '/special-chars/sp%20ce/1€/mäh/e=mc²',
585 '/special-chars/sp%20ce/1€/<µ>/e=mc²',
586 '../<µ>/e=mc²'
587 ),
588 array(
589 'not-rooted',
590 'dir/file',
591 'dir/file'
592 ),
593 array(
594 '//dir/',
595 '',
596 '../../'
597 ),
598 array(
599 '/dir/',
600 '/dir/file:with-colon',
601 './file:with-colon'
602 ),
603 array(
604 '/dir/',
605 '/dir/subdir/file:with-colon',
606 'subdir/file:with-colon'
607 ),
608 array(
609 '/dir/',
610 '/dir/:subdir/',
611 './:subdir/'
612 ),
613 );
614 }
615
616 protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
617 {
618 $context = new RequestContext('/app.php');
619 foreach ($parameters as $key => $value) {
620 $method = 'set'.$key;
621 $context->$method($value);
622 }
623 $generator = new UrlGenerator($routes, $context, $logger);
624
625 return $generator;
626 }
627
628 protected function getRoutes($name, Route $route)
629 {
630 $routes = new RouteCollection();
631 $routes->add($name, $route);
632
633 return $routes;
634 }
635}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php
new file mode 100644
index 00000000..c927ae4a
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTest.php
@@ -0,0 +1,38 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14abstract class AbstractAnnotationLoaderTest extends \PHPUnit_Framework_TestCase
15{
16 protected function setUp()
17 {
18 if (!class_exists('Doctrine\\Common\\Version')) {
19 $this->markTestSkipped('Doctrine is not available.');
20 }
21 }
22
23 public function getReader()
24 {
25 return $this->getMockBuilder('Doctrine\Common\Annotations\Reader')
26 ->disableOriginalConstructor()
27 ->getMock()
28 ;
29 }
30
31 public function getClassLoader($reader)
32 {
33 return $this->getMockBuilder('Symfony\Component\Routing\Loader\AnnotationClassLoader')
34 ->setConstructorArgs(array($reader))
35 ->getMockForAbstractClass()
36 ;
37 }
38}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
new file mode 100644
index 00000000..31c43f58
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php
@@ -0,0 +1,119 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
15{
16 protected $loader;
17
18 protected function setUp()
19 {
20 parent::setUp();
21
22 $this->reader = $this->getReader();
23 $this->loader = $this->getClassLoader($this->reader);
24 }
25
26 /**
27 * @expectedException \InvalidArgumentException
28 */
29 public function testLoadMissingClass()
30 {
31 $this->loader->load('MissingClass');
32 }
33
34 /**
35 * @expectedException \InvalidArgumentException
36 */
37 public function testLoadAbstractClass()
38 {
39 $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\AbstractClass');
40 }
41
42 /**
43 * @dataProvider provideTestSupportsChecksResource
44 */
45 public function testSupportsChecksResource($resource, $expectedSupports)
46 {
47 $this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable');
48 }
49
50 public function provideTestSupportsChecksResource()
51 {
52 return array(
53 array('class', true),
54 array('\fully\qualified\class\name', true),
55 array('namespaced\class\without\leading\slash', true),
56 array('ÿClassWithLegalSpecialCharacters', true),
57 array('5', false),
58 array('foo.foo', false),
59 array(null, false),
60 );
61 }
62
63 public function testSupportsChecksTypeIfSpecified()
64 {
65 $this->assertTrue($this->loader->supports('class', 'annotation'), '->supports() checks the resource type if specified');
66 $this->assertFalse($this->loader->supports('class', 'foo'), '->supports() checks the resource type if specified');
67 }
68
69 public function getLoadTests()
70 {
71 return array(
72 array(
73 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
74 array('name'=>'route1'),
75 array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
76 ),
77 array(
78 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
79 array('name'=>'route1', 'defaults' => array('arg2' => 'foo')),
80 array('arg2' => 'defaultValue2', 'arg3' =>'defaultValue3')
81 ),
82 );
83 }
84
85 /**
86 * @dataProvider getLoadTests
87 */
88 public function testLoad($className, $routeDatas = array(), $methodArgs = array())
89 {
90 $routeDatas = array_replace(array(
91 'name' => 'route',
92 'path' => '/',
93 'requirements' => array(),
94 'options' => array(),
95 'defaults' => array(),
96 'schemes' => array(),
97 'methods' => array(),
98 ), $routeDatas);
99
100 $this->reader
101 ->expects($this->once())
102 ->method('getMethodAnnotations')
103 ->will($this->returnValue(array($this->getAnnotatedRoute($routeDatas))))
104 ;
105 $routeCollection = $this->loader->load($className);
106 $route = $routeCollection->get($routeDatas['name']);
107
108 $this->assertSame($routeDatas['path'], $route->getPath(), '->load preserves path annotation');
109 $this->assertSame($routeDatas['requirements'],$route->getRequirements(), '->load preserves requirements annotation');
110 $this->assertCount(0, array_intersect($route->getOptions(), $routeDatas['options']), '->load preserves options annotation');
111 $this->assertSame(array_replace($routeDatas['defaults'], $methodArgs), $route->getDefaults(), '->load preserves defaults annotation');
112 }
113
114 private function getAnnotatedRoute($datas)
115 {
116 return new \Symfony\Component\Routing\Annotation\Route($datas);
117 }
118
119}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php
new file mode 100644
index 00000000..29126ba4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php
@@ -0,0 +1,53 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
15use Symfony\Component\Config\FileLocator;
16
17class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTest
18{
19 protected $loader;
20 protected $reader;
21
22 protected function setUp()
23 {
24 parent::setUp();
25
26 $this->reader = $this->getReader();
27 $this->loader = new AnnotationDirectoryLoader(new FileLocator(), $this->getClassLoader($this->reader));
28 }
29
30 public function testLoad()
31 {
32 $this->reader->expects($this->exactly(2))->method('getClassAnnotation');
33
34 $this->reader
35 ->expects($this->any())
36 ->method('getMethodAnnotations')
37 ->will($this->returnValue(array()))
38 ;
39
40 $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses');
41 }
42
43 public function testSupports()
44 {
45 $fixturesDir = __DIR__.'/../Fixtures';
46
47 $this->assertTrue($this->loader->supports($fixturesDir), '->supports() returns true if the resource is loadable');
48 $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
49
50 $this->assertTrue($this->loader->supports($fixturesDir, 'annotation'), '->supports() checks the resource type if specified');
51 $this->assertFalse($this->loader->supports($fixturesDir, 'foo'), '->supports() checks the resource type if specified');
52 }
53}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php
new file mode 100644
index 00000000..f0a8a0e3
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php
@@ -0,0 +1,47 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Routing\Loader\AnnotationFileLoader;
15use Symfony\Component\Config\FileLocator;
16
17class AnnotationFileLoaderTest extends AbstractAnnotationLoaderTest
18{
19 protected $loader;
20 protected $reader;
21
22 protected function setUp()
23 {
24 parent::setUp();
25
26 $this->reader = $this->getReader();
27 $this->loader = new AnnotationFileLoader(new FileLocator(), $this->getClassLoader($this->reader));
28 }
29
30 public function testLoad()
31 {
32 $this->reader->expects($this->once())->method('getClassAnnotation');
33
34 $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php');
35 }
36
37 public function testSupports()
38 {
39 $fixture = __DIR__.'/../Fixtures/annotated.php';
40
41 $this->assertTrue($this->loader->supports($fixture), '->supports() returns true if the resource is loadable');
42 $this->assertFalse($this->loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
43
44 $this->assertTrue($this->loader->supports($fixture, 'annotation'), '->supports() checks the resource type if specified');
45 $this->assertFalse($this->loader->supports($fixture, 'foo'), '->supports() checks the resource type if specified');
46 }
47}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php
new file mode 100644
index 00000000..64d1b086
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/ClosureLoaderTest.php
@@ -0,0 +1,55 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Routing\Loader\ClosureLoader;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\RouteCollection;
17
18class ClosureLoaderTest extends \PHPUnit_Framework_TestCase
19{
20 protected function setUp()
21 {
22 if (!class_exists('Symfony\Component\Config\FileLocator')) {
23 $this->markTestSkipped('The "Config" component is not available');
24 }
25 }
26
27 public function testSupports()
28 {
29 $loader = new ClosureLoader();
30
31 $closure = function () {};
32
33 $this->assertTrue($loader->supports($closure), '->supports() returns true if the resource is loadable');
34 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
35
36 $this->assertTrue($loader->supports($closure, 'closure'), '->supports() checks the resource type if specified');
37 $this->assertFalse($loader->supports($closure, 'foo'), '->supports() checks the resource type if specified');
38 }
39
40 public function testLoad()
41 {
42 $loader = new ClosureLoader();
43
44 $route = new Route('/');
45 $routes = $loader->load(function () use ($route) {
46 $routes = new RouteCollection();
47
48 $routes->add('foo', $route);
49
50 return $routes;
51 });
52
53 $this->assertEquals($route, $routes->get('foo'), '->load() loads a \Closure resource');
54 }
55}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php
new file mode 100644
index 00000000..18b166fc
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php
@@ -0,0 +1,55 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Config\FileLocator;
15use Symfony\Component\Routing\Loader\PhpFileLoader;
16
17class PhpFileLoaderTest extends \PHPUnit_Framework_TestCase
18{
19 protected function setUp()
20 {
21 if (!class_exists('Symfony\Component\Config\FileLocator')) {
22 $this->markTestSkipped('The "Config" component is not available');
23 }
24 }
25
26 public function testSupports()
27 {
28 $loader = new PhpFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
29
30 $this->assertTrue($loader->supports('foo.php'), '->supports() returns true if the resource is loadable');
31 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
32
33 $this->assertTrue($loader->supports('foo.php', 'php'), '->supports() checks the resource type if specified');
34 $this->assertFalse($loader->supports('foo.php', 'foo'), '->supports() checks the resource type if specified');
35 }
36
37 public function testLoadWithRoute()
38 {
39 $loader = new PhpFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
40 $routeCollection = $loader->load('validpattern.php');
41 $routes = $routeCollection->all();
42
43 $this->assertCount(2, $routes, 'Two routes are loaded');
44 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
45
46 foreach ($routes as $route) {
47 $this->assertSame('/blog/{slug}', $route->getPath());
48 $this->assertSame('MyBlogBundle:Blog:show', $route->getDefault('_controller'));
49 $this->assertSame('{locale}.example.com', $route->getHost());
50 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
51 $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
52 $this->assertEquals(array('https'), $route->getSchemes());
53 }
54 }
55}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
new file mode 100644
index 00000000..9f038c16
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
@@ -0,0 +1,127 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Config\FileLocator;
15use Symfony\Component\Routing\Loader\XmlFileLoader;
16use Symfony\Component\Routing\Tests\Fixtures\CustomXmlFileLoader;
17
18class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
19{
20 protected function setUp()
21 {
22 if (!class_exists('Symfony\Component\Config\FileLocator')) {
23 $this->markTestSkipped('The "Config" component is not available');
24 }
25 }
26
27 public function testSupports()
28 {
29 $loader = new XmlFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
30
31 $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable');
32 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
33
34 $this->assertTrue($loader->supports('foo.xml', 'xml'), '->supports() checks the resource type if specified');
35 $this->assertFalse($loader->supports('foo.xml', 'foo'), '->supports() checks the resource type if specified');
36 }
37
38 public function testLoadWithRoute()
39 {
40 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
41 $routeCollection = $loader->load('validpattern.xml');
42 $routes = $routeCollection->all();
43
44 $this->assertCount(2, $routes, 'Two routes are loaded');
45 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
46
47 foreach ($routes as $route) {
48 $this->assertSame('/blog/{slug}', $route->getPath());
49 $this->assertSame('{locale}.example.com', $route->getHost());
50 $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
51 $this->assertSame('\w+', $route->getRequirement('locale'));
52 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
53 $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
54 $this->assertEquals(array('https'), $route->getSchemes());
55 }
56 }
57
58 public function testLoadWithNamespacePrefix()
59 {
60 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
61 $routeCollection = $loader->load('namespaceprefix.xml');
62
63 $this->assertCount(1, $routeCollection->all(), 'One route is loaded');
64
65 $route = $routeCollection->get('blog_show');
66 $this->assertSame('/blog/{slug}', $route->getPath());
67 $this->assertSame('{_locale}.example.com', $route->getHost());
68 $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
69 $this->assertSame('\w+', $route->getRequirement('slug'));
70 $this->assertSame('en|fr|de', $route->getRequirement('_locale'));
71 $this->assertSame(null, $route->getDefault('slug'));
72 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
73 }
74
75 public function testLoadWithImport()
76 {
77 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
78 $routeCollection = $loader->load('validresource.xml');
79 $routes = $routeCollection->all();
80
81 $this->assertCount(2, $routes, 'Two routes are loaded');
82 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
83
84 foreach ($routes as $route) {
85 $this->assertSame('/{foo}/blog/{slug}', $route->getPath());
86 $this->assertSame('123', $route->getDefault('foo'));
87 $this->assertSame('\d+', $route->getRequirement('foo'));
88 $this->assertSame('bar', $route->getOption('foo'));
89 $this->assertSame('', $route->getHost());
90 }
91 }
92
93 /**
94 * @expectedException \InvalidArgumentException
95 * @dataProvider getPathsToInvalidFiles
96 */
97 public function testLoadThrowsExceptionWithInvalidFile($filePath)
98 {
99 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
100 $loader->load($filePath);
101 }
102
103 /**
104 * @expectedException \InvalidArgumentException
105 * @dataProvider getPathsToInvalidFiles
106 */
107 public function testLoadThrowsExceptionWithInvalidFileEvenWithoutSchemaValidation($filePath)
108 {
109 $loader = new CustomXmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
110 $loader->load($filePath);
111 }
112
113 public function getPathsToInvalidFiles()
114 {
115 return array(array('nonvalidnode.xml'), array('nonvalidroute.xml'), array('nonvalid.xml'), array('missing_id.xml'), array('missing_path.xml'));
116 }
117
118 /**
119 * @expectedException \InvalidArgumentException
120 * @expectedExceptionMessage Document types are not allowed.
121 */
122 public function testDocTypeIsNotAllowed()
123 {
124 $loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
125 $loader->load('withdoctype.xml');
126 }
127}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
new file mode 100644
index 00000000..a3e934ce
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
@@ -0,0 +1,113 @@
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
12namespace Symfony\Component\Routing\Tests\Loader;
13
14use Symfony\Component\Config\FileLocator;
15use Symfony\Component\Routing\Loader\YamlFileLoader;
16use Symfony\Component\Config\Resource\FileResource;
17
18class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
19{
20 protected function setUp()
21 {
22 if (!class_exists('Symfony\Component\Config\FileLocator')) {
23 $this->markTestSkipped('The "Config" component is not available');
24 }
25
26 if (!class_exists('Symfony\Component\Yaml\Yaml')) {
27 $this->markTestSkipped('The "Yaml" component is not available');
28 }
29 }
30
31 public function testSupports()
32 {
33 $loader = new YamlFileLoader($this->getMock('Symfony\Component\Config\FileLocator'));
34
35 $this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable');
36 $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable');
37
38 $this->assertTrue($loader->supports('foo.yml', 'yaml'), '->supports() checks the resource type if specified');
39 $this->assertFalse($loader->supports('foo.yml', 'foo'), '->supports() checks the resource type if specified');
40 }
41
42 public function testLoadDoesNothingIfEmpty()
43 {
44 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
45 $collection = $loader->load('empty.yml');
46
47 $this->assertEquals(array(), $collection->all());
48 $this->assertEquals(array(new FileResource(realpath(__DIR__.'/../Fixtures/empty.yml'))), $collection->getResources());
49 }
50
51 /**
52 * @expectedException \InvalidArgumentException
53 * @dataProvider getPathsToInvalidFiles
54 */
55 public function testLoadThrowsExceptionWithInvalidFile($filePath)
56 {
57 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
58 $loader->load($filePath);
59 }
60
61 public function getPathsToInvalidFiles()
62 {
63 return array(array('nonvalid.yml'), array('nonvalid2.yml'), array('incomplete.yml'), array('nonvalidkeys.yml'), array('nonesense_resource_plus_path.yml'), array('nonesense_type_without_resource.yml'));
64 }
65
66 public function testLoadSpecialRouteName()
67 {
68 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
69 $routeCollection = $loader->load('special_route_name.yml');
70 $route = $routeCollection->get('#$péß^a|');
71
72 $this->assertInstanceOf('Symfony\Component\Routing\Route', $route);
73 $this->assertSame('/true', $route->getPath());
74 }
75
76 public function testLoadWithRoute()
77 {
78 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
79 $routeCollection = $loader->load('validpattern.yml');
80 $routes = $routeCollection->all();
81
82 $this->assertCount(2, $routes, 'Two routes are loaded');
83 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
84
85 foreach ($routes as $route) {
86 $this->assertSame('/blog/{slug}', $route->getPath());
87 $this->assertSame('{locale}.example.com', $route->getHost());
88 $this->assertSame('MyBundle:Blog:show', $route->getDefault('_controller'));
89 $this->assertSame('\w+', $route->getRequirement('locale'));
90 $this->assertSame('RouteCompiler', $route->getOption('compiler_class'));
91 $this->assertEquals(array('GET', 'POST', 'PUT', 'OPTIONS'), $route->getMethods());
92 $this->assertEquals(array('https'), $route->getSchemes());
93 }
94 }
95
96 public function testLoadWithResource()
97 {
98 $loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
99 $routeCollection = $loader->load('validresource.yml');
100 $routes = $routeCollection->all();
101
102 $this->assertCount(2, $routes, 'Two routes are loaded');
103 $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes);
104
105 foreach ($routes as $route) {
106 $this->assertSame('/{foo}/blog/{slug}', $route->getPath());
107 $this->assertSame('123', $route->getDefault('foo'));
108 $this->assertSame('\d+', $route->getRequirement('foo'));
109 $this->assertSame('bar', $route->getOption('foo'));
110 $this->assertSame('', $route->getHost());
111 }
112 }
113}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php
new file mode 100644
index 00000000..6550911e
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/ApacheUrlMatcherTest.php
@@ -0,0 +1,137 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\RequestContext;
16use Symfony\Component\Routing\Matcher\ApacheUrlMatcher;
17
18class ApacheUrlMatcherTest extends \PHPUnit_Framework_TestCase
19{
20 protected $server;
21
22 protected function setUp()
23 {
24 $this->server = $_SERVER;
25 }
26
27 protected function tearDown()
28 {
29 $_SERVER = $this->server;
30 }
31
32 /**
33 * @dataProvider getMatchData
34 */
35 public function testMatch($name, $pathinfo, $server, $expect)
36 {
37 $collection = new RouteCollection();
38 $context = new RequestContext();
39 $matcher = new ApacheUrlMatcher($collection, $context);
40
41 $_SERVER = $server;
42
43 $result = $matcher->match($pathinfo, $server);
44 $this->assertSame(var_export($expect, true), var_export($result, true));
45 }
46
47 public function getMatchData()
48 {
49 return array(
50 array(
51 'Simple route',
52 '/hello/world',
53 array(
54 '_ROUTING_route' => 'hello',
55 '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
56 '_ROUTING_param_name' => 'world',
57 ),
58 array(
59 '_controller' => 'AcmeBundle:Default:index',
60 'name' => 'world',
61 '_route' => 'hello',
62 ),
63 ),
64 array(
65 'Route with params and defaults',
66 '/hello/hugo',
67 array(
68 '_ROUTING_route' => 'hello',
69 '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
70 '_ROUTING_param_name' => 'hugo',
71 '_ROUTING_default_name' => 'world',
72 ),
73 array(
74 'name' => 'hugo',
75 '_controller' => 'AcmeBundle:Default:index',
76 '_route' => 'hello',
77 ),
78 ),
79 array(
80 'Route with defaults only',
81 '/hello',
82 array(
83 '_ROUTING_route' => 'hello',
84 '_ROUTING_param__controller' => 'AcmeBundle:Default:index',
85 '_ROUTING_default_name' => 'world',
86 ),
87 array(
88 'name' => 'world',
89 '_controller' => 'AcmeBundle:Default:index',
90 '_route' => 'hello',
91 ),
92 ),
93 array(
94 'REDIRECT_ envs',
95 '/hello/world',
96 array(
97 'REDIRECT__ROUTING_route' => 'hello',
98 'REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
99 'REDIRECT__ROUTING_param_name' => 'world',
100 ),
101 array(
102 '_controller' => 'AcmeBundle:Default:index',
103 'name' => 'world',
104 '_route' => 'hello',
105 ),
106 ),
107 array(
108 'REDIRECT_REDIRECT_ envs',
109 '/hello/world',
110 array(
111 'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
112 'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
113 'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
114 ),
115 array(
116 '_controller' => 'AcmeBundle:Default:index',
117 'name' => 'world',
118 '_route' => 'hello',
119 ),
120 ),
121 array(
122 'REDIRECT_REDIRECT_ envs',
123 '/hello/world',
124 array(
125 'REDIRECT_REDIRECT__ROUTING_route' => 'hello',
126 'REDIRECT_REDIRECT__ROUTING_param__controller' => 'AcmeBundle:Default:index',
127 'REDIRECT_REDIRECT__ROUTING_param_name' => 'world',
128 ),
129 array(
130 '_controller' => 'AcmeBundle:Default:index',
131 'name' => 'world',
132 '_route' => 'hello',
133 ),
134 ),
135 );
136 }
137}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php
new file mode 100644
index 00000000..72bee710
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/ApacheMatcherDumperTest.php
@@ -0,0 +1,196 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16use Symfony\Component\Routing\Matcher\Dumper\ApacheMatcherDumper;
17
18class ApacheMatcherDumperTest extends \PHPUnit_Framework_TestCase
19{
20 protected static $fixturesPath;
21
22 public static function setUpBeforeClass()
23 {
24 self::$fixturesPath = realpath(__DIR__.'/../../Fixtures/');
25 }
26
27 public function testDump()
28 {
29 $dumper = new ApacheMatcherDumper($this->getRouteCollection());
30
31 $this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher1.apache', $dumper->dump(), '->dump() dumps basic routes to the correct apache format.');
32 }
33
34 /**
35 * @dataProvider provideEscapeFixtures
36 */
37 public function testEscapePattern($src, $dest, $char, $with, $message)
38 {
39 $r = new \ReflectionMethod(new ApacheMatcherDumper($this->getRouteCollection()), 'escape');
40 $r->setAccessible(true);
41 $this->assertEquals($dest, $r->invoke(null, $src, $char, $with), $message);
42 }
43
44 public function provideEscapeFixtures()
45 {
46 return array(
47 array('foo', 'foo', ' ', '-', 'Preserve string that should not be escaped'),
48 array('fo-o', 'fo-o', ' ', '-', 'Preserve string that should not be escaped'),
49 array('fo o', 'fo- o', ' ', '-', 'Escape special characters'),
50 array('fo-- o', 'fo--- o', ' ', '-', 'Escape special characters'),
51 array('fo- o', 'fo- o', ' ', '-', 'Do not escape already escaped string'),
52 );
53 }
54
55 public function testEscapeScriptName()
56 {
57 $collection = new RouteCollection();
58 $collection->add('foo', new Route('/foo'));
59 $dumper = new ApacheMatcherDumper($collection);
60 $this->assertStringEqualsFile(self::$fixturesPath.'/dumper/url_matcher2.apache', $dumper->dump(array('script_name' => 'ap p_d\ ev.php')));
61 }
62
63 private function getRouteCollection()
64 {
65 $collection = new RouteCollection();
66
67 // defaults and requirements
68 $collection->add('foo', new Route(
69 '/foo/{bar}',
70 array('def' => 'test'),
71 array('bar' => 'baz|symfony')
72 ));
73 // defaults parameters in pattern
74 $collection->add('foobar', new Route(
75 '/foo/{bar}',
76 array('bar' => 'toto')
77 ));
78 // method requirement
79 $collection->add('bar', new Route(
80 '/bar/{foo}',
81 array(),
82 array('_method' => 'GET|head')
83 ));
84 // method requirement (again)
85 $collection->add('baragain', new Route(
86 '/baragain/{foo}',
87 array(),
88 array('_method' => 'get|post')
89 ));
90 // simple
91 $collection->add('baz', new Route(
92 '/test/baz'
93 ));
94 // simple with extension
95 $collection->add('baz2', new Route(
96 '/test/baz.html'
97 ));
98 // trailing slash
99 $collection->add('baz3', new Route(
100 '/test/baz3/'
101 ));
102 // trailing slash with variable
103 $collection->add('baz4', new Route(
104 '/test/{foo}/'
105 ));
106 // trailing slash and safe method
107 $collection->add('baz5', new Route(
108 '/test/{foo}/',
109 array(),
110 array('_method' => 'get')
111 ));
112 // trailing slash and unsafe method
113 $collection->add('baz5unsafe', new Route(
114 '/testunsafe/{foo}/',
115 array(),
116 array('_method' => 'post')
117 ));
118 // complex
119 $collection->add('baz6', new Route(
120 '/test/baz',
121 array('foo' => 'bar baz')
122 ));
123 // space in path
124 $collection->add('baz7', new Route(
125 '/te st/baz'
126 ));
127 // space preceded with \ in path
128 $collection->add('baz8', new Route(
129 '/te\\ st/baz'
130 ));
131 // space preceded with \ in requirement
132 $collection->add('baz9', new Route(
133 '/test/{baz}',
134 array(),
135 array(
136 'baz' => 'te\\\\ st',
137 )
138 ));
139
140 $collection1 = new RouteCollection();
141
142 $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
143 $collection1->add('route1', $route1);
144
145 $collection2 = new RouteCollection();
146
147 $route2 = new Route('/route2', array(), array(), array(), 'a.example.com');
148 $collection2->add('route2', $route2);
149
150 $route3 = new Route('/route3', array(), array(), array(), 'b.example.com');
151 $collection2->add('route3', $route3);
152
153 $collection2->addPrefix('/c2');
154 $collection1->addCollection($collection2);
155
156 $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
157 $collection1->add('route4', $route4);
158
159 $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
160 $collection1->add('route5', $route5);
161
162 $route6 = new Route('/route6', array(), array(), array(), null);
163 $collection1->add('route6', $route6);
164
165 $collection->addCollection($collection1);
166
167 // host and variables
168
169 $collection1 = new RouteCollection();
170
171 $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
172 $collection1->add('route11', $route11);
173
174 $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
175 $collection1->add('route12', $route12);
176
177 $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
178 $collection1->add('route13', $route13);
179
180 $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
181 $collection1->add('route14', $route14);
182
183 $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
184 $collection1->add('route15', $route15);
185
186 $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
187 $collection1->add('route16', $route16);
188
189 $route17 = new Route('/route17', array(), array(), array(), null);
190 $collection1->add('route17', $route17);
191
192 $collection->addCollection($collection1);
193
194 return $collection;
195 }
196}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php
new file mode 100644
index 00000000..54b37727
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperCollectionTest.php
@@ -0,0 +1,33 @@
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
12namespace Symfony\Component\Routing\Test\Matcher\Dumper;
13
14use Symfony\Component\Routing\Matcher\Dumper\DumperCollection;
15
16class DumperCollectionTest extends \PHPUnit_Framework_TestCase
17{
18 public function testGetRoot()
19 {
20 $a = new DumperCollection();
21
22 $b = new DumperCollection();
23 $a->add($b);
24
25 $c = new DumperCollection();
26 $b->add($c);
27
28 $d = new DumperCollection();
29 $c->add($d);
30
31 $this->assertSame($a, $c->getRoot());
32 }
33}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php
new file mode 100644
index 00000000..7b4565c4
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/DumperPrefixCollectionTest.php
@@ -0,0 +1,123 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\Matcher\Dumper\DumperPrefixCollection;
16use Symfony\Component\Routing\Matcher\Dumper\DumperRoute;
17use Symfony\Component\Routing\Matcher\Dumper\DumperCollection;
18
19class DumperPrefixCollectionTest extends \PHPUnit_Framework_TestCase
20{
21 public function testAddPrefixRoute()
22 {
23 $coll = new DumperPrefixCollection;
24 $coll->setPrefix('');
25
26 $route = new DumperRoute('bar', new Route('/foo/bar'));
27 $coll = $coll->addPrefixRoute($route);
28
29 $route = new DumperRoute('bar2', new Route('/foo/bar'));
30 $coll = $coll->addPrefixRoute($route);
31
32 $route = new DumperRoute('qux', new Route('/foo/qux'));
33 $coll = $coll->addPrefixRoute($route);
34
35 $route = new DumperRoute('bar3', new Route('/foo/bar'));
36 $coll = $coll->addPrefixRoute($route);
37
38 $route = new DumperRoute('bar4', new Route(''));
39 $result = $coll->addPrefixRoute($route);
40
41 $expect = <<<'EOF'
42 |-coll /
43 | |-coll /f
44 | | |-coll /fo
45 | | | |-coll /foo
46 | | | | |-coll /foo/
47 | | | | | |-coll /foo/b
48 | | | | | | |-coll /foo/ba
49 | | | | | | | |-coll /foo/bar
50 | | | | | | | | |-route bar /foo/bar
51 | | | | | | | | |-route bar2 /foo/bar
52 | | | | | |-coll /foo/q
53 | | | | | | |-coll /foo/qu
54 | | | | | | | |-coll /foo/qux
55 | | | | | | | | |-route qux /foo/qux
56 | | | | | |-coll /foo/b
57 | | | | | | |-coll /foo/ba
58 | | | | | | | |-coll /foo/bar
59 | | | | | | | | |-route bar3 /foo/bar
60 | |-route bar4 /
61
62EOF;
63
64 $this->assertSame($expect, $this->collectionToString($result->getRoot(), ' '));
65 }
66
67 public function testMergeSlashNodes()
68 {
69 $coll = new DumperPrefixCollection;
70 $coll->setPrefix('');
71
72 $route = new DumperRoute('bar', new Route('/foo/bar'));
73 $coll = $coll->addPrefixRoute($route);
74
75 $route = new DumperRoute('bar2', new Route('/foo/bar'));
76 $coll = $coll->addPrefixRoute($route);
77
78 $route = new DumperRoute('qux', new Route('/foo/qux'));
79 $coll = $coll->addPrefixRoute($route);
80
81 $route = new DumperRoute('bar3', new Route('/foo/bar'));
82 $result = $coll->addPrefixRoute($route);
83
84 $result->getRoot()->mergeSlashNodes();
85
86 $expect = <<<'EOF'
87 |-coll /f
88 | |-coll /fo
89 | | |-coll /foo
90 | | | |-coll /foo/b
91 | | | | |-coll /foo/ba
92 | | | | | |-coll /foo/bar
93 | | | | | | |-route bar /foo/bar
94 | | | | | | |-route bar2 /foo/bar
95 | | | |-coll /foo/q
96 | | | | |-coll /foo/qu
97 | | | | | |-coll /foo/qux
98 | | | | | | |-route qux /foo/qux
99 | | | |-coll /foo/b
100 | | | | |-coll /foo/ba
101 | | | | | |-coll /foo/bar
102 | | | | | | |-route bar3 /foo/bar
103
104EOF;
105
106 $this->assertSame($expect, $this->collectionToString($result->getRoot(), ' '));
107 }
108
109 private function collectionToString(DumperCollection $collection, $prefix)
110 {
111 $string = '';
112 foreach ($collection as $route) {
113 if ($route instanceof DumperCollection) {
114 $string .= sprintf("%s|-coll %s\n", $prefix, $route->getPrefix());
115 $string .= $this->collectionToString($route, $prefix.'| ');
116 } else {
117 $string .= sprintf("%s|-route %s %s\n", $prefix, $route->getName(), $route->getRoute()->getPath());
118 }
119 }
120
121 return $string;
122 }
123}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
new file mode 100644
index 00000000..542ede85
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
@@ -0,0 +1,261 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher\Dumper;
13
14use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Routing\RouteCollection;
17
18class PhpMatcherDumperTest extends \PHPUnit_Framework_TestCase
19{
20 /**
21 * @expectedException \LogicException
22 */
23 public function testDumpWhenSchemeIsUsedWithoutAProperDumper()
24 {
25 $collection = new RouteCollection();
26 $collection->add('secure', new Route(
27 '/secure',
28 array(),
29 array('_scheme' => 'https')
30 ));
31 $dumper = new PhpMatcherDumper($collection);
32 $dumper->dump();
33 }
34
35 /**
36 * @dataProvider getRouteCollections
37 */
38 public function testDump(RouteCollection $collection, $fixture, $options = array())
39 {
40 $basePath = __DIR__.'/../../Fixtures/dumper/';
41
42 $dumper = new PhpMatcherDumper($collection);
43 $this->assertStringEqualsFile($basePath.$fixture, $dumper->dump($options), '->dump() correctly dumps routes as optimized PHP code.');
44 }
45
46 public function getRouteCollections()
47 {
48 /* test case 1 */
49
50 $collection = new RouteCollection();
51
52 $collection->add('overridden', new Route('/overridden'));
53
54 // defaults and requirements
55 $collection->add('foo', new Route(
56 '/foo/{bar}',
57 array('def' => 'test'),
58 array('bar' => 'baz|symfony')
59 ));
60 // method requirement
61 $collection->add('bar', new Route(
62 '/bar/{foo}',
63 array(),
64 array('_method' => 'GET|head')
65 ));
66 // GET method requirement automatically adds HEAD as valid
67 $collection->add('barhead', new Route(
68 '/barhead/{foo}',
69 array(),
70 array('_method' => 'GET')
71 ));
72 // simple
73 $collection->add('baz', new Route(
74 '/test/baz'
75 ));
76 // simple with extension
77 $collection->add('baz2', new Route(
78 '/test/baz.html'
79 ));
80 // trailing slash
81 $collection->add('baz3', new Route(
82 '/test/baz3/'
83 ));
84 // trailing slash with variable
85 $collection->add('baz4', new Route(
86 '/test/{foo}/'
87 ));
88 // trailing slash and method
89 $collection->add('baz5', new Route(
90 '/test/{foo}/',
91 array(),
92 array('_method' => 'post')
93 ));
94 // complex name
95 $collection->add('baz.baz6', new Route(
96 '/test/{foo}/',
97 array(),
98 array('_method' => 'put')
99 ));
100 // defaults without variable
101 $collection->add('foofoo', new Route(
102 '/foofoo',
103 array('def' => 'test')
104 ));
105 // pattern with quotes
106 $collection->add('quoter', new Route(
107 '/{quoter}',
108 array(),
109 array('quoter' => '[\']+')
110 ));
111 // space in pattern
112 $collection->add('space', new Route(
113 '/spa ce'
114 ));
115
116 // prefixes
117 $collection1 = new RouteCollection();
118 $collection1->add('overridden', new Route('/overridden1'));
119 $collection1->add('foo1', new Route('/{foo}'));
120 $collection1->add('bar1', new Route('/{bar}'));
121 $collection1->addPrefix('/b\'b');
122 $collection2 = new RouteCollection();
123 $collection2->addCollection($collection1);
124 $collection2->add('overridden', new Route('/{var}', array(), array('var' => '.*')));
125 $collection1 = new RouteCollection();
126 $collection1->add('foo2', new Route('/{foo1}'));
127 $collection1->add('bar2', new Route('/{bar1}'));
128 $collection1->addPrefix('/b\'b');
129 $collection2->addCollection($collection1);
130 $collection2->addPrefix('/a');
131 $collection->addCollection($collection2);
132
133 // overridden through addCollection() and multiple sub-collections with no own prefix
134 $collection1 = new RouteCollection();
135 $collection1->add('overridden2', new Route('/old'));
136 $collection1->add('helloWorld', new Route('/hello/{who}', array('who' => 'World!')));
137 $collection2 = new RouteCollection();
138 $collection3 = new RouteCollection();
139 $collection3->add('overridden2', new Route('/new'));
140 $collection3->add('hey', new Route('/hey/'));
141 $collection2->addCollection($collection3);
142 $collection1->addCollection($collection2);
143 $collection1->addPrefix('/multi');
144 $collection->addCollection($collection1);
145
146 // "dynamic" prefix
147 $collection1 = new RouteCollection();
148 $collection1->add('foo3', new Route('/{foo}'));
149 $collection1->add('bar3', new Route('/{bar}'));
150 $collection1->addPrefix('/b');
151 $collection1->addPrefix('{_locale}');
152 $collection->addCollection($collection1);
153
154 // route between collections
155 $collection->add('ababa', new Route('/ababa'));
156
157 // collection with static prefix but only one route
158 $collection1 = new RouteCollection();
159 $collection1->add('foo4', new Route('/{foo}'));
160 $collection1->addPrefix('/aba');
161 $collection->addCollection($collection1);
162
163 // prefix and host
164
165 $collection1 = new RouteCollection();
166
167 $route1 = new Route('/route1', array(), array(), array(), 'a.example.com');
168 $collection1->add('route1', $route1);
169
170 $collection2 = new RouteCollection();
171
172 $route2 = new Route('/c2/route2', array(), array(), array(), 'a.example.com');
173 $collection1->add('route2', $route2);
174
175 $route3 = new Route('/c2/route3', array(), array(), array(), 'b.example.com');
176 $collection1->add('route3', $route3);
177
178 $route4 = new Route('/route4', array(), array(), array(), 'a.example.com');
179 $collection1->add('route4', $route4);
180
181 $route5 = new Route('/route5', array(), array(), array(), 'c.example.com');
182 $collection1->add('route5', $route5);
183
184 $route6 = new Route('/route6', array(), array(), array(), null);
185 $collection1->add('route6', $route6);
186
187 $collection->addCollection($collection1);
188
189 // host and variables
190
191 $collection1 = new RouteCollection();
192
193 $route11 = new Route('/route11', array(), array(), array(), '{var1}.example.com');
194 $collection1->add('route11', $route11);
195
196 $route12 = new Route('/route12', array('var1' => 'val'), array(), array(), '{var1}.example.com');
197 $collection1->add('route12', $route12);
198
199 $route13 = new Route('/route13/{name}', array(), array(), array(), '{var1}.example.com');
200 $collection1->add('route13', $route13);
201
202 $route14 = new Route('/route14/{name}', array('var1' => 'val'), array(), array(), '{var1}.example.com');
203 $collection1->add('route14', $route14);
204
205 $route15 = new Route('/route15/{name}', array(), array(), array(), 'c.example.com');
206 $collection1->add('route15', $route15);
207
208 $route16 = new Route('/route16/{name}', array('var1' => 'val'), array(), array(), null);
209 $collection1->add('route16', $route16);
210
211 $route17 = new Route('/route17', array(), array(), array(), null);
212 $collection1->add('route17', $route17);
213
214 $collection->addCollection($collection1);
215
216 // multiple sub-collections with a single route and a prefix each
217 $collection1 = new RouteCollection();
218 $collection1->add('a', new Route('/a...'));
219 $collection2 = new RouteCollection();
220 $collection2->add('b', new Route('/{var}'));
221 $collection3 = new RouteCollection();
222 $collection3->add('c', new Route('/{var}'));
223 $collection3->addPrefix('/c');
224 $collection2->addCollection($collection3);
225 $collection2->addPrefix('/b');
226 $collection1->addCollection($collection2);
227 $collection1->addPrefix('/a');
228 $collection->addCollection($collection1);
229
230 /* test case 2 */
231
232 $redirectCollection = clone $collection;
233
234 // force HTTPS redirection
235 $redirectCollection->add('secure', new Route(
236 '/secure',
237 array(),
238 array('_scheme' => 'https')
239 ));
240
241 // force HTTP redirection
242 $redirectCollection->add('nonsecure', new Route(
243 '/nonsecure',
244 array(),
245 array('_scheme' => 'http')
246 ));
247
248 /* test case 3 */
249
250 $rootprefixCollection = new RouteCollection();
251 $rootprefixCollection->add('static', new Route('/test'));
252 $rootprefixCollection->add('dynamic', new Route('/{var}'));
253 $rootprefixCollection->addPrefix('rootprefix');
254
255 return array(
256 array($collection, 'url_matcher1.php', array()),
257 array($redirectCollection, 'url_matcher2.php', array('base_class' => 'Symfony\Component\Routing\Tests\Fixtures\RedirectableUrlMatcher')),
258 array($rootprefixCollection, 'url_matcher3.php', array())
259 );
260 }
261}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
new file mode 100644
index 00000000..2ad4fc87
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php
@@ -0,0 +1,58 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16use Symfony\Component\Routing\RequestContext;
17
18class RedirectableUrlMatcherTest extends \PHPUnit_Framework_TestCase
19{
20 public function testRedirectWhenNoSlash()
21 {
22 $coll = new RouteCollection();
23 $coll->add('foo', new Route('/foo/'));
24
25 $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
26 $matcher->expects($this->once())->method('redirect');
27 $matcher->match('/foo');
28 }
29
30 /**
31 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
32 */
33 public function testRedirectWhenNoSlashForNonSafeMethod()
34 {
35 $coll = new RouteCollection();
36 $coll->add('foo', new Route('/foo/'));
37
38 $context = new RequestContext();
39 $context->setMethod('POST');
40 $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, $context));
41 $matcher->match('/foo');
42 }
43
44 public function testSchemeRedirect()
45 {
46 $coll = new RouteCollection();
47 $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https')));
48
49 $matcher = $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($coll, new RequestContext()));
50 $matcher
51 ->expects($this->once())
52 ->method('redirect')
53 ->with('/foo', 'foo', 'https')
54 ->will($this->returnValue(array('_route' => 'foo')))
55 ;
56 $matcher->match('/foo');
57 }
58}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
new file mode 100644
index 00000000..86d8d954
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php
@@ -0,0 +1,66 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\Route;
15use Symfony\Component\Routing\RouteCollection;
16use Symfony\Component\Routing\RequestContext;
17use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
18
19class TraceableUrlMatcherTest extends \PHPUnit_Framework_TestCase
20{
21 public function test()
22 {
23 $coll = new RouteCollection();
24 $coll->add('foo', new Route('/foo', array(), array('_method' => 'POST')));
25 $coll->add('bar', new Route('/bar/{id}', array(), array('id' => '\d+')));
26 $coll->add('bar1', new Route('/bar/{name}', array(), array('id' => '\w+', '_method' => 'POST')));
27 $coll->add('bar2', new Route('/foo', array(), array(), array(), 'baz'));
28 $coll->add('bar3', new Route('/foo1', array(), array(), array(), 'baz'));
29
30 $context = new RequestContext();
31 $context->setHost('baz');
32
33 $matcher = new TraceableUrlMatcher($coll, $context);
34 $traces = $matcher->getTraces('/babar');
35 $this->assertEquals(array(0, 0, 0, 0, 0), $this->getLevels($traces));
36
37 $traces = $matcher->getTraces('/foo');
38 $this->assertEquals(array(1, 0, 0, 2), $this->getLevels($traces));
39
40 $traces = $matcher->getTraces('/bar/12');
41 $this->assertEquals(array(0, 2), $this->getLevels($traces));
42
43 $traces = $matcher->getTraces('/bar/dd');
44 $this->assertEquals(array(0, 1, 1, 0, 0), $this->getLevels($traces));
45
46 $traces = $matcher->getTraces('/foo1');
47 $this->assertEquals(array(0, 0, 0, 0, 2), $this->getLevels($traces));
48
49 $context->setMethod('POST');
50 $traces = $matcher->getTraces('/foo');
51 $this->assertEquals(array(2), $this->getLevels($traces));
52
53 $traces = $matcher->getTraces('/bar/dd');
54 $this->assertEquals(array(0, 1, 2), $this->getLevels($traces));
55 }
56
57 public function getLevels($traces)
58 {
59 $levels = array();
60 foreach ($traces as $trace) {
61 $levels[] = $trace['level'];
62 }
63
64 return $levels;
65 }
66}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
new file mode 100644
index 00000000..8a1428f1
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
@@ -0,0 +1,383 @@
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
12namespace Symfony\Component\Routing\Tests\Matcher;
13
14use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15use Symfony\Component\Routing\Exception\ResourceNotFoundException;
16use Symfony\Component\Routing\Matcher\UrlMatcher;
17use Symfony\Component\Routing\Route;
18use Symfony\Component\Routing\RouteCollection;
19use Symfony\Component\Routing\RequestContext;
20
21class UrlMatcherTest extends \PHPUnit_Framework_TestCase
22{
23 public function testNoMethodSoAllowed()
24 {
25 $coll = new RouteCollection();
26 $coll->add('foo', new Route('/foo'));
27
28 $matcher = new UrlMatcher($coll, new RequestContext());
29 $matcher->match('/foo');
30 }
31
32 public function testMethodNotAllowed()
33 {
34 $coll = new RouteCollection();
35 $coll->add('foo', new Route('/foo', array(), array('_method' => 'post')));
36
37 $matcher = new UrlMatcher($coll, new RequestContext());
38
39 try {
40 $matcher->match('/foo');
41 $this->fail();
42 } catch (MethodNotAllowedException $e) {
43 $this->assertEquals(array('POST'), $e->getAllowedMethods());
44 }
45 }
46
47 public function testHeadAllowedWhenRequirementContainsGet()
48 {
49 $coll = new RouteCollection();
50 $coll->add('foo', new Route('/foo', array(), array('_method' => 'get')));
51
52 $matcher = new UrlMatcher($coll, new RequestContext('', 'head'));
53 $matcher->match('/foo');
54 }
55
56 public function testMethodNotAllowedAggregatesAllowedMethods()
57 {
58 $coll = new RouteCollection();
59 $coll->add('foo1', new Route('/foo', array(), array('_method' => 'post')));
60 $coll->add('foo2', new Route('/foo', array(), array('_method' => 'put|delete')));
61
62 $matcher = new UrlMatcher($coll, new RequestContext());
63
64 try {
65 $matcher->match('/foo');
66 $this->fail();
67 } catch (MethodNotAllowedException $e) {
68 $this->assertEquals(array('POST', 'PUT', 'DELETE'), $e->getAllowedMethods());
69 }
70 }
71
72 public function testMatch()
73 {
74 // test the patterns are matched and parameters are returned
75 $collection = new RouteCollection();
76 $collection->add('foo', new Route('/foo/{bar}'));
77 $matcher = new UrlMatcher($collection, new RequestContext());
78 try {
79 $matcher->match('/no-match');
80 $this->fail();
81 } catch (ResourceNotFoundException $e) {}
82 $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz'), $matcher->match('/foo/baz'));
83
84 // test that defaults are merged
85 $collection = new RouteCollection();
86 $collection->add('foo', new Route('/foo/{bar}', array('def' => 'test')));
87 $matcher = new UrlMatcher($collection, new RequestContext());
88 $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'def' => 'test'), $matcher->match('/foo/baz'));
89
90 // test that route "method" is ignored if no method is given in the context
91 $collection = new RouteCollection();
92 $collection->add('foo', new Route('/foo', array(), array('_method' => 'GET|head')));
93 $matcher = new UrlMatcher($collection, new RequestContext());
94 $this->assertInternalType('array', $matcher->match('/foo'));
95
96 // route does not match with POST method context
97 $matcher = new UrlMatcher($collection, new RequestContext('', 'post'));
98 try {
99 $matcher->match('/foo');
100 $this->fail();
101 } catch (MethodNotAllowedException $e) {}
102
103 // route does match with GET or HEAD method context
104 $matcher = new UrlMatcher($collection, new RequestContext());
105 $this->assertInternalType('array', $matcher->match('/foo'));
106 $matcher = new UrlMatcher($collection, new RequestContext('', 'head'));
107 $this->assertInternalType('array', $matcher->match('/foo'));
108
109 // route with an optional variable as the first segment
110 $collection = new RouteCollection();
111 $collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar')));
112 $matcher = new UrlMatcher($collection, new RequestContext());
113 $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo'));
114 $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo'));
115
116 $collection = new RouteCollection();
117 $collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar')));
118 $matcher = new UrlMatcher($collection, new RequestContext());
119 $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo'));
120 $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/'));
121
122 // route with only optional variables
123 $collection = new RouteCollection();
124 $collection->add('bar', new Route('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar'), array()));
125 $matcher = new UrlMatcher($collection, new RequestContext());
126 $this->assertEquals(array('_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'), $matcher->match('/'));
127 $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'), $matcher->match('/a'));
128 $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'b'), $matcher->match('/a/b'));
129 }
130
131 public function testMatchWithPrefixes()
132 {
133 $collection = new RouteCollection();
134 $collection->add('foo', new Route('/{foo}'));
135 $collection->addPrefix('/b');
136 $collection->addPrefix('/a');
137
138 $matcher = new UrlMatcher($collection, new RequestContext());
139 $this->assertEquals(array('_route' => 'foo', 'foo' => 'foo'), $matcher->match('/a/b/foo'));
140 }
141
142 public function testMatchWithDynamicPrefix()
143 {
144 $collection = new RouteCollection();
145 $collection->add('foo', new Route('/{foo}'));
146 $collection->addPrefix('/b');
147 $collection->addPrefix('/{_locale}');
148
149 $matcher = new UrlMatcher($collection, new RequestContext());
150 $this->assertEquals(array('_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'), $matcher->match('/fr/b/foo'));
151 }
152
153 public function testMatchSpecialRouteName()
154 {
155 $collection = new RouteCollection();
156 $collection->add('$péß^a|', new Route('/bar'));
157
158 $matcher = new UrlMatcher($collection, new RequestContext());
159 $this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar'));
160 }
161
162 public function testMatchNonAlpha()
163 {
164 $collection = new RouteCollection();
165 $chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-';
166 $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+')));
167
168 $matcher = new UrlMatcher($collection, new RequestContext());
169 $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.rawurlencode($chars).'/bar'));
170 $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.strtr($chars, array('%' => '%25')).'/bar'));
171 }
172
173 public function testMatchWithDotMetacharacterInRequirements()
174 {
175 $collection = new RouteCollection();
176 $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '.+')));
177
178 $matcher = new UrlMatcher($collection, new RequestContext());
179 $this->assertEquals(array('_route' => 'foo', 'foo' => "\n"), $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched');
180 }
181
182 public function testMatchOverriddenRoute()
183 {
184 $collection = new RouteCollection();
185 $collection->add('foo', new Route('/foo'));
186
187 $collection1 = new RouteCollection();
188 $collection1->add('foo', new Route('/foo1'));
189
190 $collection->addCollection($collection1);
191
192 $matcher = new UrlMatcher($collection, new RequestContext());
193
194 $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1'));
195 $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
196 $this->assertEquals(array(), $matcher->match('/foo'));
197 }
198
199 public function testMatchRegression()
200 {
201 $coll = new RouteCollection();
202 $coll->add('foo', new Route('/foo/{foo}'));
203 $coll->add('bar', new Route('/foo/bar/{foo}'));
204
205 $matcher = new UrlMatcher($coll, new RequestContext());
206 $this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar'));
207
208 $collection = new RouteCollection();
209 $collection->add('foo', new Route('/{bar}'));
210 $matcher = new UrlMatcher($collection, new RequestContext());
211 try {
212 $matcher->match('/');
213 $this->fail();
214 } catch (ResourceNotFoundException $e) {
215 }
216 }
217
218 public function testDefaultRequirementForOptionalVariables()
219 {
220 $coll = new RouteCollection();
221 $coll->add('test', new Route('/{page}.{_format}', array('page' => 'index', '_format' => 'html')));
222
223 $matcher = new UrlMatcher($coll, new RequestContext());
224 $this->assertEquals(array('page' => 'my-page', '_format' => 'xml', '_route' => 'test'), $matcher->match('/my-page.xml'));
225 }
226
227 public function testMatchingIsEager()
228 {
229 $coll = new RouteCollection();
230 $coll->add('test', new Route('/{foo}-{bar}-', array(), array('foo' => '.+', 'bar' => '.+')));
231
232 $matcher = new UrlMatcher($coll, new RequestContext());
233 $this->assertEquals(array('foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'), $matcher->match('/text1-text2-text3-text4-'));
234 }
235
236 public function testAdjacentVariables()
237 {
238 $coll = new RouteCollection();
239 $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => 'y|Y')));
240
241 $matcher = new UrlMatcher($coll, new RequestContext());
242 // 'w' eagerly matches as much as possible and the other variables match the remaining chars.
243 // This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement.
244 // Otherwise they would also consume '.xml' and _format would never match as it's an optional variable.
245 $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z','_format' => 'xml', '_route' => 'test'), $matcher->match('/wwwwwxYZ.xml'));
246 // As 'y' has custom requirement and can only be of value 'y|Y', it will leave 'ZZZ' to variable z.
247 // So with carefully chosen requirements adjacent variables, can be useful.
248 $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxyZZZ'));
249 // z and _format are optional.
250 $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxy'));
251
252 $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
253 $matcher->match('/wxy.html');
254 }
255
256 public function testOptionalVariableWithNoRealSeparator()
257 {
258 $coll = new RouteCollection();
259 $coll->add('test', new Route('/get{what}', array('what' => 'All')));
260 $matcher = new UrlMatcher($coll, new RequestContext());
261
262 $this->assertEquals(array('what' => 'All', '_route' => 'test'), $matcher->match('/get'));
263 $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSites'));
264
265 // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match.
266 // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it.
267 $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException');
268 $matcher->match('/ge');
269 }
270
271 public function testRequiredVariableWithNoRealSeparator()
272 {
273 $coll = new RouteCollection();
274 $coll->add('test', new Route('/get{what}Suffix'));
275 $matcher = new UrlMatcher($coll, new RequestContext());
276
277 $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSitesSuffix'));
278 }
279
280 public function testDefaultRequirementOfVariable()
281 {
282 $coll = new RouteCollection();
283 $coll->add('test', new Route('/{page}.{_format}'));
284 $matcher = new UrlMatcher($coll, new RequestContext());
285
286 $this->assertEquals(array('page' => 'index', '_format' => 'mobile.html', '_route' => 'test'), $matcher->match('/index.mobile.html'));
287 }
288
289 /**
290 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
291 */
292 public function testDefaultRequirementOfVariableDisallowsSlash()
293 {
294 $coll = new RouteCollection();
295 $coll->add('test', new Route('/{page}.{_format}'));
296 $matcher = new UrlMatcher($coll, new RequestContext());
297
298 $matcher->match('/index.sl/ash');
299 }
300
301 /**
302 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
303 */
304 public function testDefaultRequirementOfVariableDisallowsNextSeparator()
305 {
306 $coll = new RouteCollection();
307 $coll->add('test', new Route('/{page}.{_format}', array(), array('_format' => 'html|xml')));
308 $matcher = new UrlMatcher($coll, new RequestContext());
309
310 $matcher->match('/do.t.html');
311 }
312
313 /**
314 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
315 */
316 public function testSchemeRequirement()
317 {
318 $coll = new RouteCollection();
319 $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https')));
320 $matcher = new UrlMatcher($coll, new RequestContext());
321 $matcher->match('/foo');
322 }
323
324 public function testDecodeOnce()
325 {
326 $coll = new RouteCollection();
327 $coll->add('foo', new Route('/foo/{foo}'));
328
329 $matcher = new UrlMatcher($coll, new RequestContext());
330 $this->assertEquals(array('foo' => 'bar%23', '_route' => 'foo'), $matcher->match('/foo/bar%2523'));
331 }
332
333 public function testCannotRelyOnPrefix()
334 {
335 $coll = new RouteCollection();
336
337 $subColl = new RouteCollection();
338 $subColl->add('bar', new Route('/bar'));
339 $subColl->addPrefix('/prefix');
340 // overwrite the pattern, so the prefix is not valid anymore for this route in the collection
341 $subColl->get('bar')->setPattern('/new');
342
343 $coll->addCollection($subColl);
344
345 $matcher = new UrlMatcher($coll, new RequestContext());
346 $this->assertEquals(array('_route' => 'bar'), $matcher->match('/new'));
347 }
348
349 public function testWithHost()
350 {
351 $coll = new RouteCollection();
352 $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
353
354 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
355 $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
356 }
357
358 public function testWithHostOnRouteCollection()
359 {
360 $coll = new RouteCollection();
361 $coll->add('foo', new Route('/foo/{foo}'));
362 $coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net'));
363 $coll->setHost('{locale}.example.com');
364
365 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
366 $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar'));
367
368 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com'));
369 $this->assertEquals(array('foo' => 'bar', '_route' => 'bar', 'locale' => 'en'), $matcher->match('/bar/bar'));
370 }
371
372 /**
373 * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
374 */
375 public function testWithOutHostHostDoesNotMatch()
376 {
377 $coll = new RouteCollection();
378 $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com'));
379
380 $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'example.com'));
381 $matcher->match('/foo/bar');
382 }
383}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php
new file mode 100644
index 00000000..3d78adf9
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCollectionTest.php
@@ -0,0 +1,255 @@
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
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\RouteCollection;
15use Symfony\Component\Routing\Route;
16use Symfony\Component\Config\Resource\FileResource;
17
18class RouteCollectionTest extends \PHPUnit_Framework_TestCase
19{
20 public function testRoute()
21 {
22 $collection = new RouteCollection();
23 $route = new Route('/foo');
24 $collection->add('foo', $route);
25 $this->assertEquals(array('foo' => $route), $collection->all(), '->add() adds a route');
26 $this->assertEquals($route, $collection->get('foo'), '->get() returns a route by name');
27 $this->assertNull($collection->get('bar'), '->get() returns null if a route does not exist');
28 }
29
30 public function testOverriddenRoute()
31 {
32 $collection = new RouteCollection();
33 $collection->add('foo', new Route('/foo'));
34 $collection->add('foo', new Route('/foo1'));
35
36 $this->assertEquals('/foo1', $collection->get('foo')->getPath());
37 }
38
39 public function testDeepOverriddenRoute()
40 {
41 $collection = new RouteCollection();
42 $collection->add('foo', new Route('/foo'));
43
44 $collection1 = new RouteCollection();
45 $collection1->add('foo', new Route('/foo1'));
46
47 $collection2 = new RouteCollection();
48 $collection2->add('foo', new Route('/foo2'));
49
50 $collection1->addCollection($collection2);
51 $collection->addCollection($collection1);
52
53 $this->assertEquals('/foo2', $collection1->get('foo')->getPath());
54 $this->assertEquals('/foo2', $collection->get('foo')->getPath());
55 }
56
57 public function testIterator()
58 {
59 $collection = new RouteCollection();
60 $collection->add('foo', new Route('/foo'));
61
62 $collection1 = new RouteCollection();
63 $collection1->add('bar', $bar = new Route('/bar'));
64 $collection1->add('foo', $foo = new Route('/foo-new'));
65 $collection->addCollection($collection1);
66 $collection->add('last', $last = new Route('/last'));
67
68 $this->assertInstanceOf('\ArrayIterator', $collection->getIterator());
69 $this->assertSame(array('bar' => $bar, 'foo' => $foo, 'last' => $last), $collection->getIterator()->getArrayCopy());
70 }
71
72 public function testCount()
73 {
74 $collection = new RouteCollection();
75 $collection->add('foo', new Route('/foo'));
76
77 $collection1 = new RouteCollection();
78 $collection1->add('bar', new Route('/bar'));
79 $collection->addCollection($collection1);
80
81 $this->assertCount(2, $collection);
82 }
83
84 public function testAddCollection()
85 {
86 $collection = new RouteCollection();
87 $collection->add('foo', new Route('/foo'));
88
89 $collection1 = new RouteCollection();
90 $collection1->add('bar', $bar = new Route('/bar'));
91 $collection1->add('foo', $foo = new Route('/foo-new'));
92
93 $collection2 = new RouteCollection();
94 $collection2->add('grandchild', $grandchild = new Route('/grandchild'));
95
96 $collection1->addCollection($collection2);
97 $collection->addCollection($collection1);
98 $collection->add('last', $last = new Route('/last'));
99
100 $this->assertSame(array('bar' => $bar, 'foo' => $foo, 'grandchild' => $grandchild, 'last' => $last), $collection->all(),
101 '->addCollection() imports routes of another collection, overrides if necessary and adds them at the end');
102 }
103
104 public function testAddCollectionWithResources()
105 {
106 if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
107 $this->markTestSkipped('The "Config" component is not available');
108 }
109
110 $collection = new RouteCollection();
111 $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml'));
112 $collection1 = new RouteCollection();
113 $collection1->addResource($foo1 = new FileResource(__DIR__.'/Fixtures/foo1.xml'));
114 $collection->addCollection($collection1);
115 $this->assertEquals(array($foo, $foo1), $collection->getResources(), '->addCollection() merges resources');
116 }
117
118 public function testAddDefaultsAndRequirementsAndOptions()
119 {
120 $collection = new RouteCollection();
121 $collection->add('foo', new Route('/{placeholder}'));
122 $collection1 = new RouteCollection();
123 $collection1->add('bar', new Route('/{placeholder}',
124 array('_controller' => 'fixed', 'placeholder' => 'default'), array('placeholder' => '.+'), array('option' => 'value'))
125 );
126 $collection->addCollection($collection1);
127
128 $collection->addDefaults(array('placeholder' => 'new-default'));
129 $this->assertEquals(array('placeholder' => 'new-default'), $collection->get('foo')->getDefaults(), '->addDefaults() adds defaults to all routes');
130 $this->assertEquals(array('_controller' => 'fixed', 'placeholder' => 'new-default'), $collection->get('bar')->getDefaults(),
131 '->addDefaults() adds defaults to all routes and overwrites existing ones');
132
133 $collection->addRequirements(array('placeholder' => '\d+'));
134 $this->assertEquals(array('placeholder' => '\d+'), $collection->get('foo')->getRequirements(), '->addRequirements() adds requirements to all routes');
135 $this->assertEquals(array('placeholder' => '\d+'), $collection->get('bar')->getRequirements(),
136 '->addRequirements() adds requirements to all routes and overwrites existing ones');
137
138 $collection->addOptions(array('option' => 'new-value'));
139 $this->assertEquals(
140 array('option' => 'new-value', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'),
141 $collection->get('bar')->getOptions(), '->addOptions() adds options to all routes and overwrites existing ones'
142 );
143 }
144
145 public function testAddPrefix()
146 {
147 $collection = new RouteCollection();
148 $collection->add('foo', $foo = new Route('/foo'));
149 $collection2 = new RouteCollection();
150 $collection2->add('bar', $bar = new Route('/bar'));
151 $collection->addCollection($collection2);
152 $collection->addPrefix(' / ');
153 $this->assertSame('/foo', $collection->get('foo')->getPattern(), '->addPrefix() trims the prefix and a single slash has no effect');
154 $collection->addPrefix('/{admin}', array('admin' => 'admin'), array('admin' => '\d+'));
155 $this->assertEquals('/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() adds a prefix to all routes');
156 $this->assertEquals('/{admin}/bar', $collection->get('bar')->getPath(), '->addPrefix() adds a prefix to all routes');
157 $this->assertEquals(array('admin' => 'admin'), $collection->get('foo')->getDefaults(), '->addPrefix() adds defaults to all routes');
158 $this->assertEquals(array('admin' => 'admin'), $collection->get('bar')->getDefaults(), '->addPrefix() adds defaults to all routes');
159 $this->assertEquals(array('admin' => '\d+'), $collection->get('foo')->getRequirements(), '->addPrefix() adds requirements to all routes');
160 $this->assertEquals(array('admin' => '\d+'), $collection->get('bar')->getRequirements(), '->addPrefix() adds requirements to all routes');
161 $collection->addPrefix('0');
162 $this->assertEquals('/0/{admin}/foo', $collection->get('foo')->getPattern(), '->addPrefix() ensures a prefix must start with a slash and must not end with a slash');
163 $collection->addPrefix('/ /');
164 $this->assertSame('/ /0/{admin}/foo', $collection->get('foo')->getPath(), '->addPrefix() can handle spaces if desired');
165 $this->assertSame('/ /0/{admin}/bar', $collection->get('bar')->getPath(), 'the route pattern of an added collection is in synch with the added prefix');
166 }
167
168 public function testAddPrefixOverridesDefaultsAndRequirements()
169 {
170 $collection = new RouteCollection();
171 $collection->add('foo', $foo = new Route('/foo'));
172 $collection->add('bar', $bar = new Route('/bar', array(), array('_scheme' => 'http')));
173 $collection->addPrefix('/admin', array(), array('_scheme' => 'https'));
174
175 $this->assertEquals('https', $collection->get('foo')->getRequirement('_scheme'), '->addPrefix() overrides existing requirements');
176 $this->assertEquals('https', $collection->get('bar')->getRequirement('_scheme'), '->addPrefix() overrides existing requirements');
177 }
178
179 public function testResource()
180 {
181 if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
182 $this->markTestSkipped('The "Config" component is not available');
183 }
184
185 $collection = new RouteCollection();
186 $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml'));
187 $collection->addResource($bar = new FileResource(__DIR__.'/Fixtures/bar.xml'));
188 $collection->addResource(new FileResource(__DIR__.'/Fixtures/foo.xml'));
189
190 $this->assertEquals(array($foo, $bar), $collection->getResources(),
191 '->addResource() adds a resource and getResources() only returns unique ones by comparing the string representation');
192 }
193
194 public function testUniqueRouteWithGivenName()
195 {
196 $collection1 = new RouteCollection();
197 $collection1->add('foo', new Route('/old'));
198 $collection2 = new RouteCollection();
199 $collection3 = new RouteCollection();
200 $collection3->add('foo', $new = new Route('/new'));
201
202 $collection2->addCollection($collection3);
203 $collection1->addCollection($collection2);
204
205 $this->assertSame($new, $collection1->get('foo'), '->get() returns new route that overrode previous one');
206 // size of 1 because collection1 contains /new but not /old anymore
207 $this->assertCount(1, $collection1->getIterator(), '->addCollection() removes previous routes when adding new routes with the same name');
208 }
209
210 public function testGet()
211 {
212 $collection1 = new RouteCollection();
213 $collection1->add('a', $a = new Route('/a'));
214 $collection2 = new RouteCollection();
215 $collection2->add('b', $b = new Route('/b'));
216 $collection1->addCollection($collection2);
217 $collection1->add('$péß^a|', $c = new Route('/special'));
218
219 $this->assertSame($b, $collection1->get('b'), '->get() returns correct route in child collection');
220 $this->assertSame($c, $collection1->get('$péß^a|'), '->get() can handle special characters');
221 $this->assertNull($collection2->get('a'), '->get() does not return the route defined in parent collection');
222 $this->assertNull($collection1->get('non-existent'), '->get() returns null when route does not exist');
223 $this->assertNull($collection1->get(0), '->get() does not disclose internal child RouteCollection');
224 }
225
226 public function testRemove()
227 {
228 $collection = new RouteCollection();
229 $collection->add('foo', $foo = new Route('/foo'));
230
231 $collection1 = new RouteCollection();
232 $collection1->add('bar', $bar = new Route('/bar'));
233 $collection->addCollection($collection1);
234 $collection->add('last', $last = new Route('/last'));
235
236 $collection->remove('foo');
237 $this->assertSame(array('bar' => $bar, 'last' => $last), $collection->all(), '->remove() can remove a single route');
238 $collection->remove(array('bar', 'last'));
239 $this->assertSame(array(), $collection->all(), '->remove() accepts an array and can remove multiple routes at once');
240 }
241
242 public function testSetHost()
243 {
244 $collection = new RouteCollection();
245 $routea = new Route('/a');
246 $routeb = new Route('/b', array(), array(), array(), '{locale}.example.net');
247 $collection->add('a', $routea);
248 $collection->add('b', $routeb);
249
250 $collection->setHost('{locale}.example.com');
251
252 $this->assertEquals('{locale}.example.com', $routea->getHost());
253 $this->assertEquals('{locale}.example.com', $routeb->getHost());
254 }
255}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php
new file mode 100644
index 00000000..d663ae96
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteCompilerTest.php
@@ -0,0 +1,253 @@
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
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\Route;
15
16class RouteCompilerTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @dataProvider provideCompileData
20 */
21 public function testCompile($name, $arguments, $prefix, $regex, $variables, $tokens)
22 {
23 $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
24 $route = $r->newInstanceArgs($arguments);
25
26 $compiled = $route->compile();
27 $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
28 $this->assertEquals($regex, $compiled->getRegex(), $name.' (regex)');
29 $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
30 $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
31 }
32
33 public function provideCompileData()
34 {
35 return array(
36 array(
37 'Static route',
38 array('/foo'),
39 '/foo', '#^/foo$#s', array(), array(
40 array('text', '/foo'),
41 )),
42
43 array(
44 'Route with a variable',
45 array('/foo/{bar}'),
46 '/foo', '#^/foo/(?P<bar>[^/]++)$#s', array('bar'), array(
47 array('variable', '/', '[^/]++', 'bar'),
48 array('text', '/foo'),
49 )),
50
51 array(
52 'Route with a variable that has a default value',
53 array('/foo/{bar}', array('bar' => 'bar')),
54 '/foo', '#^/foo(?:/(?P<bar>[^/]++))?$#s', array('bar'), array(
55 array('variable', '/', '[^/]++', 'bar'),
56 array('text', '/foo'),
57 )),
58
59 array(
60 'Route with several variables',
61 array('/foo/{bar}/{foobar}'),
62 '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
63 array('variable', '/', '[^/]++', 'foobar'),
64 array('variable', '/', '[^/]++', 'bar'),
65 array('text', '/foo'),
66 )),
67
68 array(
69 'Route with several variables that have default values',
70 array('/foo/{bar}/{foobar}', array('bar' => 'bar', 'foobar' => '')),
71 '/foo', '#^/foo(?:/(?P<bar>[^/]++)(?:/(?P<foobar>[^/]++))?)?$#s', array('bar', 'foobar'), array(
72 array('variable', '/', '[^/]++', 'foobar'),
73 array('variable', '/', '[^/]++', 'bar'),
74 array('text', '/foo'),
75 )),
76
77 array(
78 'Route with several variables but some of them have no default values',
79 array('/foo/{bar}/{foobar}', array('bar' => 'bar')),
80 '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
81 array('variable', '/', '[^/]++', 'foobar'),
82 array('variable', '/', '[^/]++', 'bar'),
83 array('text', '/foo'),
84 )),
85
86 array(
87 'Route with an optional variable as the first segment',
88 array('/{bar}', array('bar' => 'bar')),
89 '', '#^/(?P<bar>[^/]++)?$#s', array('bar'), array(
90 array('variable', '/', '[^/]++', 'bar'),
91 )),
92
93 array(
94 'Route with a requirement of 0',
95 array('/{bar}', array('bar' => null), array('bar' => '0')),
96 '', '#^/(?P<bar>0)?$#s', array('bar'), array(
97 array('variable', '/', '0', 'bar'),
98 )),
99
100 array(
101 'Route with an optional variable as the first segment with requirements',
102 array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
103 '', '#^/(?P<bar>(foo|bar))?$#s', array('bar'), array(
104 array('variable', '/', '(foo|bar)', 'bar'),
105 )),
106
107 array(
108 'Route with only optional variables',
109 array('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar')),
110 '', '#^/(?P<foo>[^/]++)?(?:/(?P<bar>[^/]++))?$#s', array('foo', 'bar'), array(
111 array('variable', '/', '[^/]++', 'bar'),
112 array('variable', '/', '[^/]++', 'foo'),
113 )),
114
115 array(
116 'Route with a variable in last position',
117 array('/foo-{bar}'),
118 '/foo', '#^/foo\-(?P<bar>[^/]++)$#s', array('bar'), array(
119 array('variable', '-', '[^/]++', 'bar'),
120 array('text', '/foo'),
121 )),
122
123 array(
124 'Route with nested placeholders',
125 array('/{static{var}static}'),
126 '/{static', '#^/\{static(?P<var>[^/]+)static\}$#s', array('var'), array(
127 array('text', 'static}'),
128 array('variable', '', '[^/]+', 'var'),
129 array('text', '/{static'),
130 )),
131
132 array(
133 'Route without separator between variables',
134 array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')),
135 '', '#^/(?P<w>[^/\.]+)(?P<x>[^/\.]+)(?P<y>(y|Y))(?:(?P<z>[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#s', array('w', 'x', 'y', 'z', '_format'), array(
136 array('variable', '.', '[^/]++', '_format'),
137 array('variable', '', '[^/\.]++', 'z'),
138 array('variable', '', '(y|Y)', 'y'),
139 array('variable', '', '[^/\.]+', 'x'),
140 array('variable', '/', '[^/\.]+', 'w'),
141 )),
142
143 array(
144 'Route with a format',
145 array('/foo/{bar}.{_format}'),
146 '/foo', '#^/foo/(?P<bar>[^/\.]++)\.(?P<_format>[^/]++)$#s', array('bar', '_format'), array(
147 array('variable', '.', '[^/]++', '_format'),
148 array('variable', '/', '[^/\.]++', 'bar'),
149 array('text', '/foo'),
150 )),
151 );
152 }
153
154 /**
155 * @expectedException \LogicException
156 */
157 public function testRouteWithSameVariableTwice()
158 {
159 $route = new Route('/{name}/{name}');
160
161 $compiled = $route->compile();
162 }
163
164 /**
165 * @dataProvider getNumericVariableNames
166 * @expectedException \DomainException
167 */
168 public function testRouteWithNumericVariableName($name)
169 {
170 $route = new Route('/{'. $name.'}');
171 $route->compile();
172 }
173
174 public function getNumericVariableNames()
175 {
176 return array(
177 array('09'),
178 array('123'),
179 array('1e2')
180 );
181 }
182
183 /**
184 * @dataProvider provideCompileWithHostData
185 */
186 public function testCompileWithHost($name, $arguments, $prefix, $regex, $variables, $pathVariables, $tokens, $hostRegex, $hostVariables, $hostTokens)
187 {
188 $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
189 $route = $r->newInstanceArgs($arguments);
190
191 $compiled = $route->compile();
192 $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
193 $this->assertEquals($regex, str_replace(array("\n", ' '), '', $compiled->getRegex()), $name.' (regex)');
194 $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
195 $this->assertEquals($pathVariables, $compiled->getPathVariables(), $name.' (path variables)');
196 $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
197 $this->assertEquals($hostRegex, str_replace(array("\n", ' '), '', $compiled->getHostRegex()), $name.' (host regex)');
198 $this->assertEquals($hostVariables, $compiled->getHostVariables(), $name.' (host variables)');
199 $this->assertEquals($hostTokens, $compiled->getHostTokens(), $name.' (host tokens)');
200 }
201
202 public function provideCompileWithHostData()
203 {
204 return array(
205 array(
206 'Route with host pattern',
207 array('/hello', array(), array(), array(), 'www.example.com'),
208 '/hello', '#^/hello$#s', array(), array(), array(
209 array('text', '/hello'),
210 ),
211 '#^www\.example\.com$#s', array(), array(
212 array('text', 'www.example.com'),
213 ),
214 ),
215 array(
216 'Route with host pattern and some variables',
217 array('/hello/{name}', array(), array(), array(), 'www.example.{tld}'),
218 '/hello', '#^/hello/(?P<name>[^/]++)$#s', array('tld', 'name'), array('name'), array(
219 array('variable', '/', '[^/]++', 'name'),
220 array('text', '/hello'),
221 ),
222 '#^www\.example\.(?P<tld>[^\.]++)$#s', array('tld'), array(
223 array('variable', '.', '[^\.]++', 'tld'),
224 array('text', 'www.example'),
225 ),
226 ),
227 array(
228 'Route with variable at beginning of host',
229 array('/hello', array(), array(), array(), '{locale}.example.{tld}'),
230 '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
231 array('text', '/hello'),
232 ),
233 '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
234 array('variable', '.', '[^\.]++', 'tld'),
235 array('text', '.example'),
236 array('variable', '', '[^\.]++', 'locale'),
237 ),
238 ),
239 array(
240 'Route with host variables that has a default value',
241 array('/hello', array('locale' => 'a', 'tld' => 'b'), array(), array(), '{locale}.example.{tld}'),
242 '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
243 array('text', '/hello'),
244 ),
245 '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#s', array('locale', 'tld'), array(
246 array('variable', '.', '[^\.]++', 'tld'),
247 array('text', '.example'),
248 array('variable', '', '[^\.]++', 'locale'),
249 ),
250 ),
251 );
252 }
253}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php
new file mode 100644
index 00000000..31f1066f
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouteTest.php
@@ -0,0 +1,192 @@
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
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\Route;
15
16class RouteTest extends \PHPUnit_Framework_TestCase
17{
18 public function testConstructor()
19 {
20 $route = new Route('/{foo}', array('foo' => 'bar'), array('foo' => '\d+'), array('foo' => 'bar'), '{locale}.example.com');
21 $this->assertEquals('/{foo}', $route->getPath(), '__construct() takes a path as its first argument');
22 $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '__construct() takes defaults as its second argument');
23 $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '__construct() takes requirements as its third argument');
24 $this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument');
25 $this->assertEquals('{locale}.example.com', $route->getHost(), '__construct() takes a host pattern as its fifth argument');
26
27 $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'));
28 $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it');
29 $this->assertEquals(array('POST', 'PUT'), $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it');
30
31 $route = new Route('/', array(), array(), array(), '', 'Https', 'Post');
32 $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument');
33 $this->assertEquals(array('POST'), $route->getMethods(), '__construct() takes a single method as its seventh argument');
34 }
35
36 public function testPath()
37 {
38 $route = new Route('/{foo}');
39 $route->setPath('/{bar}');
40 $this->assertEquals('/{bar}', $route->getPath(), '->setPath() sets the path');
41 $route->setPath('');
42 $this->assertEquals('/', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
43 $route->setPath('bar');
44 $this->assertEquals('/bar', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
45 $this->assertEquals($route, $route->setPath(''), '->setPath() implements a fluent interface');
46 $route->setPath('//path');
47 $this->assertEquals('/path', $route->getPath(), '->setPath() does not allow two slahes "//" at the beginning of the path as it would be confused with a network path when generating the path from the route');
48 }
49
50 public function testOptions()
51 {
52 $route = new Route('/{foo}');
53 $route->setOptions(array('foo' => 'bar'));
54 $this->assertEquals(array_merge(array(
55 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
56 ), array('foo' => 'bar')), $route->getOptions(), '->setOptions() sets the options');
57 $this->assertEquals($route, $route->setOptions(array()), '->setOptions() implements a fluent interface');
58
59 $route->setOptions(array('foo' => 'foo'));
60 $route->addOptions(array('bar' => 'bar'));
61 $this->assertEquals($route, $route->addOptions(array()), '->addOptions() implements a fluent interface');
62 $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $route->getOptions(), '->addDefaults() keep previous defaults');
63 }
64
65 public function testDefaults()
66 {
67 $route = new Route('/{foo}');
68 $route->setDefaults(array('foo' => 'bar'));
69 $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '->setDefaults() sets the defaults');
70 $this->assertEquals($route, $route->setDefaults(array()), '->setDefaults() implements a fluent interface');
71
72 $route->setDefault('foo', 'bar');
73 $this->assertEquals('bar', $route->getDefault('foo'), '->setDefault() sets a default value');
74
75 $route->setDefault('foo2', 'bar2');
76 $this->assertEquals('bar2', $route->getDefault('foo2'), '->getDefault() return the default value');
77 $this->assertNull($route->getDefault('not_defined'), '->getDefault() return null if default value is not setted');
78
79 $route->setDefault('_controller', $closure = function () { return 'Hello'; });
80 $this->assertEquals($closure, $route->getDefault('_controller'), '->setDefault() sets a default value');
81
82 $route->setDefaults(array('foo' => 'foo'));
83 $route->addDefaults(array('bar' => 'bar'));
84 $this->assertEquals($route, $route->addDefaults(array()), '->addDefaults() implements a fluent interface');
85 $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $route->getDefaults(), '->addDefaults() keep previous defaults');
86 }
87
88 public function testRequirements()
89 {
90 $route = new Route('/{foo}');
91 $route->setRequirements(array('foo' => '\d+'));
92 $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '->setRequirements() sets the requirements');
93 $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() returns a requirement');
94 $this->assertNull($route->getRequirement('bar'), '->getRequirement() returns null if a requirement is not defined');
95 $route->setRequirements(array('foo' => '^\d+$'));
96 $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the path');
97 $this->assertEquals($route, $route->setRequirements(array()), '->setRequirements() implements a fluent interface');
98
99 $route->setRequirements(array('foo' => '\d+'));
100 $route->addRequirements(array('bar' => '\d+'));
101 $this->assertEquals($route, $route->addRequirements(array()), '->addRequirements() implements a fluent interface');
102 $this->assertEquals(array('foo' => '\d+', 'bar' => '\d+'), $route->getRequirements(), '->addRequirement() keep previous requirements');
103 }
104
105 public function testRequirement()
106 {
107 $route = new Route('/{foo}');
108 $route->setRequirement('foo', '^\d+$');
109 $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the path');
110 }
111
112 /**
113 * @dataProvider getInvalidRequirements
114 * @expectedException \InvalidArgumentException
115 */
116 public function testSetInvalidRequirement($req)
117 {
118 $route = new Route('/{foo}');
119 $route->setRequirement('foo', $req);
120 }
121
122 public function getInvalidRequirements()
123 {
124 return array(
125 array(''),
126 array(array()),
127 array('^$'),
128 array('^'),
129 array('$')
130 );
131 }
132
133 public function testHost()
134 {
135 $route = new Route('/');
136 $route->setHost('{locale}.example.net');
137 $this->assertEquals('{locale}.example.net', $route->getHost(), '->setHost() sets the host pattern');
138 }
139
140 public function testScheme()
141 {
142 $route = new Route('/');
143 $this->assertEquals(array(), $route->getSchemes(), 'schemes is initialized with array()');
144 $route->setSchemes('hTTp');
145 $this->assertEquals(array('http'), $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it');
146 $route->setSchemes(array('HttpS', 'hTTp'));
147 $this->assertEquals(array('https', 'http'), $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them');
148 }
149
150 public function testSchemeIsBC()
151 {
152 $route = new Route('/');
153 $route->setRequirement('_scheme', 'http|https');
154 $this->assertEquals('http|https', $route->getRequirement('_scheme'));
155 $this->assertEquals(array('http', 'https'), $route->getSchemes());
156 $route->setSchemes(array('hTTp'));
157 $this->assertEquals('http', $route->getRequirement('_scheme'));
158 $route->setSchemes(array());
159 $this->assertNull($route->getRequirement('_scheme'));
160 }
161
162 public function testMethod()
163 {
164 $route = new Route('/');
165 $this->assertEquals(array(), $route->getMethods(), 'methods is initialized with array()');
166 $route->setMethods('gEt');
167 $this->assertEquals(array('GET'), $route->getMethods(), '->setMethods() accepts a single method string and uppercases it');
168 $route->setMethods(array('gEt', 'PosT'));
169 $this->assertEquals(array('GET', 'POST'), $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them');
170 }
171
172 public function testMethodIsBC()
173 {
174 $route = new Route('/');
175 $route->setRequirement('_method', 'GET|POST');
176 $this->assertEquals('GET|POST', $route->getRequirement('_method'));
177 $this->assertEquals(array('GET', 'POST'), $route->getMethods());
178 $route->setMethods(array('gEt'));
179 $this->assertEquals('GET', $route->getRequirement('_method'));
180 $route->setMethods(array());
181 $this->assertNull($route->getRequirement('_method'));
182 }
183
184 public function testCompile()
185 {
186 $route = new Route('/{foo}');
187 $this->assertInstanceOf('Symfony\Component\Routing\CompiledRoute', $compiled = $route->compile(), '->compile() returns a compiled route');
188 $this->assertSame($compiled, $route->compile(), '->compile() only compiled the route once if unchanged');
189 $route->setRequirement('foo', '.*');
190 $this->assertNotSame($compiled, $route->compile(), '->compile() recompiles if the route was modified');
191 }
192}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php
new file mode 100644
index 00000000..a3c336e5
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/RouterTest.php
@@ -0,0 +1,138 @@
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
12namespace Symfony\Component\Routing\Tests;
13
14use Symfony\Component\Routing\Router;
15
16class RouterTest extends \PHPUnit_Framework_TestCase
17{
18 private $router = null;
19
20 private $loader = null;
21
22 protected function setUp()
23 {
24 $this->loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
25 $this->router = new Router($this->loader, 'routing.yml');
26 }
27
28 public function testSetOptionsWithSupportedOptions()
29 {
30 $this->router->setOptions(array(
31 'cache_dir' => './cache',
32 'debug' => true,
33 'resource_type' => 'ResourceType'
34 ));
35
36 $this->assertSame('./cache', $this->router->getOption('cache_dir'));
37 $this->assertTrue($this->router->getOption('debug'));
38 $this->assertSame('ResourceType', $this->router->getOption('resource_type'));
39 }
40
41 /**
42 * @expectedException \InvalidArgumentException
43 * @expectedExceptionMessage The Router does not support the following options: "option_foo", "option_bar"
44 */
45 public function testSetOptionsWithUnsupportedOptions()
46 {
47 $this->router->setOptions(array(
48 'cache_dir' => './cache',
49 'option_foo' => true,
50 'option_bar' => 'baz',
51 'resource_type' => 'ResourceType'
52 ));
53 }
54
55 public function testSetOptionWithSupportedOption()
56 {
57 $this->router->setOption('cache_dir', './cache');
58
59 $this->assertSame('./cache', $this->router->getOption('cache_dir'));
60 }
61
62 /**
63 * @expectedException \InvalidArgumentException
64 * @expectedExceptionMessage The Router does not support the "option_foo" option
65 */
66 public function testSetOptionWithUnsupportedOption()
67 {
68 $this->router->setOption('option_foo', true);
69 }
70
71 /**
72 * @expectedException \InvalidArgumentException
73 * @expectedExceptionMessage The Router does not support the "option_foo" option
74 */
75 public function testGetOptionWithUnsupportedOption()
76 {
77 $this->router->getOption('option_foo', true);
78 }
79
80 public function testThatRouteCollectionIsLoaded()
81 {
82 $this->router->setOption('resource_type', 'ResourceType');
83
84 $routeCollection = $this->getMock('Symfony\Component\Routing\RouteCollection');
85
86 $this->loader->expects($this->once())
87 ->method('load')->with('routing.yml', 'ResourceType')
88 ->will($this->returnValue($routeCollection));
89
90 $this->assertSame($routeCollection, $this->router->getRouteCollection());
91 }
92
93 /**
94 * @dataProvider provideMatcherOptionsPreventingCaching
95 */
96 public function testMatcherIsCreatedIfCacheIsNotConfigured($option)
97 {
98 $this->router->setOption($option, null);
99
100 $this->loader->expects($this->once())
101 ->method('load')->with('routing.yml', null)
102 ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RouteCollection')));
103
104 $this->assertInstanceOf('Symfony\\Component\\Routing\\Matcher\\UrlMatcher', $this->router->getMatcher());
105
106 }
107
108 public function provideMatcherOptionsPreventingCaching()
109 {
110 return array(
111 array('cache_dir'),
112 array('matcher_cache_class')
113 );
114 }
115
116 /**
117 * @dataProvider provideGeneratorOptionsPreventingCaching
118 */
119 public function testGeneratorIsCreatedIfCacheIsNotConfigured($option)
120 {
121 $this->router->setOption($option, null);
122
123 $this->loader->expects($this->once())
124 ->method('load')->with('routing.yml', null)
125 ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RouteCollection')));
126
127 $this->assertInstanceOf('Symfony\\Component\\Routing\\Generator\\UrlGenerator', $this->router->getGenerator());
128
129 }
130
131 public function provideGeneratorOptionsPreventingCaching()
132 {
133 return array(
134 array('cache_dir'),
135 array('generator_cache_class')
136 );
137 }
138}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/composer.json b/vendor/symfony/routing/Symfony/Component/Routing/composer.json
new file mode 100644
index 00000000..9a737c6b
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/composer.json
@@ -0,0 +1,42 @@
1{
2 "name": "symfony/routing",
3 "type": "library",
4 "description": "Symfony Routing Component",
5 "keywords": [],
6 "homepage": "http://symfony.com",
7 "license": "MIT",
8 "authors": [
9 {
10 "name": "Fabien Potencier",
11 "email": "fabien@symfony.com"
12 },
13 {
14 "name": "Symfony Community",
15 "homepage": "http://symfony.com/contributors"
16 }
17 ],
18 "require": {
19 "php": ">=5.3.3"
20 },
21 "require-dev": {
22 "symfony/config": "~2.2",
23 "symfony/yaml": "~2.0",
24 "doctrine/common": "~2.2",
25 "psr/log": "~1.0"
26 },
27 "suggest": {
28 "symfony/config": "",
29 "symfony/yaml": "",
30 "doctrine/common": ""
31 },
32 "autoload": {
33 "psr-0": { "Symfony\\Component\\Routing\\": "" }
34 },
35 "target-dir": "Symfony/Component/Routing",
36 "minimum-stability": "dev",
37 "extra": {
38 "branch-alias": {
39 "dev-master": "2.3-dev"
40 }
41 }
42}
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist b/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist
new file mode 100644
index 00000000..830066aa
--- /dev/null
+++ b/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8"?>
2
3<phpunit backupGlobals="false"
4 backupStaticAttributes="false"
5 colors="true"
6 convertErrorsToExceptions="true"
7 convertNoticesToExceptions="true"
8 convertWarningsToExceptions="true"
9 processIsolation="false"
10 stopOnFailure="false"
11 syntaxCheck="false"
12 bootstrap="vendor/autoload.php"
13>
14 <testsuites>
15 <testsuite name="Symfony Routing Component Test Suite">
16 <directory>./Tests/</directory>
17 </testsuite>
18 </testsuites>
19
20 <filter>
21 <whitelist>
22 <directory>./</directory>
23 <exclude>
24 <directory>./vendor</directory>
25 <directory>./Tests</directory>
26 </exclude>
27 </whitelist>
28 </filter>
29</phpunit>