Permalink
Browse files

Merge pull request #12 from elazar/route-filters

Added support for route filters to the application and dispatcher classes
  • Loading branch information...
2 parents 6922779 + ca883a8 commit 4caae2b3c53d121bd3461e8903be86e15fdcd037 @whatthejeff committed Jun 29, 2011
View
@@ -159,6 +159,28 @@ put('/process_my_form', function(){
});
```
+### Route Filters
+
+In some cases, routes patterns require a global modification, such as prepending a base path when the application is running in a subdirectory of the document root and web server-level URL rewrites are not an available or desirable option. Route filters are callbacks that are executed on each route pattern before it's evaluated against the current request.
+
+**bootstrap.php:**
+
+``` php
+config('base_dir', '/subdir');
+route(function($pattern) {
+ return config('base_dir') . $pattern;
+});
+```
+
+**Controller.php:**
+
+``` php
+// This route will actually resolve to /subdir/foo
+$app->get('/foo', function() {
+ // ...
+});
+```
+
Pass
----
View
@@ -116,6 +116,32 @@ function before()
}
/**
+ * Defines a new route filter.
+ *
+ * Closure `$filter` will be invoked on each route pattern before it's
+ * evaluated against the current request.
+ *
+ * NOTE: If you call `route()` multiple times, each callback will be invoked
+ * in the order it was defined.
+ *
+ * @code
+ * route(function($pattern){
+ * return '/subdir' . $pattern;
+ * });
+ * @endcode
+ *
+ * @param Closure $filter The filter to add.
+ *
+ * @return void
+ */
+function route()
+{
+ return call_user_func_array(
+ array(Application::getInstance('breeze'), 'route'), func_get_args()
+ );
+}
+
+/**
* Defines or dispatches a condition.
*
* @code
@@ -1497,16 +1497,21 @@ public function dispatch($requestMethod = null, $requestUri = null)
$this->setRequestMethod($requestMethod);
if (isset($this->_routes[$this->_requestMethod])) {
+ $filters = $this->_application->getRouteFilters();
foreach ($this->_routes[$this->_requestMethod] as $route) {
+ $pattern = $route['pattern'];
+ foreach ($filters as $filter) {
+ $pattern = $filter($pattern);
+ }
try {
- if ($route['pattern']{0} != '/') {
+ if ($pattern{0} != '/') {
$this->_processRegexpRoute(
- $route['pattern'],
+ $pattern,
$route['handler']
);
} else {
$this->_processRoute(
- $route['pattern'], $route['handler']
+ $pattern, $route['handler']
);
}
} catch (PassException $exception) {
@@ -1991,6 +1996,12 @@ class Application
* @var Breeze\ClosuresCollection
*/
protected $_filters = array();
+ /**
+ * User-defined route filters.
+ *
+ * @var Breeze\ClosuresCollection
+ */
+ protected $_routeFilters;
/**
* Initializes defined plugins and allows for overriding of default
@@ -2034,6 +2045,9 @@ public function __construct(Configurations $configurations = null)
'after_filters_object', 'Breeze\\ClosuresCollection'
)
);
+ $this->_routeFilters = $this->_getDependency(
+ 'route_filters_object', 'Breeze\\ClosuresCollection'
+ );
foreach (self::$_plugins as $plugin) {
$plugin($this);
@@ -2094,6 +2108,7 @@ public function __clone()
$this->_conditions = clone $this->_conditions;
$this->_status = clone $this->_status;
$this->_userHelpers = clone $this->_userHelpers;
+ $this->_routeFilters = clone $this->_routeFilters;
$this->_filters[self::BEFORE] = clone $this->_filters[self::BEFORE];
$this->_filters[self::AFTER] = clone $this->_filters[self::AFTER];
@@ -2505,6 +2520,16 @@ public function getUserHelpers()
}
/**
+ * Gets a list of all user-defined route filters.
+ *
+ * @return array All user-defined route filters.
+ */
+ public function getRouteFilters()
+ {
+ return $this->_routeFilters->all();
+ }
+
+ /**
* Adds a filter to be executed before the request is routed.
*
* @param Closure $filter The filter to add.
@@ -2517,6 +2542,19 @@ public function before($filter)
}
/**
+ * Adds a filter to be executed on each route before evaluating it
+ * against the current request.
+ *
+ * @param Closure $filter The filter to add.
+ *
+ * @return void
+ */
+ public function route($filter)
+ {
+ $this->_routeFilters->add($filter);
+ }
+
+ /**
* Adds a filter to be executed after the request is routed.
*
* @param Closure $filter The filter to add.
@@ -2578,4 +2616,4 @@ public function run($requestMethod = null, $requestUri = null)
// to the end of a Breeze request
}
}
-}
+}
@@ -784,6 +784,18 @@ public function testAddAfterFilter()
}
/**
+ * Tests {@link Breeze\Application::route()} to add a route filter.
+ */
+ public function testAddRouteFilter()
+ {
+ $closure = function(){};
+ $this->_mocks['route_filters_object']->expects($this->once())
+ ->method('add')
+ ->with($this->equalTo($closure));
+ $this->_application->route($closure);
+ }
+
+ /**
* Tests {@link Breeze\Application::filter()} with a bad filter type throws
* an InvalidArgumentException.
*/
@@ -1006,8 +1018,12 @@ public function testCloneIsDeep()
->method('add');
$clone->after(function(){});
+ $this->_mocks['route_filters_object']->expects($this->never())
+ ->method('add');
+ $clone->route(function(){});
+
$this->_configurations->expects($this->never())
->method('set');
$clone->config('jeff', 'is cool');
}
-}
+}
@@ -90,6 +90,9 @@ protected function _setupMockedDependencies()
$this->_mocks['after_filters_object'] = $this->getMock(
'Breeze\\ClosuresCollection', array(), array(), '', FALSE
);
+ $this->_mocks['route_filters_object'] = $this->getMock(
+ 'Breeze\\ClosuresCollection', array(), array(), '', FALSE
+ );
$this->_configurations = $this->getMock(
'Breeze\\Configurations', array(), array(), '', FALSE
@@ -130,10 +130,24 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase
*/
public function setUp()
{
+ $this->_mockApplication();
+ $this->_dispatcher = new Dispatcher($this->_application);
+ }
+
+ /**
+ * Configures a mock application instance.
+ *
+ * @param array $routeFilterCallbacks Optional list of router filter
+ * callbacks to add
+ */
+ protected function _mockApplication(array $routeFilterCallbacks = array())
+ {
$this->_application = $this->getMock(
- 'Breeze\\Application', array(), array(), '', FALSE
+ 'Breeze\\Application', array('getRouteFilters'), array(), '', FALSE
);
- $this->_dispatcher = new Dispatcher($this->_application);
+ $this->_application->expects($this->any())
+ ->method('getRouteFilters')
+ ->will($this->returnValue($routeFilterCallbacks));
}
/**
@@ -236,6 +250,24 @@ public function testSetRequestUriWithParameter()
}
/**
+ * Tests {@link Breeze\Dispatcher\Dispatcher::dispatch()} with route
+ * filters added.
+ */
+ public function testDispatchWithRouteFilters()
+ {
+ $bar = function($pattern) { return $pattern . '/bar'; };
+ $baz = function($pattern) { return $pattern . '/baz'; };
+ $this->_mockApplication(array($bar, $baz));
+ $this->_dispatcher = new Dispatcher($this->_application);
+ $success = false;
+ $this->_dispatcher->get('/foo', function() use (&$success) {
+ $success = true;
+ });
+ $this->_dispatcher->dispatch('GET', '/foo/bar/baz');
+ $this->assertTrue($success);
+ }
+
+ /**
* Tests {@link Breeze\Dispatcher\Dispatcher::setRequestUri()} to
* set the requested URI from the $_SERVER['REQUEST_URI'] superglobal.
*/

0 comments on commit 4caae2b

Please sign in to comment.