Skip to content

Commit

Permalink
Implement matches() and add in progress test cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed May 15, 2014
1 parent 5ad0d6f commit 7a808d0
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 2 deletions.
45 changes: 43 additions & 2 deletions src/Routing/DispatcherFilter.php
Expand Up @@ -15,6 +15,7 @@
namespace Cake\Routing;

use Cake\Core\InstanceConfigTrait;
use Cake\Error;
use Cake\Event\Event;
use Cake\Event\EventListener;

Expand Down Expand Up @@ -87,6 +88,9 @@ class DispatcherFilter implements EventListener {
*/
public function __construct($config = []) {
$this->config($config);
if (isset($config['when']) && !is_callable($config['when'])) {
throw new Error\Exception('"when" conditions must be a callable.');
}
}

/**
Expand All @@ -100,11 +104,47 @@ public function __construct($config = []) {
*/
public function implementedEvents() {
return array(
'Dispatcher.beforeDispatch' => array('callable' => 'beforeDispatch', 'priority' => $this->priority),
'Dispatcher.afterDispatch' => array('callable' => 'afterDispatch', 'priority' => $this->priority),
'Dispatcher.beforeDispatch' => array('callable' => 'handle', 'priority' => $this->priority),
'Dispatcher.afterDispatch' => array('callable' => 'handle', 'priority' => $this->priority),
);
}

/**
* Handler method that applies conditions and resolves the correct method to call.
*
* @param \Cake\Event\Event $event The event instance.
* @return mixed
*/
public function handle(Event $event) {
$name = $event->name();
list($_, $method) = explode('.', $name);
if (empty($this->_config['for']) && empty($this->_config['when'])) {
return $this->{$method}($event);
}
if ($this->matches($event)) {
return $this->{$method}($event);
}
}

/**
* Check to see if the incoming request matches this filter's criteria.
*
* @param \Cake\Event\Event $event The event to match.
* @return boolean
*/
public function matches(Event $event) {
$request = $event->data['request'];
$pass = true;
if (!empty($this->_config['for'])) {
$pass = strpos($request->here(false), $this->_config['for']) === 0;
}
if ($pass && !empty($this->_config['when'])) {
$response = $event->data['response'];
$pass = $this->_config['when']($request, $response);
}
return $pass;
}

/**
* Method called before the controller is instantiated and called to serve a request.
* If used with default priority, it will be called after the Router has parsed the
Expand Down Expand Up @@ -136,4 +176,5 @@ public function beforeDispatch(Event $event) {
*/
public function afterDispatch(Event $event) {
}

}
161 changes: 161 additions & 0 deletions tests/TestCase/Routing/DispatcherFilterTest.php
@@ -0,0 +1,161 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\TestCase\Routing;

use Cake\Event\Event;
use Cake\Network\Request;
use Cake\Network\Response;
use Cake\Routing\DispatcherFilter;
use Cake\TestSuite\TestCase;

/**
* Dispatcher filter test.
*/
class DispatcherFilterTest extends TestCase {

/**
* Test that the constructor takes config.
*
* @return void
*/
public function testConstructConfig() {
$filter = new DispatcherFilter(['one' => 'value', 'on' => '/blog']);
$this->assertEquals('value', $filter->config('one'));
}

/**
* Test constructor error invalid when
*
* @expectedException Cake\Error\Exception
* @expectedExceptionMessage "when" conditions must be a callable.
* @return void
*/
public function testConstructorInvalidWhen() {
new DispatcherFilter(['when' => 'nope']);
}

/**
* Test basic matching with for option.
*
* @return void
*/
public function testMatchesWithFor() {
$request = new Request(['url' => '/articles/view']);
$event = new Event('Dispatcher.beforeDispatch', $this, compact('request'));
$filter = new DispatcherFilter(['for' => '/articles']);
$this->assertTrue($filter->matches($event));

$request = new Request(['url' => '/blog/articles']);
$event = new Event('Dispatcher.beforeDispatch', $this, compact('request'));
$this->assertFalse($filter->matches($event), 'Does not start with /articles');
}

/**
* Test matching with when option.
*
* @return void
*/
public function testMatchesWithWhen() {
$matcher = function ($request, $response) {
$this->assertInstanceOf('Cake\Network\Request', $request);
$this->assertInstanceOf('Cake\Network\Response', $response);
return true;
};

$request = new Request(['url' => '/articles/view']);
$response = new Response();
$event = new Event('Dispatcher.beforeDispatch', $this, compact('response', 'request'));
$filter = new DispatcherFilter(['when' => $matcher]);
$this->assertTrue($filter->matches($event));

$matcher = function() {
return false;
};
$filter = new DispatcherFilter(['when' => $matcher]);
$this->assertFalse($filter->matches($event));
}

/**
* Test matching with for & when option.
*
* @return void
*/
public function testMatchesWithForAndWhen() {
$request = new Request(['url' => '/articles/view']);
$response = new Response();

$matcher = function () {
return true;
};
$event = new Event('Dispatcher.beforeDispatch', $this, compact('response', 'request'));
$filter = new DispatcherFilter(['for' => '/admin', 'when' => $matcher]);
$this->assertFalse($filter->matches($event));

$filter = new DispatcherFilter(['for' => '/articles', 'when' => $matcher]);
$this->assertTrue($filter->matches($event));

$matcher = function() {
return false;
};
$filter = new DispatcherFilter(['for' => '/admin', 'when' => $matcher]);
$this->assertFalse($filter->matches($event));

$filter = new DispatcherFilter(['for' => '/articles', 'when' => $matcher]);
$this->assertFalse($filter->matches($event));
}

/**
* Test matching with when option.
*
* @expectedException \RuntimeException
* @expectedExceptionMessage 'when' conditions must be a callable.
* @return void
*/
public function testMatchesWithWhenInvalid() {
$this->markTestIncomplete('not done');

}

/**
* Test event bindings have use condition checker
*
* @return void
*/
public function testImplementedEventsMethodName() {
$this->markTestIncomplete('not done');

}

/**
* Test handle applies for conditions
*
* @return void
*/
public function testHandleAppliesFor() {
$this->markTestIncomplete('not done');

}

/**
* Test handle applies when conditions
*
* @return void
*/
public function testHandleAppliesWhen() {
$this->markTestIncomplete('not done');

}

}

0 comments on commit 7a808d0

Please sign in to comment.