From 2e1344eb7ef1e4a6c5cc21e098fd2a6404f2b289 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 23 Oct 2011 11:56:23 +0200 Subject: [PATCH] [Routing] added the possibility to define default values and requirements for placeholders in prefix --- CHANGELOG-2.1.md | 1 + .../Routing/Loader/XmlFileLoader.php | 23 +++++++++++++- .../Routing/Loader/YamlFileLoader.php | 5 +++- .../Loader/schema/routing/routing-1.0.xsd | 5 ++++ src/Symfony/Component/Routing/Route.php | 30 +++++++++++++++++++ .../Component/Routing/RouteCollection.php | 20 ++++++++----- .../Routing/Fixtures/validresource.xml | 5 +++- .../Routing/Fixtures/validresource.yml | 5 +++- .../Routing/Loader/XmlFileLoaderTest.php | 3 +- .../Routing/Loader/YamlFileLoaderTest.php | 2 ++ .../Component/Routing/RouteCollectionTest.php | 16 ++++++---- .../Tests/Component/Routing/RouteTest.php | 10 +++++++ 12 files changed, 108 insertions(+), 17 deletions(-) diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md index aef4f409e981..42f8d56475f3 100644 --- a/CHANGELOG-2.1.md +++ b/CHANGELOG-2.1.md @@ -79,6 +79,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c ### Routing + * added the possibility to define default values and requirements for placeholders in prefix * added RouterInterface::getRouteCollection ### Translation diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index eb96d2a2eecc..913deab43b94 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php @@ -76,8 +76,29 @@ protected function parseNode(RouteCollection $collection, \DOMElement $node, $pa $resource = (string) $node->getAttribute('resource'); $type = (string) $node->getAttribute('type'); $prefix = (string) $node->getAttribute('prefix'); + + $defaults = array(); + $requirements = array(); + + foreach ($node->childNodes as $n) { + if (!$n instanceof \DOMElement) { + continue; + } + + switch ($n->tagName) { + case 'default': + $defaults[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue); + break; + case 'requirement': + $requirements[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue); + break; + default: + throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $n->tagName)); + } + } + $this->setCurrentDir(dirname($path)); - $collection->addCollection($this->import($resource, ('' !== $type ? $type : null), false, $file), $prefix); + $collection->addCollection($this->import($resource, ('' !== $type ? $type : null), false, $file), $prefix, $defaults, $requirements); break; default: throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName)); diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php index 3ff11a5e6250..5d8f02a26828 100644 --- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php @@ -67,8 +67,11 @@ public function load($file, $type = null) if (isset($config['resource'])) { $type = isset($config['type']) ? $config['type'] : null; $prefix = isset($config['prefix']) ? $config['prefix'] : null; + $defaults = isset($config['defaults']) ? $config['defaults'] : array(); + $requirements = isset($config['requirements']) ? $config['requirements'] : array(); + $this->setCurrentDir(dirname($path)); - $collection->addCollection($this->import($config['resource'], $type, false, $file), $prefix); + $collection->addCollection($this->import($config['resource'], $type, false, $file), $prefix, $defaults, $requirements); } else { $this->parseRoute($collection, $name, $config, $path); } 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 a9554e64df3e..3b8fa3db9a4b 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 @@ -26,6 +26,11 @@ + + + + + diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 6069cdc466db..3492d71f76d7 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -162,6 +162,21 @@ public function getDefaults() public function setDefaults(array $defaults) { $this->defaults = array(); + + return $this->addDefaults($defaults); + } + + /** + * Adds defaults. + * + * This method implements a fluent interface. + * + * @param array $defaults The defaults + * + * @return Route The current Route instance + */ + public function addDefaults(array $defaults) + { foreach ($defaults as $name => $default) { $this->defaults[(string) $name] = $default; } @@ -232,6 +247,21 @@ public function getRequirements() public function setRequirements(array $requirements) { $this->requirements = array(); + + return $this->addRequirements($requirements); + } + + /** + * Adds requirements. + * + * This method implements a fluent interface. + * + * @param array $requirements The requirements + * + * @return Route The current Route instance + */ + public function addRequirements(array $requirements) + { foreach ($requirements as $key => $regex) { $this->requirements[$key] = $this->sanitizeRequirement($key, $regex); } diff --git a/src/Symfony/Component/Routing/RouteCollection.php b/src/Symfony/Component/Routing/RouteCollection.php index 47b75117340c..b29867736291 100644 --- a/src/Symfony/Component/Routing/RouteCollection.php +++ b/src/Symfony/Component/Routing/RouteCollection.php @@ -165,15 +165,17 @@ public function remove($name) /** * Adds a route collection to the current set of routes (at the end of the current set). * - * @param RouteCollection $collection A RouteCollection instance - * @param string $prefix An optional prefix to add before each pattern of the route collection + * @param RouteCollection $collection A RouteCollection instance + * @param string $prefix An optional prefix to add before each pattern of the route collection + * @param array $defaults An array of default values + * @param array $requirements An array of requirements * * @api */ - public function addCollection(RouteCollection $collection, $prefix = '') + public function addCollection(RouteCollection $collection, $prefix = '', $defaults = array(), $requirements = array()) { $collection->setParent($this); - $collection->addPrefix($prefix); + $collection->addPrefix($prefix, $defaults, $requirements); // remove all routes with the same name in all existing collections foreach (array_keys($collection->all()) as $name) { @@ -186,11 +188,13 @@ public function addCollection(RouteCollection $collection, $prefix = '') /** * Adds a prefix to all routes in the current set. * - * @param string $prefix An optional prefix to add before each pattern of the route collection + * @param string $prefix An optional prefix to add before each pattern of the route collection + * @param array $defaults An array of default values + * @param array $requirements An array of requirements * * @api */ - public function addPrefix($prefix) + public function addPrefix($prefix, $defaults = array(), $requirements = array()) { // a prefix must not end with a slash $prefix = rtrim($prefix, '/'); @@ -208,9 +212,11 @@ public function addPrefix($prefix) foreach ($this->routes as $name => $route) { if ($route instanceof RouteCollection) { - $route->addPrefix($prefix); + $route->addPrefix($prefix, $defaults, $requirements); } else { $route->setPattern($prefix.$route->getPattern()); + $route->addDefaults($defaults); + $route->addRequirements($requirements); } } } diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.xml b/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.xml index 80f11633accd..72856b81618c 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.xml +++ b/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.xml @@ -4,5 +4,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + + foo + \d+ + diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.yml b/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.yml index ec8bf91179ab..c36dea5c4f81 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.yml +++ b/tests/Symfony/Tests/Component/Routing/Fixtures/validresource.yml @@ -1,2 +1,5 @@ blog_show: - resource: validpattern.yml + resource: validpattern.yml + prefix: /{foo} + defaults: { 'foo': 'foo' } + requirements: { 'foo': '\d+' } diff --git a/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php b/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php index b0e082d43db8..100a16850e9f 100644 --- a/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php +++ b/tests/Symfony/Tests/Component/Routing/Loader/XmlFileLoaderTest.php @@ -51,6 +51,8 @@ public function testLoadWithImport() $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); + $this->assertEquals('foo', $routes['blog_show']->getDefault('foo')); + $this->assertEquals('\d+', $routes['blog_show']->getRequirement('foo')); } /** @@ -89,4 +91,3 @@ protected function validate(\DOMDocument $dom) return true; } } - diff --git a/tests/Symfony/Tests/Component/Routing/Loader/YamlFileLoaderTest.php b/tests/Symfony/Tests/Component/Routing/Loader/YamlFileLoaderTest.php index e68c263166c9..4278bca38357 100644 --- a/tests/Symfony/Tests/Component/Routing/Loader/YamlFileLoaderTest.php +++ b/tests/Symfony/Tests/Component/Routing/Loader/YamlFileLoaderTest.php @@ -88,6 +88,8 @@ public function testLoadWithResource() $this->assertEquals(1, count($routes), 'One route is loaded'); $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); + $this->assertEquals('foo', $routes['blog_show']->getDefault('foo')); + $this->assertEquals('\d+', $routes['blog_show']->getRequirement('foo')); } /** diff --git a/tests/Symfony/Tests/Component/Routing/RouteCollectionTest.php b/tests/Symfony/Tests/Component/Routing/RouteCollectionTest.php index f0569065c1ce..a57da3c7e1c2 100644 --- a/tests/Symfony/Tests/Component/Routing/RouteCollectionTest.php +++ b/tests/Symfony/Tests/Component/Routing/RouteCollectionTest.php @@ -103,8 +103,10 @@ public function testAddCollection() $collection->add('foo', $foo = new Route('/foo')); $collection1 = new RouteCollection(); $collection1->add('foo', $foo1 = new Route('/foo1')); - $collection->addCollection($collection1, '/foo'); - $this->assertEquals('/foo/foo1', $collection->get('foo')->getPattern(), '->addCollection() can add a prefix to all merged routes'); + $collection->addCollection($collection1, '/{foo}', array('foo' => 'foo'), array('foo' => '\d+')); + $this->assertEquals('/{foo}/foo1', $collection->get('foo')->getPattern(), '->addCollection() can add a prefix to all merged routes'); + $this->assertEquals(array('foo' => 'foo'), $collection->get('foo')->getDefaults(), '->addCollection() can add a prefix to all merged routes'); + $this->assertEquals(array('foo' => '\d+'), $collection->get('foo')->getRequirements(), '->addCollection() can add a prefix to all merged routes'); $collection = new RouteCollection(); $collection->addResource($foo = new FileResource(__DIR__.'/Fixtures/foo.xml')); @@ -119,9 +121,13 @@ public function testAddPrefix() $collection = new RouteCollection(); $collection->add('foo', $foo = new Route('/foo')); $collection->add('bar', $bar = new Route('/bar')); - $collection->addPrefix('/admin'); - $this->assertEquals('/admin/foo', $collection->get('foo')->getPattern(), '->addPrefix() adds a prefix to all routes'); - $this->assertEquals('/admin/bar', $collection->get('bar')->getPattern(), '->addPrefix() adds a prefix to all routes'); + $collection->addPrefix('/{admin}', array('admin' => 'admin'), array('admin' => '\d+')); + $this->assertEquals('/{admin}/foo', $collection->get('foo')->getPattern(), '->addPrefix() adds a prefix to all routes'); + $this->assertEquals('/{admin}/bar', $collection->get('bar')->getPattern(), '->addPrefix() adds a prefix to all routes'); + $this->assertEquals(array('admin' => 'admin'), $collection->get('foo')->getDefaults(), '->addPrefix() adds a prefix to all routes'); + $this->assertEquals(array('admin' => 'admin'), $collection->get('bar')->getDefaults(), '->addPrefix() adds a prefix to all routes'); + $this->assertEquals(array('admin' => '\d+'), $collection->get('foo')->getRequirements(), '->addPrefix() adds a prefix to all routes'); + $this->assertEquals(array('admin' => '\d+'), $collection->get('bar')->getRequirements(), '->addPrefix() adds a prefix to all routes'); } public function testResource() diff --git a/tests/Symfony/Tests/Component/Routing/RouteTest.php b/tests/Symfony/Tests/Component/Routing/RouteTest.php index 831bd915ba1c..91f09c850cc1 100644 --- a/tests/Symfony/Tests/Component/Routing/RouteTest.php +++ b/tests/Symfony/Tests/Component/Routing/RouteTest.php @@ -68,6 +68,11 @@ public function testDefaults() $route->setDefault('_controller', $closure = function () { return 'Hello'; }); $this->assertEquals($closure, $route->getDefault('_controller'), '->setDefault() sets a default value'); + + $route->setDefaults(array('foo' => 'foo')); + $route->addDefaults(array('bar' => 'bar')); + $this->assertEquals($route, $route->addDefaults(array()), '->addDefaults() implements a fluent interface'); + $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $route->getDefaults(), '->addDefaults() keep previous defaults'); } public function testRequirements() @@ -80,6 +85,11 @@ public function testRequirements() $route->setRequirements(array('foo' => '^\d+$')); $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the pattern'); $this->assertEquals($route, $route->setRequirements(array()), '->setRequirements() implements a fluent interface'); + + $route->setRequirements(array('foo' => '\d+')); + $route->addRequirements(array('bar' => '\d+')); + $this->assertEquals($route, $route->addRequirements(array()), '->addRequirements() implements a fluent interface'); + $this->assertEquals(array('foo' => '\d+', 'bar' => '\d+'), $route->getRequirements(), '->addRequirement() keep previous requirements'); } public function testRequirement()