Commit 31652440 authored by Fabien Potencier's avatar Fabien Potencier

added a way to define settings for all routes of a collection (closes #186)

parent a0a78aff
...@@ -3,6 +3,8 @@ Changelog ...@@ -3,6 +3,8 @@ Changelog
This changelog references all backward incompatibilities as we introduce them: This changelog references all backward incompatibilities as we introduce them:
* **2012-05-20**: Added a way to define settings for all routes of a collection.
* **2012-05-20**: The Request instance is not available anymore from the * **2012-05-20**: The Request instance is not available anymore from the
Application after it has been handled. Application after it has been handled.
......
...@@ -43,7 +43,7 @@ Routing ...@@ -43,7 +43,7 @@ Routing
------- -------
In Silex you define a route and the controller that is called when that In Silex you define a route and the controller that is called when that
route is matched route is matched.
A route pattern consists of: A route pattern consists of:
...@@ -433,6 +433,25 @@ redirect response, which you can create by calling the Application ...@@ -433,6 +433,25 @@ redirect response, which you can create by calling the Application
If a route middleware does not return a Symfony HTTP Response or ``null``, a If a route middleware does not return a Symfony HTTP Response or ``null``, a
``RuntimeException`` is thrown. ``RuntimeException`` is thrown.
Global Configuration
--------------------
If a route setting must be applied to all routes (a converter, a middleware, a
requirement, or a default value), you can configure it on
``$app['controllers']``, which holds all controllers::
$app['controllers']
->value('id', '1')
->assert('id', '\d+')
->requireHttps()
->method('get')
->convert('id', function () { // ... })
->middleware(function () { // ... })
;
These settings can be set before or after controller definitions and settings
defined on a controller always override the globally configured one.
Error handlers Error handlers
-------------- --------------
...@@ -575,7 +594,15 @@ blog home page, and ``/forum/`` to the forum home page. ...@@ -575,7 +594,15 @@ blog home page, and ``/forum/`` to the forum home page.
When calling ``get()``, ``match()``, or any other HTTP methods on the When calling ``get()``, ``match()``, or any other HTTP methods on the
Application, you are in fact calling them on a default instance of Application, you are in fact calling them on a default instance of
``ControllerCollection``. ``ControllerCollection`` (stored in ``$app['controllers']``).
Another benefit is the ability to apply default settings on a set of
controllers very easily. Building on the example from the middleware section,
here is how you would secure all controllers for all backend routes::
$backend = new ControllerCollection();
$backend->middleware($mustBeLogged);
.. tip:: .. tip::
......
...@@ -21,10 +21,11 @@ use Symfony\Component\Routing\Route; ...@@ -21,10 +21,11 @@ use Symfony\Component\Routing\Route;
*/ */
class Controller class Controller
{ {
private $route;
private $routeName; private $routeName;
private $isFrozen = false; private $isFrozen = false;
protected $route;
/** /**
* Constructor. * Constructor.
* *
......
...@@ -25,10 +25,20 @@ use Silex\Controller; ...@@ -25,10 +25,20 @@ use Silex\Controller;
* @author Igor Wiedler <igor@wiedler.ch> * @author Igor Wiedler <igor@wiedler.ch>
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
*/ */
class ControllerCollection class ControllerCollection extends Controller
{ {
protected $controllers = array(); protected $controllers = array();
/**
* Constructor.
*
* @param Route $route
*/
public function __construct()
{
parent::__construct(new Route(''));
}
/** /**
* Maps a pattern to a callable. * Maps a pattern to a callable.
* *
...@@ -120,6 +130,8 @@ class ControllerCollection ...@@ -120,6 +130,8 @@ class ControllerCollection
$routes = new RouteCollection(); $routes = new RouteCollection();
foreach ($this->controllers as $controller) { foreach ($this->controllers as $controller) {
$route = $controller->getRoute();
if (!$name = $controller->getRouteName()) { if (!$name = $controller->getRouteName()) {
$name = $controller->generateRouteName($prefix); $name = $controller->generateRouteName($prefix);
while ($routes->get($name)) { while ($routes->get($name)) {
...@@ -127,7 +139,11 @@ class ControllerCollection ...@@ -127,7 +139,11 @@ class ControllerCollection
} }
$controller->bind($name); $controller->bind($name);
} }
$routes->add($name, $controller->getRoute());
$this->mergeGlobalSettings($route);
$routes->add($name, $route);
$controller->freeze(); $controller->freeze();
} }
...@@ -135,4 +151,22 @@ class ControllerCollection ...@@ -135,4 +151,22 @@ class ControllerCollection
return $routes; return $routes;
} }
protected function mergeGlobalSettings(Route $route)
{
$route->setOption('_middlewares', array_merge((array) $this->route->getOption('_middlewares'), (array) $route->getOption('_middlewares')));
$route->setOption('_converters', array_replace((array) $this->route->getOption('_converters'), (array) $route->getOption('_converters')));
foreach ($this->route->getDefaults() as $name => $value) {
if (!$route->hasDefault($name)) {
$route->setDefault($name, $value);
}
}
foreach ($this->route->getRequirements() as $name => $value) {
if (!$route->getRequirement($name)) {
$route->setRequirement($name, $value);
}
}
}
} }
...@@ -94,4 +94,67 @@ class ControllerCollectionTest extends \PHPUnit_Framework_TestCase ...@@ -94,4 +94,67 @@ class ControllerCollectionTest extends \PHPUnit_Framework_TestCase
$this->assertCount(2, $routes->all()); $this->assertCount(2, $routes->all());
$this->assertEquals(array('_a_a', '_a_a_'), array_keys($routes->all())); $this->assertEquals(array('_a_a', '_a_a_'), array_keys($routes->all()));
} }
public function testRouteSettingsFromCollection()
{
$controller = new Controller(new Route('/'));
$controller
->value('bar', 'bar')
->value('baz', 'baz')
->assert('bar', 'bar')
->assert('baz', 'baz')
->convert('bar', $converterBar = function () {})
->middleware($middleware1 = function () {})
->bind('home')
;
$controller1 = new Controller(new Route('/'));
$controller1
->requireHttp()
->method('post')
->convert('foo', $converterFoo1 = function () {})
->bind('home1')
;
$controllers = new ControllerCollection();
$controllers->add($controller);
$controllers->add($controller1);
$controllers
->value('foo', 'foo')
->value('baz', 'not_used')
->assert('foo', 'foo')
->assert('baz', 'not_used')
->requireHttps()
->method('get')
->convert('foo', $converterFoo = function () {})
->middleware($middleware2 = function () {})
;
$routes = $controllers->flush();
$this->assertEquals(array(
'foo' => 'foo',
'bar' => 'bar',
'baz' => 'baz',
), $routes->get('home')->getDefaults());
$this->assertEquals(array(
'foo' => 'foo',
'bar' => 'bar',
'baz' => 'baz',
'_scheme' => 'https',
'_method' => 'get',
), $routes->get('home')->getRequirements());
$this->assertEquals(array(
'foo' => $converterFoo,
'bar' => $converterBar,
), $routes->get('home')->getOption('_converters'));
$this->assertEquals(array($middleware1, $middleware2), $routes->get('home')->getOption('_middlewares'));
$this->assertEquals('http', $routes->get('home1')->getRequirement('_scheme'));
$this->assertEquals('post', $routes->get('home1')->getRequirement('_method'));
$this->assertEquals(array('foo' => $converterFoo1), $routes->get('home1')->getOption('_converters'));
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment