Deprecated: Assigning the return value of new by reference is deprecated in /home/bluestat/public_html/source/index.php on line 477
phalanx - Commitdiff - ViewGit - Blue Static

First cut at Context::dispatch().

Robert Sesek [2009-08-25 00:33]
First cut at Context::dispatch().

* Added dispatch() and _tokenizeURL()
* Add unit test for GET requests in dispatch()
* Add tests for _tokenizeURL()
diff --git a/events/context.php b/events/context.php
index f5ee896..f2d6453 100644
--- a/events/context.php
+++ b/events/context.php
@@ -20,10 +20,17 @@ namespace phalanx\events;
 // request (GPC variables). Events are handleded within a specific context.
 class Context
 {
+	// The POST variable name used to determine the event to raise.
+	const kEventPOSTVarKey = 'phalanx_event';
+
 	// GPC variables. By default these are unsanitized. On construction, the
 	// variable arrays are copied from their respective superglobals.
 	protected $gpc = null;

+	// The base URL. This is stripped from the URL before tokenizing it in a
+	// GET request.
+	protected $base_url = '/';
+
 	public function __construct()
 	{
 		$gpc = array(
@@ -34,6 +41,67 @@ class Context
 		$this->gpc = new \phalanx\base\KeyDescender($gpc);
 	}

+	// This raises events based on incoming GET and POST data. If it's a GET
+	// request, the URL will be used to determine the event. If the request is
+	// a POST one, the key |kEventPOSTVarKey| will be used to determine the
+	// event. If neither one of those works, an exception is thrown.
+	public function dispatch()
+	{
+		$method = strtolower($_SERVER['REQUEST_METHOD']);
+		if ($method == 'post')
+		{
+			$event_name = $this->gpc->get('p.' . self::kEventPOSTVarKey);
+		}
+		else if ($method == 'get')
+		{
+			$this->_tokenizeURL();
+			$event_name = $this->gpc->get('g.' . self::kEventPOSTVarKey);
+		}
+		else
+		{
+			throw new ContextException("Unknown HTTP method '$method'");
+		}
+
+		$event_name = \phalanx\base\underscore_to_cammelcase($event_name);
+		if (class_exists($event_name . 'Event'))
+			$event_name .= 'Event';
+		else if (!class_exists($event_name))
+			throw new ContextException("Unable to locate event class for '$event_name'");
+
+		$event = new $event_name();
+		$event->set_context($this);
+		EventPump::pump()->raise($event);
+	}
+
+	// This splits a request URL into the event name and then appropriate key
+	// value matching. URLs can take the form:
+	//   /event_name/id
+	//   /event_name/id/k1/v1/k2/v2/
+	//   /event_name/k1/v1/k2/v2/
+	// The differentiation of |id| vs |k1| after |event_name| depends on if
+	// that path component is numeric.
+	protected function _tokenizeURL()
+	{
+		$url = $this->gpc->get('g.__dispatch__');
+		$base_url_pattern = preg_quote($this->base_url, '/');
+		$url = preg_replace('/^' . $base_url_pattern . '/', '', $url);
+		$parts = explode('/', $url);
+		\phalanx\base\array_strip_empty($parts);
+
+		$this->gpc->set('g.' . self::kEventPOSTVarKey, $parts[0]);
+
+		$i = 1;
+		if (is_numeric($parts[$i]))
+			$this->gpc->set('g.id', $parts[$i++]);
+
+		for ( ; $i < count($parts); $i += 2)
+		{
+			if (!isset($parts[$i]) || !isset($parts[$i+1]))
+				throw new ContextException("Invalid key-value pair in URL '$url'");
+			$this->gpc->set('g.' . $parts[$i], $parts[$i+1]);
+		}
+	}
+
 	// Called by the EventPump when an event in this context has been handled
 	// successfully and is ready for context-specific handling.
 	public function onEventHandled(Event $event)
@@ -43,4 +111,16 @@ class Context
 	// Setters and getters.
 	// -------------------------------------------------------------------------
 	public function gpc() { return $this->gpc; }
+
+	public function set_base_url($url)
+	{
+		if ($url[strlen($url) - 1] != '/')
+			$url .= '/';
+		$this->base_url = $url;
+	}
+	public function base_url() { return $this->base_url; }
+}
+
+class ContextException extends \Exception
+{
 }
diff --git a/testing/tests/events.php b/testing/tests/events.php
index 7752a6c..48d0c14 100644
--- a/testing/tests/events.php
+++ b/testing/tests/events.php
@@ -111,4 +111,5 @@ class TestContext extends events\Context
 	// Getter and setters.
 	// -------------------------------------------------------------------------
 	public function T_gpc() { return $this->gpc; }
+	public function T_tokenizeURL() { $this->_tokenizeURL(); }
 }
