Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 392747c

Browse filesBrowse files
[Routing] allow no-slash root on imported routes
1 parent a38cbd0 commit 392747c
Copy full SHA for 392747c

File tree

9 files changed

+41
-10
lines changed
Filter options

9 files changed

+41
-10
lines changed

‎src/Symfony/Component/Routing/Annotation/Route.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Annotation/Route.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Route
3838
*/
3939
public function __construct(array $data)
4040
{
41-
if (isset($data['value'])) {
41+
if (array_key_exists('value', $data)) {
4242
$data['path'] = $data['value'];
4343
unset($data['value']);
4444
}

‎src/Symfony/Component/Routing/Loader/XmlFileLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ protected function parseRoute(RouteCollection $collection, \DOMElement $node, $p
115115
$methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
116116

117117
list($defaults, $requirements, $options, $condition) = $this->parseConfigs($node, $path);
118+
$path = $node->getAttribute('path');
118119

119-
$route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods, $condition);
120+
$route = new Route('null' !== $path ? $path : null, $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods, $condition);
120121
$collection->add($id, $route);
121122
}
122123

‎src/Symfony/Component/Routing/Loader/YamlFileLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/YamlFileLoader.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ protected function validate($config, $name, $path)
198198
$path, $name, implode('", "', $extraKeys), implode('", "', self::$availableKeys)
199199
));
200200
}
201-
if (isset($config['resource']) && isset($config['path'])) {
201+
if (isset($config['resource']) && array_key_exists('path', $config)) {
202202
throw new \InvalidArgumentException(sprintf(
203203
'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.',
204204
$path, $name
@@ -210,7 +210,7 @@ protected function validate($config, $name, $path)
210210
$name, $path
211211
));
212212
}
213-
if (!isset($config['resource']) && !isset($config['path'])) {
213+
if (!isset($config['resource']) && !array_key_exists('path', $config)) {
214214
throw new \InvalidArgumentException(sprintf(
215215
'You must define a "path" for the route "%s" in file "%s".',
216216
$name, $path

‎src/Symfony/Component/Routing/Route.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Route.php
+10-5Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class Route implements \Serializable
4141
* * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
4242
* * utf8: Whether UTF-8 matching is enforced ot not
4343
*
44-
* @param string $path The path pattern to match
44+
* @param string|null $path The path pattern to match, or null to declare a trailing-slash-less root of a collection
4545
* @param array $defaults An array of default parameter values
4646
* @param array $requirements An array of requirements for parameters (regexes)
4747
* @param array $options An array of options
@@ -50,7 +50,7 @@ class Route implements \Serializable
5050
* @param string|string[] $methods A required HTTP method or an array of restricted methods
5151
* @param string $condition A condition that should evaluate to true for the route to match
5252
*/
53-
public function __construct(string $path, array $defaults = array(), array $requirements = array(), array $options = array(), ?string $host = '', $schemes = array(), $methods = array(), ?string $condition = '')
53+
public function __construct(?string $path, array $defaults = array(), array $requirements = array(), array $options = array(), ?string $host = '', $schemes = array(), $methods = array(), ?string $condition = '')
5454
{
5555
$this->setPath($path);
5656
$this->setDefaults($defaults);
@@ -109,28 +109,33 @@ public function unserialize($serialized)
109109
*/
110110
public function getPath()
111111
{
112-
return $this->path;
112+
return null === $this->path ? '/' : $this->path;
113113
}
114114

115115
/**
116116
* Sets the pattern for the path.
117117
*
118118
* This method implements a fluent interface.
119119
*
120-
* @param string $pattern The path pattern
120+
* @param string|null $pattern The path pattern
121121
*
122122
* @return $this
123123
*/
124124
public function setPath($pattern)
125125
{
126126
// A pattern must start with a slash and must not have multiple slashes at the beginning because the
127127
// generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
128-
$this->path = '/'.ltrim(trim($pattern), '/');
128+
$this->path = null !== $pattern ? '/'.ltrim(trim($pattern), '/') : null;
129129
$this->compiled = null;
130130

131131
return $this;
132132
}
133133

134+
public function hasTrailingSlash(): bool
135+
{
136+
return null !== $this->path && '/' === $this->path[-1];
137+
}
138+
134139
/**
135140
* Returns the pattern for the host.
136141
*

‎src/Symfony/Component/Routing/RouteCollection.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/RouteCollection.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public function addPrefix($prefix, array $defaults = array(), array $requirement
147147
}
148148

149149
foreach ($this->routes as $route) {
150-
$route->setPath('/'.$prefix.$route->getPath());
150+
$route->setPath('/'.$prefix.(!$route->hasTrailingSlash() && '/' === $route->getPath() ? '' : $route->getPath()));
151151
$route->addDefaults($defaults);
152152
$route->addRequirements($requirements);
153153
}

‎src/Symfony/Component/Routing/Tests/Fixtures/controller/routing.xml

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/controller/routing.xml
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
<route id="app_homepage" path="/" controller="AppBundle:Homepage:show" />
88

9+
<route id="app_homepage_no_slash" path="null" />
10+
911
<route id="app_blog" path="/blog">
1012
<default key="_controller">AppBundle:Blog:list</default>
1113
</route>

‎src/Symfony/Component/Routing/Tests/Fixtures/controller/routing.yml

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/controller/routing.yml
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ app_homepage:
22
path: /
33
controller: AppBundle:Homepage:show
44

5+
app_homepage_no_slash:
6+
path: ~
7+
58
app_blog:
69
path: /blog
710
defaults:

‎src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,10 @@ public function testLoadRouteWithControllerAttribute()
296296
$route = $routeCollection->get('app_homepage');
297297

298298
$this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller'));
299+
300+
$route = $routeCollection->get('app_homepage_no_slash');
301+
302+
$this->assertSame('/', $route->getPath());
299303
}
300304

301305
public function testLoadRouteWithoutControllerAttribute()
@@ -371,5 +375,11 @@ public function testImportRouteWithNamePrefix()
371375
$this->assertEquals('/blog', $routeCollection->get('app_blog')->getPath());
372376
$this->assertNotNull($routeCollection->get('api_app_blog'));
373377
$this->assertEquals('/api/blog', $routeCollection->get('api_app_blog')->getPath());
378+
379+
$route = $routeCollection->get('api_app_homepage');
380+
$this->assertSame('/api/', $route->getPath());
381+
382+
$route = $routeCollection->get('api_app_homepage_no_slash');
383+
$this->assertSame('/api', $route->getPath());
374384
}
375385
}

‎src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ public function testLoadRouteWithControllerAttribute()
117117
$route = $routeCollection->get('app_homepage');
118118

119119
$this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller'));
120+
121+
$route = $routeCollection->get('app_homepage_no_slash');
122+
123+
$this->assertSame('/', $route->getPath());
120124
}
121125

122126
public function testLoadRouteWithoutControllerAttribute()
@@ -192,5 +196,11 @@ public function testImportRouteWithNamePrefix()
192196
$this->assertEquals('/blog', $routeCollection->get('app_blog')->getPath());
193197
$this->assertNotNull($routeCollection->get('api_app_blog'));
194198
$this->assertEquals('/api/blog', $routeCollection->get('api_app_blog')->getPath());
199+
200+
$route = $routeCollection->get('api_app_homepage');
201+
$this->assertSame('/api/', $route->getPath());
202+
203+
$route = $routeCollection->get('api_app_homepage_no_slash');
204+
$this->assertSame('/api', $route->getPath());
195205
}
196206
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.