Skip to content

Commit

Permalink
Merge pull request #12 from elazar/route-filters
Browse files Browse the repository at this point in the history
Added support for route filters to the application and dispatcher classes
  • Loading branch information
whatthejeff committed Jun 29, 2011
2 parents 6922779 + ca883a8 commit 4caae2b
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 7 deletions.
22 changes: 22 additions & 0 deletions README.md
Expand Up @@ -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 Pass
---- ----


Expand Down
26 changes: 26 additions & 0 deletions lib/Breeze.php
Expand Up @@ -115,6 +115,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. * Defines or dispatches a condition.
* *
Expand Down
46 changes: 42 additions & 4 deletions lib/Breeze/Application.php
Expand Up @@ -1497,16 +1497,21 @@ public function dispatch($requestMethod = null, $requestUri = null)
$this->setRequestMethod($requestMethod); $this->setRequestMethod($requestMethod);


if (isset($this->_routes[$this->_requestMethod])) { if (isset($this->_routes[$this->_requestMethod])) {
$filters = $this->_application->getRouteFilters();
foreach ($this->_routes[$this->_requestMethod] as $route) { foreach ($this->_routes[$this->_requestMethod] as $route) {
$pattern = $route['pattern'];
foreach ($filters as $filter) {
$pattern = $filter($pattern);
}
try { try {
if ($route['pattern']{0} != '/') { if ($pattern{0} != '/') {
$this->_processRegexpRoute( $this->_processRegexpRoute(
$route['pattern'], $pattern,
$route['handler'] $route['handler']
); );
} else { } else {
$this->_processRoute( $this->_processRoute(
$route['pattern'], $route['handler'] $pattern, $route['handler']
); );
} }
} catch (PassException $exception) { } catch (PassException $exception) {
Expand Down Expand Up @@ -1991,6 +1996,12 @@ class Application
* @var Breeze\ClosuresCollection * @var Breeze\ClosuresCollection
*/ */
protected $_filters = array(); protected $_filters = array();
/**
* User-defined route filters.
*
* @var Breeze\ClosuresCollection
*/
protected $_routeFilters;


/** /**
* Initializes defined plugins and allows for overriding of default * Initializes defined plugins and allows for overriding of default
Expand Down Expand Up @@ -2034,6 +2045,9 @@ public function __construct(Configurations $configurations = null)
'after_filters_object', 'Breeze\\ClosuresCollection' 'after_filters_object', 'Breeze\\ClosuresCollection'
) )
); );
$this->_routeFilters = $this->_getDependency(
'route_filters_object', 'Breeze\\ClosuresCollection'
);


foreach (self::$_plugins as $plugin) { foreach (self::$_plugins as $plugin) {
$plugin($this); $plugin($this);
Expand Down Expand Up @@ -2094,6 +2108,7 @@ public function __clone()
$this->_conditions = clone $this->_conditions; $this->_conditions = clone $this->_conditions;
$this->_status = clone $this->_status; $this->_status = clone $this->_status;
$this->_userHelpers = clone $this->_userHelpers; $this->_userHelpers = clone $this->_userHelpers;
$this->_routeFilters = clone $this->_routeFilters;


$this->_filters[self::BEFORE] = clone $this->_filters[self::BEFORE]; $this->_filters[self::BEFORE] = clone $this->_filters[self::BEFORE];
$this->_filters[self::AFTER] = clone $this->_filters[self::AFTER]; $this->_filters[self::AFTER] = clone $this->_filters[self::AFTER];
Expand Down Expand Up @@ -2504,6 +2519,16 @@ public function getUserHelpers()
return array_keys($this->_userHelpers->all()); return array_keys($this->_userHelpers->all());
} }


/**
* 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. * Adds a filter to be executed before the request is routed.
* *
Expand All @@ -2516,6 +2541,19 @@ public function before($filter)
$this->_filters[self::BEFORE]->add($filter); $this->_filters[self::BEFORE]->add($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. * Adds a filter to be executed after the request is routed.
* *
Expand Down Expand Up @@ -2578,4 +2616,4 @@ public function run($requestMethod = null, $requestUri = null)
// to the end of a Breeze request // to the end of a Breeze request
} }
} }
} }
18 changes: 17 additions & 1 deletion test/Breeze/ApplicationTest.php
Expand Up @@ -783,6 +783,18 @@ public function testAddAfterFilter()
$this->_application->after($closure); $this->_application->after($closure);
} }


/**
* 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 * Tests {@link Breeze\Application::filter()} with a bad filter type throws
* an InvalidArgumentException. * an InvalidArgumentException.
Expand Down Expand Up @@ -1006,8 +1018,12 @@ public function testCloneIsDeep()
->method('add'); ->method('add');
$clone->after(function(){}); $clone->after(function(){});


$this->_mocks['route_filters_object']->expects($this->never())
->method('add');
$clone->route(function(){});

$this->_configurations->expects($this->never()) $this->_configurations->expects($this->never())
->method('set'); ->method('set');
$clone->config('jeff', 'is cool'); $clone->config('jeff', 'is cool');
} }
} }
3 changes: 3 additions & 0 deletions test/Breeze/ApplicationTestCase.php
Expand Up @@ -90,6 +90,9 @@ protected function _setupMockedDependencies()
$this->_mocks['after_filters_object'] = $this->getMock( $this->_mocks['after_filters_object'] = $this->getMock(
'Breeze\\ClosuresCollection', array(), array(), '', FALSE 'Breeze\\ClosuresCollection', array(), array(), '', FALSE
); );
$this->_mocks['route_filters_object'] = $this->getMock(
'Breeze\\ClosuresCollection', array(), array(), '', FALSE
);


$this->_configurations = $this->getMock( $this->_configurations = $this->getMock(
'Breeze\\Configurations', array(), array(), '', FALSE 'Breeze\\Configurations', array(), array(), '', FALSE
Expand Down
36 changes: 34 additions & 2 deletions test/Breeze/Dispatcher/DispatcherTest.php
Expand Up @@ -129,11 +129,25 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase
* @return void * @return void
*/ */
public function setUp() 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( $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));
} }


/** /**
Expand Down Expand Up @@ -235,6 +249,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 * Tests {@link Breeze\Dispatcher\Dispatcher::setRequestUri()} to
* set the requested URI from the $_SERVER['REQUEST_URI'] superglobal. * set the requested URI from the $_SERVER['REQUEST_URI'] superglobal.
Expand Down

0 comments on commit 4caae2b

Please sign in to comment.