Skip to content

Navigation Menu

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 1245272

Browse filesBrowse files
[Routing] allow no-slash root on imported routes
1 parent 0f9246f commit 1245272
Copy full SHA for 1245272

File tree

12 files changed

+95
-9
lines changed
Filter options

12 files changed

+95
-9
lines changed

‎src/Symfony/Component/Routing/Loader/Configurator/ImportConfigurator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/Configurator/ImportConfigurator.php
+12-3Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Routing\Loader\Configurator;
1313

14+
use Symfony\Component\Routing\Route;
1415
use Symfony\Component\Routing\RouteCollection;
1516

1617
/**
@@ -40,7 +41,7 @@ public function __destruct()
4041
*
4142
* @return $this
4243
*/
43-
final public function prefix($prefix, string $namePrefix = '')
44+
final public function prefix($prefix, string $namePrefix = '', bool $trailingSlashOnRoot = true)
4445
{
4546
if ('' !== $namePrefix) {
4647
$this->route->addNamePrefix($namePrefix);
@@ -50,6 +51,14 @@ final public function prefix($prefix, string $namePrefix = '')
5051
}
5152
if (!\is_array($prefix)) {
5253
$this->route->addPrefix($prefix);
54+
if (!$trailingSlashOnRoot) {
55+
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
56+
foreach ($this->route->all() as $route) {
57+
if ($route->getPath() === $rootPath) {
58+
$route->setPath(rtrim($rootPath, '/'));
59+
}
60+
}
61+
}
5362
} else {
5463
foreach ($prefix as $locale => $localePrefix) {
5564
$prefix[$locale] = trim(trim($localePrefix), '/');
@@ -61,13 +70,13 @@ final public function prefix($prefix, string $namePrefix = '')
6170
$localizedRoute = clone $route;
6271
$localizedRoute->setDefault('_locale', $locale);
6372
$localizedRoute->setDefault('_canonical_route', $name);
64-
$localizedRoute->setPath($localePrefix.$route->getPath());
73+
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
6574
$this->route->add($name.'.'.$locale, $localizedRoute);
6675
}
6776
} elseif (!isset($prefix[$locale])) {
6877
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
6978
} else {
70-
$route->setPath($prefix[$locale].$route->getPath());
79+
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
7180
$this->route->add($name, $route);
7281
}
7382
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+11-2Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, $
158158
$host = $node->hasAttribute('host') ? $node->getAttribute('host') : null;
159159
$schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
160160
$methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
161+
$trailingSlashOnRoot = $node->hasAttribute('trailing-slash-on-root') ? XmlUtils::phpize($node->getAttribute('trailing-slash-on-root')) : true;
161162

162163
list($defaults, $requirements, $options, $condition, /* $paths */, $prefixes) = $this->parseConfigs($node, $path);
163164

@@ -172,6 +173,14 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, $
172173

173174
if ('' !== $prefix || !$prefixes) {
174175
$subCollection->addPrefix($prefix);
176+
if (!$trailingSlashOnRoot) {
177+
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
178+
foreach ($subCollection->all() as $route) {
179+
if ($route->getPath() === $rootPath) {
180+
$route->setPath(rtrim($rootPath, '/'));
181+
}
182+
}
183+
}
175184
} else {
176185
foreach ($prefixes as $locale => $localePrefix) {
177186
$prefixes[$locale] = trim(trim($localePrefix), '/');
@@ -181,15 +190,15 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, $
181190
$subCollection->remove($name);
182191
foreach ($prefixes as $locale => $localePrefix) {
183192
$localizedRoute = clone $route;
184-
$localizedRoute->setPath($localePrefix.$route->getPath());
193+
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
185194
$localizedRoute->setDefault('_locale', $locale);
186195
$localizedRoute->setDefault('_canonical_route', $name);
187196
$subCollection->add($name.'.'.$locale, $localizedRoute);
188197
}
189198
} elseif (!isset($prefixes[$locale])) {
190199
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix when imported in "%s".', $name, $locale, $path));
191200
} else {
192-
$route->setPath($prefixes[$locale].$route->getPath());
201+
$route->setPath($prefixes[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
193202
$subCollection->add($name, $route);
194203
}
195204
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/YamlFileLoader.php
+12-3Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
class YamlFileLoader extends FileLoader
2929
{
3030
private static $availableKeys = array(
31-
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix',
31+
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root',
3232
);
3333
private $yamlParser;
3434

@@ -155,6 +155,7 @@ protected function parseImport(RouteCollection $collection, array $config, $path
155155
$condition = isset($config['condition']) ? $config['condition'] : null;
156156
$schemes = isset($config['schemes']) ? $config['schemes'] : null;
157157
$methods = isset($config['methods']) ? $config['methods'] : null;
158+
$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;
158159

159160
if (isset($config['controller'])) {
160161
$defaults['_controller'] = $config['controller'];
@@ -167,6 +168,14 @@ protected function parseImport(RouteCollection $collection, array $config, $path
167168

168169
if (!\is_array($prefix)) {
169170
$subCollection->addPrefix($prefix);
171+
if (!$trailingSlashOnRoot) {
172+
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
173+
foreach ($subCollection->all() as $route) {
174+
if ($route->getPath() === $rootPath) {
175+
$route->setPath(rtrim($rootPath, '/'));
176+
}
177+
}
178+
}
170179
} else {
171180
foreach ($prefix as $locale => $localePrefix) {
172181
$prefix[$locale] = trim(trim($localePrefix), '/');
@@ -178,13 +187,13 @@ protected function parseImport(RouteCollection $collection, array $config, $path
178187
$localizedRoute = clone $route;
179188
$localizedRoute->setDefault('_locale', $locale);
180189
$localizedRoute->setDefault('_canonical_route', $name);
181-
$localizedRoute->setPath($localePrefix.$route->getPath());
190+
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
182191
$subCollection->add($name.'.'.$locale, $localizedRoute);
183192
}
184193
} elseif (!isset($prefix[$locale])) {
185194
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix when imported in "%s".', $name, $locale, $file));
186195
} else {
187-
$route->setPath($prefix[$locale].$route->getPath());
196+
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
188197
$subCollection->add($name, $route);
189198
}
190199
}

‎src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
<xsd:attribute name="schemes" type="xsd:string" />
6868
<xsd:attribute name="methods" type="xsd:string" />
6969
<xsd:attribute name="controller" type="xsd:string" />
70+
<xsd:attribute name="trailing-slash-on-root" type="xsd:boolean" />
7071
</xsd:complexType>
7172

7273
<xsd:complexType name="default" mixed="true">
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<routes xmlns="http://symfony.com/schema/routing"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/routing
5+
http://symfony.com/schema/routing/routing-1.0.xsd">
6+
7+
<import resource="../controller/routing.xml" prefix="/slash" name-prefix="a_" />
8+
<import resource="../controller/routing.xml" prefix="/no-slash" name-prefix="b_" trailing-slash-on-root="false" />
9+
10+
</routes>
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
app:
2+
resource: ../controller/routing.yml
3+
name_prefix: a_
4+
prefix: /slash
5+
6+
api:
7+
resource: ../controller/routing.yml
8+
name_prefix: b_
9+
prefix: /no-slash
10+
trailing_slash_on_root: false

‎src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
$routes->import('php_dsl_sub.php')
1919
->prefix('/zub', 'z_');
2020

21+
$routes->import('php_dsl_sub_root.php')
22+
->prefix('/bus', '', false);
23+
2124
$routes->add('ouf', '/ouf')
2225
->schemes(array('https'))
2326
->methods(array('GET'))

‎src/Symfony/Component/Routing/Tests/Fixtures/php_dsl_sub.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/php_dsl_sub.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
$add = $routes->collection('c_')
77
->prefix('pub');
88

9+
$add('root', '/');
910
$add('bar', '/bar');
1011

1112
$add->collection('pub_')
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Component\Routing\Loader\Configurator;
4+
5+
return function (RoutingConfigurator $routes) {
6+
$add = $routes->collection('r_');
7+
8+
$add('root', '/');
9+
$add('bar', '/bar/');
10+
};

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,29 @@ public function testRoutingConfigurator()
9999
$expectedCollection->add('buz', (new Route('/zub'))
100100
->setDefaults(array('_controller' => 'foo:act'))
101101
);
102+
$expectedCollection->add('c_root', (new Route('/sub/pub/'))
103+
->setRequirements(array('id' => '\d+'))
104+
);
102105
$expectedCollection->add('c_bar', (new Route('/sub/pub/bar'))
103106
->setRequirements(array('id' => '\d+'))
104107
);
105108
$expectedCollection->add('c_pub_buz', (new Route('/sub/pub/buz'))
106109
->setHost('host')
107110
->setRequirements(array('id' => '\d+'))
108111
);
112+
$expectedCollection->add('z_c_root', new Route('/zub/pub/'));
109113
$expectedCollection->add('z_c_bar', new Route('/zub/pub/bar'));
110114
$expectedCollection->add('z_c_pub_buz', (new Route('/zub/pub/buz'))->setHost('host'));
115+
$expectedCollection->add('r_root', new Route('/bus'));
116+
$expectedCollection->add('r_bar', new Route('/bus/bar/'));
111117
$expectedCollection->add('ouf', (new Route('/ouf'))
112118
->setSchemes(array('https'))
113119
->setMethods(array('GET'))
114120
->setDefaults(array('id' => 0))
115121
);
116122

117123
$expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl_sub.php')));
124+
$expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl_sub_root.php')));
118125
$expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl.php')));
119126

120127
$this->assertEquals($expectedCollection, $routeCollection);

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,4 +411,13 @@ public function testImportRouteWithNamePrefix()
411411
$this->assertNotNull($routeCollection->get('api_app_blog'));
412412
$this->assertEquals('/api/blog', $routeCollection->get('api_app_blog')->getPath());
413413
}
414+
415+
public function testImportRouteWithNoTrailingSlash()
416+
{
417+
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/import_with_no_trailing_slash')));
418+
$routeCollection = $loader->load('routing.xml');
419+
420+
$this->assertEquals('/slash/', $routeCollection->get('a_app_homepage')->getPath());
421+
$this->assertEquals('/no-slash', $routeCollection->get('b_app_homepage')->getPath());
422+
}
414423
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ public function testLoadingLocalizedRoute()
209209
$this->assertCount(3, $routes);
210210
}
211211

212-
213212
public function testImportingRoutesFromDefinition()
214213
{
215214
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/localized')));
@@ -275,4 +274,13 @@ public function testImportingWithControllerDefault()
275274
$this->assertEquals('DefaultController::defaultAction', $routes->get('home.nl')->getDefault('_controller'));
276275
$this->assertEquals('DefaultController::defaultAction', $routes->get('not_localized')->getDefault('_controller'));
277276
}
277+
278+
public function testImportRouteWithNoTrailingSlash()
279+
{
280+
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/import_with_no_trailing_slash')));
281+
$routeCollection = $loader->load('routing.yml');
282+
283+
$this->assertEquals('/slash/', $routeCollection->get('a_app_homepage')->getPath());
284+
$this->assertEquals('/no-slash', $routeCollection->get('b_app_homepage')->getPath());
285+
}
278286
}

0 commit comments

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