Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1245272

Browse files
[Routing] allow no-slash root on imported routes
1 parent 0f9246f commit 1245272

File tree

12 files changed

+95
-9
lines changed

12 files changed

+95
-9
lines changed

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

Lines 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

Lines 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

Lines 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

Lines 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">
Lines 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>
Lines 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

Lines 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

Lines 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_')
Lines 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

Lines 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

Lines 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

Lines 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)