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'));