diff --git a/testing/tests/events/context_test.php b/testing/tests/events/context_test.php
index 2d6b0fe..d441c4d 100644
--- a/testing/tests/events/context_test.php
+++ b/testing/tests/events/context_test.php
@@ -66,4 +66,87 @@ class ContextTest extends \PHPUnit_Framework_TestCase
 		$pump->raise(new TestEvent());
 		$this->assertTrue($context->did_event_handled);
 	}
+
+	public function testBaseURL()
+	{
+		$this->assertEquals('/', $this->context->base_url());
+
+		$this->context->set_base_url('/foo/bar');
+		$this->assertEquals('/foo/bar/', $this->context->base_url());
+
+		$this->context->set_base_url('/another/moo/');
+		$this->assertEquals('/another/moo/', $this->context->base_url());
+
+		$this->context->set_base_url('');
+		$this->assertEquals('/', $this->context->base_url());
+	}
+
+	public function testTokenizeURLSimple()
+	{
+		$_GET['__dispatch__'] = '/test_event/';
+		$context = new TestContext();
+		$context->T_tokenizeURL();
+		$this->assertEquals('test_event', $context->gpc()->get('g.' . TestContext::kEventPOSTVarKey));
+	}
+
+	public function testTokenizeURLWithID()
+	{
+		$_GET['__dispatch__'] = '/test/314159/';
+		$context = new TestContext();
+		$context->T_tokenizeURL();
+		$this->assertEquals('test', $context->gpc()->get('g.' . TestContext::kEventPOSTVarKey));
+		$this->assertEquals('314159', $context->gpc()->get('g.id'));
+	}
+
+	public function testTokenizeURLWith1Pair()
+	{
+		$_GET['__dispatch__'] = '/test_event/k1/v1/';
+		$context = new TestContext();
+		$context->T_tokenizeURL();
+		$this->assertEquals('test_event', $context->gpc()->get('g.' . TestContext::kEventPOSTVarKey));
+		$this->assertEquals('v1', $context->gpc()->get('g.k1'));
+	}
+
+	public function testTokenizeURLWith2Pair()
+	{
+		$_GET['__dispatch__'] = '/test_event/k1/v1/k2/v2/';
+		$context = new TestContext();
+		$context->T_tokenizeURL();
+		$this->assertEquals('test_event', $context->gpc()->get('g.' . TestContext::kEventPOSTVarKey));
+		$this->assertEquals('v1', $context->gpc()->get('g.k1'));
+		$this->assertEquals('v2', $context->gpc()->get('g.k2'));
+	}
+
+	public function testTokenizeURLWithBadPair()
+	{
+		$_GET['__dispatch__'] = '/test_event/k1/';
+		$context = new TestContext();
+		$this->setExpectedException('\phalanx\events\ContextException');
+		$context->T_tokenizeURL();
+	}
+
+	public function testTokenizeURLWithIDAndPair()
+	{
+		$_GET['__dispatch__'] = '/test_event/314159/k1/v1/';
+		$context = new TestContext();
+		$context->T_tokenizeURL();
+		$this->assertEquals('test_event', $context->gpc()->get('g.' . TestContext::kEventPOSTVarKey));
+		$this->assertEquals('314159', $context->gpc()->get('g.id'));
+		$this->assertEquals('v1', $context->gpc()->get('g.k1'));
+	}
+
+	public function testDispatchGET()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$_GET['__dispatch__'] = '/test_event/314159/k1/v1/k2/v2/';
+		$pump = events\EventPump::pump();
+		$context = new TestContext();
+		$pump->set_context($context);
+		$context->dispatch();
+		$event = $pump->getLastEvent();
+		$this->assertTrue($event->did_init);
+		$this->assertTrue($event->did_handle);
+		$this->assertTrue($event->did_end);
+		$this->assertTrue($context->did_event_handled);
+	}
 }