From 2da68bae8f3e819b0cc91fb68ea243affdfae218 Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Wed, 19 Feb 2020 05:20:56 +0100 Subject: [PATCH] [Routing] Add stateless route attribute --- src/Symfony/Component/Routing/Annotation/Route.php | 5 +++++ src/Symfony/Component/Routing/CHANGELOG.md | 1 + .../Loader/Configurator/Traits/RouteTrait.php | 12 ++++++++++++ .../Component/Routing/Loader/XmlFileLoader.php | 10 +++++++++- .../Component/Routing/Loader/YamlFileLoader.php | 12 ++++++++++-- .../Routing/Loader/schema/routing/routing-1.0.xsd | 2 ++ .../Component/Routing/Tests/Fixtures/defaults.php | 1 + .../Component/Routing/Tests/Fixtures/defaults.xml | 2 +- .../Component/Routing/Tests/Fixtures/defaults.yml | 1 + .../Tests/Fixtures/importer-with-defaults.php | 1 + .../Tests/Fixtures/importer-with-defaults.xml | 3 ++- .../Tests/Fixtures/importer-with-defaults.yml | 1 + .../Component/Routing/Tests/Fixtures/php_dsl.php | 3 ++- .../Routing/Tests/Fixtures/php_object_dsl.php | 3 ++- .../Routing/Tests/Fixtures/validpattern.php | 2 +- .../Routing/Tests/Fixtures/validpattern.xml | 3 +++ .../Routing/Tests/Fixtures/validpattern.yml | 2 +- .../Routing/Tests/Loader/PhpFileLoaderTest.php | 5 ++++- .../Routing/Tests/Loader/XmlFileLoaderTest.php | 4 ++++ .../Routing/Tests/Loader/YamlFileLoaderTest.php | 4 ++++ 20 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Routing/Annotation/Route.php b/src/Symfony/Component/Routing/Annotation/Route.php index 0cecfeaec1..3b7d964072 100644 --- a/src/Symfony/Component/Routing/Annotation/Route.php +++ b/src/Symfony/Component/Routing/Annotation/Route.php @@ -72,6 +72,11 @@ class Route unset($data['utf8']); } + if (isset($data['stateless'])) { + $data['defaults']['_stateless'] = filter_var($data['stateless'], FILTER_VALIDATE_BOOLEAN) ?: false; + unset($data['stateless']); + } + foreach ($data as $key => $value) { $method = 'set'.str_replace('_', '', $key); if (!method_exists($this, $method)) { diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 23d32c3242..b0f2f0e8d2 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -10,6 +10,7 @@ CHANGELOG * added argument `$priority` to `RouteCollection::add()` * deprecated the `RouteCompiler::REGEX_DELIMITER` constant * added `ExpressionLanguageProvider` to expose extra functions to route conditions + * added support for a `stateless` keyword for configuring route stateless in PHP, YAML and XML configurations. 5.0.0 ----- diff --git a/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php b/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php index d9e8e70250..acdffae33b 100644 --- a/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php +++ b/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php @@ -160,4 +160,16 @@ trait RouteTrait return $this; } + + /** + * Adds the "_stateless" entry to defaults. + * + * @return $this + */ + final public function stateless(bool $stateless = true): self + { + $this->route->addDefaults(['_stateless' => $stateless]); + + return $this; + } } diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index 1690a83c96..100c1a0d72 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php @@ -17,7 +17,6 @@ use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait; use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait; use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\Routing\RouteCompiler; /** * XmlFileLoader loads XML routing files. @@ -300,6 +299,15 @@ class XmlFileLoader extends FileLoader if ($node->hasAttribute('utf8')) { $options['utf8'] = XmlUtils::phpize($node->getAttribute('utf8')); } + if ($stateless = $node->getAttribute('stateless')) { + if (isset($defaults['_stateless'])) { + $name = $node->hasAttribute('id') ? sprintf('"%s"', $node->getAttribute('id')) : sprintf('the "%s" tag', $node->tagName); + + throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" attribute and the defaults key "_stateless" for %s.', $path, $name)); + } + + $defaults['_stateless'] = XmlUtils::phpize($stateless); + } return [$defaults, $requirements, $options, $condition, $paths, $prefixes]; } diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php index 6f0b31a6cb..b0718f6838 100644 --- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php @@ -16,7 +16,6 @@ use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait; use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait; use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\Routing\RouteCompiler; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Parser as YamlParser; use Symfony\Component\Yaml\Yaml; @@ -33,7 +32,7 @@ class YamlFileLoader extends FileLoader use PrefixTrait; private static $availableKeys = [ - 'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude', + 'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude', 'stateless', ]; private $yamlParser; @@ -134,6 +133,9 @@ class YamlFileLoader extends FileLoader if (isset($config['utf8'])) { $options['utf8'] = $config['utf8']; } + if (isset($config['stateless'])) { + $defaults['_stateless'] = $config['stateless']; + } $route = $this->createLocalizedRoute($collection, $name, $config['path']); $route->addDefaults($defaults); @@ -179,6 +181,9 @@ class YamlFileLoader extends FileLoader if (isset($config['utf8'])) { $options['utf8'] = $config['utf8']; } + if (isset($config['stateless'])) { + $defaults['_stateless'] = $config['stateless']; + } $this->setCurrentDir(\dirname($path)); @@ -245,5 +250,8 @@ class YamlFileLoader extends FileLoader if (isset($config['controller']) && isset($config['defaults']['_controller'])) { throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name)); } + if (isset($config['stateless']) && isset($config['defaults']['_stateless'])) { + throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name)); + } } } diff --git a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd index 8e61d03e9a..423aa7979e 100644 --- a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd +++ b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd @@ -55,6 +55,7 @@ + @@ -76,6 +77,7 @@ + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.php b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.php index 200b568b17..a2262bbb3d 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.php @@ -6,5 +6,6 @@ return function (RoutingConfigurator $routes) { $routes->add('defaults', '/defaults') ->locale('en') ->format('html') + ->stateless(true) ; }; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml index dfa9153a86..bd30c24604 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml @@ -4,5 +4,5 @@ xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd"> - + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml index a563ae084b..cc842eeae5 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml @@ -2,3 +2,4 @@ defaults: path: /defaults locale: en format: html + stateless: true diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php index 6ac9d69e62..55aa67a658 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php @@ -7,5 +7,6 @@ return function (RoutingConfigurator $routes) { ->prefix('/defaults') ->locale('g_locale') ->format('g_format') + ->stateless(true) ; }; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml index bdd25318d5..f910690426 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml @@ -6,5 +6,6 @@ + format="g_format" + stateless="true" /> diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml index 2e7d590021..b0c08b18ff 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml @@ -3,3 +3,4 @@ defaults: prefix: /defaults locale: g_locale format: g_format + stateless: true diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php b/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php index 86caa99696..e4a1dc618c 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php @@ -9,7 +9,8 @@ return function (RoutingConfigurator $routes) { ->condition('abc') ->options(['utf8' => true]) ->add('buz', 'zub') - ->controller('foo:act'); + ->controller('foo:act') + ->stateless(true); $routes->import('php_dsl_sub.php') ->prefix('/sub') diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php b/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php index 9b9183a1b9..c2410831af 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/php_object_dsl.php @@ -11,7 +11,8 @@ return new class() { ->condition('abc') ->options(['utf8' => true]) ->add('buz', 'zub') - ->controller('foo:act'); + ->controller('foo:act') + ->stateless(true); $routes->import('php_dsl_sub.php') ->prefix('/sub') diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php index 3ef0e14862..1deb043910 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.php @@ -6,7 +6,7 @@ use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection(); $collection->add('blog_show', new Route( '/blog/{slug}', - ['_controller' => 'MyBlogBundle:Blog:show'], + ['_controller' => 'MyBlogBundle:Blog:show', '_stateless' => true], ['locale' => '\w+'], ['compiler_class' => 'RouteCompiler'], '{locale}.example.com', diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml index 93e59d62a7..5c6f88ab43 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml @@ -6,6 +6,9 @@ MyBundle:Blog:show + + true + \w+ context.getMethod() == "GET" diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml index 565abaaa2c..0faac8a4db 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validpattern.yml @@ -1,6 +1,6 @@ blog_show: path: /blog/{slug} - defaults: { _controller: "MyBundle:Blog:show" } + defaults: { _controller: "MyBundle:Blog:show", _stateless: true } host: "{locale}.example.com" requirements: { 'locale': '\w+' } methods: ['GET','POST','put','OpTiOnS'] diff --git a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php index 789848c660..ffde004ade 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php @@ -43,6 +43,7 @@ class PhpFileLoaderTest extends TestCase foreach ($routes as $route) { $this->assertSame('/blog/{slug}', $route->getPath()); $this->assertSame('MyBlogBundle:Blog:show', $route->getDefault('_controller')); + $this->assertTrue($route->getDefault('_stateless')); $this->assertSame('{locale}.example.com', $route->getHost()); $this->assertSame('RouteCompiler', $route->getOption('compiler_class')); $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); @@ -109,9 +110,11 @@ class PhpFileLoaderTest extends TestCase $expectedRoutes->add('one', $localeRoute = new Route('/defaults/one')); $localeRoute->setDefault('_locale', 'g_locale'); $localeRoute->setDefault('_format', 'g_format'); + $localeRoute->setDefault('_stateless', true); $expectedRoutes->add('two', $formatRoute = new Route('/defaults/two')); $formatRoute->setDefault('_locale', 'g_locale'); $formatRoute->setDefault('_format', 'g_format'); + $formatRoute->setDefault('_stateless', true); $formatRoute->setDefault('specific', 'imported'); $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/imported-with-defaults.php')); @@ -172,7 +175,7 @@ class PhpFileLoaderTest extends TestCase ->setCondition('abc') ); $expectedCollection->add('buz', (new Route('/zub')) - ->setDefaults(['_controller' => 'foo:act']) + ->setDefaults(['_controller' => 'foo:act', '_stateless' => true]) ); $expectedCollection->add('c_root', (new Route('/sub/pub/')) ->setRequirements(['id' => '\d+']) diff --git a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php index 66d54fc985..8453d546a0 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php @@ -47,6 +47,7 @@ class XmlFileLoaderTest extends TestCase $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); $this->assertEquals(['https'], $route->getSchemes()); $this->assertEquals('context.getMethod() == "GET"', $route->getCondition()); + $this->assertTrue($route->getDefault('_stateless')); } public function testLoadWithNamespacePrefix() @@ -98,6 +99,7 @@ class XmlFileLoaderTest extends TestCase $this->assertSame('/defaults', $defaultsRoute->getPath()); $this->assertSame('en', $defaultsRoute->getDefault('_locale')); $this->assertSame('html', $defaultsRoute->getDefault('_format')); + $this->assertTrue($defaultsRoute->getDefault('_stateless')); } public function testLoadingImportedRoutesWithDefaults() @@ -111,9 +113,11 @@ class XmlFileLoaderTest extends TestCase $expectedRoutes->add('one', $localeRoute = new Route('/defaults/one')); $localeRoute->setDefault('_locale', 'g_locale'); $localeRoute->setDefault('_format', 'g_format'); + $localeRoute->setDefault('_stateless', true); $expectedRoutes->add('two', $formatRoute = new Route('/defaults/two')); $formatRoute->setDefault('_locale', 'g_locale'); $formatRoute->setDefault('_format', 'g_format'); + $formatRoute->setDefault('_stateless', true); $formatRoute->setDefault('specific', 'imported'); $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/imported-with-defaults.xml')); diff --git a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php index 301908d88d..005093bafd 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php @@ -90,6 +90,7 @@ class YamlFileLoaderTest extends TestCase $this->assertEquals(['GET', 'POST', 'PUT', 'OPTIONS'], $route->getMethods()); $this->assertEquals(['https'], $route->getSchemes()); $this->assertEquals('context.getMethod() == "GET"', $route->getCondition()); + $this->assertTrue($route->getDefault('_stateless')); } public function testLoadWithResource() @@ -232,6 +233,7 @@ class YamlFileLoaderTest extends TestCase $this->assertSame('/defaults', $defaultsRoute->getPath()); $this->assertSame('en', $defaultsRoute->getDefault('_locale')); $this->assertSame('html', $defaultsRoute->getDefault('_format')); + $this->assertTrue($defaultsRoute->getDefault('_stateless')); } public function testLoadingImportedRoutesWithDefaults() @@ -245,9 +247,11 @@ class YamlFileLoaderTest extends TestCase $expectedRoutes->add('one', $localeRoute = new Route('/defaults/one')); $localeRoute->setDefault('_locale', 'g_locale'); $localeRoute->setDefault('_format', 'g_format'); + $localeRoute->setDefault('_stateless', true); $expectedRoutes->add('two', $formatRoute = new Route('/defaults/two')); $formatRoute->setDefault('_locale', 'g_locale'); $formatRoute->setDefault('_format', 'g_format'); + $formatRoute->setDefault('_stateless', true); $formatRoute->setDefault('specific', 'imported'); $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/imported-with-defaults.yml'));