feature #26518 [Routing] Allow inline definition of requirements and defaults (nicolas-grekas)
This PR was merged into the 4.1-dev branch.
Discussion
----------
[Routing] Allow inline definition of requirements and defaults
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #26481
| License | MIT
| Doc PR | -
```
{bar} -- no requirement, no default value
{bar<.*>} -- with requirement, no default value
{bar?default_value} -- no requirement, with default value
{bar<.*>?default_value} -- with requirement and default value
{bar?} -- no requirement, with default value of null
{bar<.*>?} -- with requirement and default value of null
```
Details:
* Requirements and default values are not escaped in any way. This is valid -> `@Route("/foo/{bar<>>?<>}")` (requirements = `>` and default value = `<>`)
* Because of the lack of escaping, you can't use a closing brace (`}`) inside the default value (wrong -> `@Route("/foo/{bar<\d+>?aa}bb}")`) but you can use it inside requirements (correct -> `@Route("/foo/{bar<\d{3}>}")`).
* PHP constants are not supported (use the traditional `defaults` syntax for that)
* ...
Commits
-------
67559e1
[Routing] Allow inline definition of requirements and defaults
This commit is contained in:
commit
0f9246fcfe
@ -53,8 +53,8 @@ class Route implements \Serializable
|
||||
public function __construct(string $path, array $defaults = array(), array $requirements = array(), array $options = array(), ?string $host = '', $schemes = array(), $methods = array(), ?string $condition = '')
|
||||
{
|
||||
$this->setPath($path);
|
||||
$this->setDefaults($defaults);
|
||||
$this->setRequirements($requirements);
|
||||
$this->addDefaults($defaults);
|
||||
$this->addRequirements($requirements);
|
||||
$this->setOptions($options);
|
||||
$this->setHost($host);
|
||||
$this->setSchemes($schemes);
|
||||
@ -123,6 +123,19 @@ class Route implements \Serializable
|
||||
*/
|
||||
public function setPath($pattern)
|
||||
{
|
||||
if (false !== strpbrk($pattern, '?<')) {
|
||||
$pattern = preg_replace_callback('#\{(\w++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) {
|
||||
if (isset($m[3][0])) {
|
||||
$this->setDefault($m[1], '?' !== $m[3] ? substr($m[3], 1) : null);
|
||||
}
|
||||
if (isset($m[2][0])) {
|
||||
$this->setRequirement($m[1], substr($m[2], 1, -1));
|
||||
}
|
||||
|
||||
return '{'.$m[1].'}';
|
||||
}, $pattern);
|
||||
}
|
||||
|
||||
// A pattern must start with a slash and must not have multiple slashes at the beginning because the
|
||||
// generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
|
||||
$this->path = '/'.ltrim(trim($pattern), '/');
|
||||
|
@ -203,6 +203,22 @@ class RouteTest extends TestCase
|
||||
$this->assertNotSame($route, $unserialized);
|
||||
}
|
||||
|
||||
public function testInlineDefaultAndRequirement()
|
||||
{
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null), new Route('/foo/{bar?}'));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}'));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz<buz>'), new Route('/foo/{bar?baz<buz>}'));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?}', array('bar' => 'baz')));
|
||||
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>}'));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '>'), new Route('/foo/{bar<>>}'));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{bar<.*>}', array(), array('bar' => '\d+')));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '[a-z]{2}'), new Route('/foo/{bar<[a-z]{2}>}'));
|
||||
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null)->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>?}'));
|
||||
$this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', '<>')->setRequirement('bar', '>'), new Route('/foo/{bar<>>?<>}'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the compiled version is also serialized to prevent the overhead
|
||||
* of compiling it again after unserialize.
|
||||
|
Reference in New Issue
Block a user