Skip to content

Commit

Permalink
[Routing] Add stateless route attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
mtarld committed Feb 26, 2020
1 parent 7995fed commit 2da68ba
Show file tree
Hide file tree
Showing 20 changed files with 67 additions and 10 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/Routing/Annotation/Route.php
Expand Up @@ -72,6 +72,11 @@ public function __construct(array $data)
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)) {
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Routing/CHANGELOG.md
Expand Up @@ -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
-----
Expand Down
Expand Up @@ -160,4 +160,16 @@ final public function format(string $format): self

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;
}
}
10 changes: 9 additions & 1 deletion src/Symfony/Component/Routing/Loader/XmlFileLoader.php
Expand Up @@ -17,7 +17,6 @@
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.
Expand Down Expand Up @@ -300,6 +299,15 @@ private function parseConfigs(\DOMElement $node, string $path): array
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];
}
Expand Down
12 changes: 10 additions & 2 deletions src/Symfony/Component/Routing/Loader/YamlFileLoader.php
Expand Up @@ -16,7 +16,6 @@
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;
Expand All @@ -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;

Expand Down Expand Up @@ -134,6 +133,9 @@ protected function parseRoute(RouteCollection $collection, string $name, array $
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);
Expand Down Expand Up @@ -179,6 +181,9 @@ protected function parseImport(RouteCollection $collection, array $config, strin
if (isset($config['utf8'])) {
$options['utf8'] = $config['utf8'];
}
if (isset($config['stateless'])) {
$defaults['_stateless'] = $config['stateless'];
}

$this->setCurrentDir(\dirname($path));

Expand Down Expand Up @@ -245,5 +250,8 @@ protected function validate($config, string $name, string $path)
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));
}
}
}
Expand Up @@ -55,6 +55,7 @@
<xsd:attribute name="locale" type="xsd:string" />
<xsd:attribute name="format" type="xsd:string" />
<xsd:attribute name="utf8" type="xsd:boolean" />
<xsd:attribute name="stateless" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="import">
Expand All @@ -76,6 +77,7 @@
<xsd:attribute name="format" type="xsd:string" />
<xsd:attribute name="trailing-slash-on-root" type="xsd:boolean" />
<xsd:attribute name="utf8" type="xsd:boolean" />
<xsd:attribute name="stateless" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="default" mixed="true">
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Routing/Tests/Fixtures/defaults.php
Expand Up @@ -6,5 +6,6 @@
$routes->add('defaults', '/defaults')
->locale('en')
->format('html')
->stateless(true)
;
};
2 changes: 1 addition & 1 deletion src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml
Expand Up @@ -4,5 +4,5 @@
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">

<route id="defaults" path="/defaults" locale="en" format="html" />
<route id="defaults" path="/defaults" locale="en" format="html" stateless="true" />
</routes>
1 change: 1 addition & 0 deletions src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml
Expand Up @@ -2,3 +2,4 @@ defaults:
path: /defaults
locale: en
format: html
stateless: true
Expand Up @@ -7,5 +7,6 @@
->prefix('/defaults')
->locale('g_locale')
->format('g_format')
->stateless(true)
;
};
Expand Up @@ -6,5 +6,6 @@

<import resource="imported-with-defaults.xml" prefix="/defaults"
locale="g_locale"
format="g_format" />
format="g_format"
stateless="true" />
</routes>
Expand Up @@ -3,3 +3,4 @@ defaults:
prefix: /defaults
locale: g_locale
format: g_format
stateless: true
3 changes: 2 additions & 1 deletion src/Symfony/Component/Routing/Tests/Fixtures/php_dsl.php
Expand Up @@ -9,7 +9,8 @@
->condition('abc')
->options(['utf8' => true])
->add('buz', 'zub')
->controller('foo:act');
->controller('foo:act')
->stateless(true);

$routes->import('php_dsl_sub.php')
->prefix('/sub')
Expand Down
Expand Up @@ -11,7 +11,8 @@ public function __invoke(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')
Expand Down
Expand Up @@ -6,7 +6,7 @@
$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',
Expand Down
3 changes: 3 additions & 0 deletions src/Symfony/Component/Routing/Tests/Fixtures/validpattern.xml
Expand Up @@ -6,6 +6,9 @@

<route id="blog_show" path="/blog/{slug}" host="{locale}.example.com" methods="GET|POST put,OpTiOnS" schemes="hTTps">
<default key="_controller">MyBundle:Blog:show</default>
<default key="_stateless">
<bool>true</bool>
</default>
<requirement key="locale">\w+</requirement>
<option key="compiler_class">RouteCompiler</option>
<condition>context.getMethod() == "GET"</condition>
Expand Down
@@ -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']
Expand Down
Expand Up @@ -43,6 +43,7 @@ public function testLoadWithRoute()
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());
Expand Down Expand Up @@ -109,9 +110,11 @@ public function testLoadingImportedRoutesWithDefaults()
$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'));
Expand Down Expand Up @@ -172,7 +175,7 @@ public function testRoutingConfigurator()
->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+'])
Expand Down
Expand Up @@ -47,6 +47,7 @@ public function testLoadWithRoute()
$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()
Expand Down Expand Up @@ -98,6 +99,7 @@ public function testLoadingRouteWithDefaults()
$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()
Expand All @@ -111,9 +113,11 @@ public function testLoadingImportedRoutesWithDefaults()
$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'));
Expand Down
Expand Up @@ -90,6 +90,7 @@ public function testLoadWithRoute()
$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()
Expand Down Expand Up @@ -232,6 +233,7 @@ public function testLoadingRouteWithDefaults()
$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()
Expand All @@ -245,9 +247,11 @@ public function testLoadingImportedRoutesWithDefaults()
$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'));
Expand Down

0 comments on commit 2da68ba

Please sign in to comment.