First cut at Context::dispatch().
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);
+ }
}