Browse Source

Implement matches() and add in progress test cases.

mark_story 12 years ago
parent
commit
7a808d0a43
2 changed files with 204 additions and 2 deletions
  1. 43 2
      src/Routing/DispatcherFilter.php
  2. 161 0
      tests/TestCase/Routing/DispatcherFilterTest.php

+ 43 - 2
src/Routing/DispatcherFilter.php

@@ -15,6 +15,7 @@
 namespace Cake\Routing;
 
 use Cake\Core\InstanceConfigTrait;
+use Cake\Error;
 use Cake\Event\Event;
 use Cake\Event\EventListener;
 
@@ -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.');
+		}
 	}
 
 /**
@@ -100,12 +104,48 @@ class DispatcherFilter implements EventListener {
  */
 	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
  * URL and set the routing params into the request object.
@@ -136,4 +176,5 @@ class DispatcherFilter implements EventListener {
  */
 	public function afterDispatch(Event $event) {
 	}
+
 }

+ 161 - 0
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');
+
+	}
+
+}