Skip to content

Commit 7a808d0

Browse files
committed
Implement matches() and add in progress test cases.
1 parent 5ad0d6f commit 7a808d0

File tree

2 files changed

+204
-2
lines changed

2 files changed

+204
-2
lines changed

src/Routing/DispatcherFilter.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
namespace Cake\Routing;
1616

1717
use Cake\Core\InstanceConfigTrait;
18+
use Cake\Error;
1819
use Cake\Event\Event;
1920
use Cake\Event\EventListener;
2021

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

9296
/**
@@ -100,11 +104,47 @@ public function __construct($config = []) {
100104
*/
101105
public function implementedEvents() {
102106
return array(
103-
'Dispatcher.beforeDispatch' => array('callable' => 'beforeDispatch', 'priority' => $this->priority),
104-
'Dispatcher.afterDispatch' => array('callable' => 'afterDispatch', 'priority' => $this->priority),
107+
'Dispatcher.beforeDispatch' => array('callable' => 'handle', 'priority' => $this->priority),
108+
'Dispatcher.afterDispatch' => array('callable' => 'handle', 'priority' => $this->priority),
105109
);
106110
}
107111

112+
/**
113+
* Handler method that applies conditions and resolves the correct method to call.
114+
*
115+
* @param \Cake\Event\Event $event The event instance.
116+
* @return mixed
117+
*/
118+
public function handle(Event $event) {
119+
$name = $event->name();
120+
list($_, $method) = explode('.', $name);
121+
if (empty($this->_config['for']) && empty($this->_config['when'])) {
122+
return $this->{$method}($event);
123+
}
124+
if ($this->matches($event)) {
125+
return $this->{$method}($event);
126+
}
127+
}
128+
129+
/**
130+
* Check to see if the incoming request matches this filter's criteria.
131+
*
132+
* @param \Cake\Event\Event $event The event to match.
133+
* @return boolean
134+
*/
135+
public function matches(Event $event) {
136+
$request = $event->data['request'];
137+
$pass = true;
138+
if (!empty($this->_config['for'])) {
139+
$pass = strpos($request->here(false), $this->_config['for']) === 0;
140+
}
141+
if ($pass && !empty($this->_config['when'])) {
142+
$response = $event->data['response'];
143+
$pass = $this->_config['when']($request, $response);
144+
}
145+
return $pass;
146+
}
147+
108148
/**
109149
* Method called before the controller is instantiated and called to serve a request.
110150
* If used with default priority, it will be called after the Router has parsed the
@@ -136,4 +176,5 @@ public function beforeDispatch(Event $event) {
136176
*/
137177
public function afterDispatch(Event $event) {
138178
}
179+
139180
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
/**
3+
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4+
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5+
*
6+
* Licensed under The MIT License
7+
* For full copyright and license information, please see the LICENSE.txt
8+
* Redistributions of files must retain the above copyright notice.
9+
*
10+
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11+
* @link http://cakephp.org CakePHP(tm) Project
12+
* @since 3.0.0
13+
* @license http://www.opensource.org/licenses/mit-license.php MIT License
14+
*/
15+
namespace Cake\Test\TestCase\Routing;
16+
17+
use Cake\Event\Event;
18+
use Cake\Network\Request;
19+
use Cake\Network\Response;
20+
use Cake\Routing\DispatcherFilter;
21+
use Cake\TestSuite\TestCase;
22+
23+
/**
24+
* Dispatcher filter test.
25+
*/
26+
class DispatcherFilterTest extends TestCase {
27+
28+
/**
29+
* Test that the constructor takes config.
30+
*
31+
* @return void
32+
*/
33+
public function testConstructConfig() {
34+
$filter = new DispatcherFilter(['one' => 'value', 'on' => '/blog']);
35+
$this->assertEquals('value', $filter->config('one'));
36+
}
37+
38+
/**
39+
* Test constructor error invalid when
40+
*
41+
* @expectedException Cake\Error\Exception
42+
* @expectedExceptionMessage "when" conditions must be a callable.
43+
* @return void
44+
*/
45+
public function testConstructorInvalidWhen() {
46+
new DispatcherFilter(['when' => 'nope']);
47+
}
48+
49+
/**
50+
* Test basic matching with for option.
51+
*
52+
* @return void
53+
*/
54+
public function testMatchesWithFor() {
55+
$request = new Request(['url' => '/articles/view']);
56+
$event = new Event('Dispatcher.beforeDispatch', $this, compact('request'));
57+
$filter = new DispatcherFilter(['for' => '/articles']);
58+
$this->assertTrue($filter->matches($event));
59+
60+
$request = new Request(['url' => '/blog/articles']);
61+
$event = new Event('Dispatcher.beforeDispatch', $this, compact('request'));
62+
$this->assertFalse($filter->matches($event), 'Does not start with /articles');
63+
}
64+
65+
/**
66+
* Test matching with when option.
67+
*
68+
* @return void
69+
*/
70+
public function testMatchesWithWhen() {
71+
$matcher = function ($request, $response) {
72+
$this->assertInstanceOf('Cake\Network\Request', $request);
73+
$this->assertInstanceOf('Cake\Network\Response', $response);
74+
return true;
75+
};
76+
77+
$request = new Request(['url' => '/articles/view']);
78+
$response = new Response();
79+
$event = new Event('Dispatcher.beforeDispatch', $this, compact('response', 'request'));
80+
$filter = new DispatcherFilter(['when' => $matcher]);
81+
$this->assertTrue($filter->matches($event));
82+
83+
$matcher = function() {
84+
return false;
85+
};
86+
$filter = new DispatcherFilter(['when' => $matcher]);
87+
$this->assertFalse($filter->matches($event));
88+
}
89+
90+
/**
91+
* Test matching with for & when option.
92+
*
93+
* @return void
94+
*/
95+
public function testMatchesWithForAndWhen() {
96+
$request = new Request(['url' => '/articles/view']);
97+
$response = new Response();
98+
99+
$matcher = function () {
100+
return true;
101+
};
102+
$event = new Event('Dispatcher.beforeDispatch', $this, compact('response', 'request'));
103+
$filter = new DispatcherFilter(['for' => '/admin', 'when' => $matcher]);
104+
$this->assertFalse($filter->matches($event));
105+
106+
$filter = new DispatcherFilter(['for' => '/articles', 'when' => $matcher]);
107+
$this->assertTrue($filter->matches($event));
108+
109+
$matcher = function() {
110+
return false;
111+
};
112+
$filter = new DispatcherFilter(['for' => '/admin', 'when' => $matcher]);
113+
$this->assertFalse($filter->matches($event));
114+
115+
$filter = new DispatcherFilter(['for' => '/articles', 'when' => $matcher]);
116+
$this->assertFalse($filter->matches($event));
117+
}
118+
119+
/**
120+
* Test matching with when option.
121+
*
122+
* @expectedException \RuntimeException
123+
* @expectedExceptionMessage 'when' conditions must be a callable.
124+
* @return void
125+
*/
126+
public function testMatchesWithWhenInvalid() {
127+
$this->markTestIncomplete('not done');
128+
129+
}
130+
131+
/**
132+
* Test event bindings have use condition checker
133+
*
134+
* @return void
135+
*/
136+
public function testImplementedEventsMethodName() {
137+
$this->markTestIncomplete('not done');
138+
139+
}
140+
141+
/**
142+
* Test handle applies for conditions
143+
*
144+
* @return void
145+
*/
146+
public function testHandleAppliesFor() {
147+
$this->markTestIncomplete('not done');
148+
149+
}
150+
151+
/**
152+
* Test handle applies when conditions
153+
*
154+
* @return void
155+
*/
156+
public function testHandleAppliesWhen() {
157+
$this->markTestIncomplete('not done');
158+
159+
}
160+
161+
}

0 commit comments

Comments
 (0)