Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release-0.2.6'

  • Loading branch information...
commit 18a42a72bea585c6702f7e45e291792780d3e010 2 parents f7d88db + 4992e6e
Tony R Quilkey trq authored
24 lib/Proem/Api/Bootstrap/Filter/Event/Dispatch.php
View
@@ -31,8 +31,11 @@
namespace Proem\Api\Bootstrap\Filter\Event;
use Proem\Service\Manager\Template as Manager,
+ Proem\Service\Asset\Standard as Asset,
Proem\Bootstrap\Signal\Event\Bootstrap,
- Proem\Filter\Event\Generic as Event;
+ Proem\Filter\Event\Generic as Event,
+ Proem\Dispatch\Standard as DispatchStandard,
+ Proem\Dispatch\Stage as DispatchStage;
/**
* Proem\Api\Bootstrap\Filter\Event\Dispatch
@@ -55,7 +58,11 @@ public function preIn(Manager $assets)
'target' => $this,
'method' => __FUNCTION__,
'event' => (new Bootstrap())->setServiceManager($assets),
- 'callback' => function($e) {},
+ 'callback' => function($e) use ($assets) {
+ if ($e->provides('Proem\Dispatch\Template')) {
+ $assets->set('dispatch', $e);
+ }
+ },
]);
}
}
@@ -67,7 +74,15 @@ public function preIn(Manager $assets)
*/
public function inBound(Manager $assets)
{
-
+ if (!$assets->provides('Proem\Dispatch\Template')) {
+ $asset = new Asset;
+ $assets->set(
+ 'dispatch',
+ $asset->set('Proem\Dispatch\Template', $asset->single(function() use ($assets) {
+ return new DispatchStandard($assets);
+ }))
+ );
+ }
}
/**
@@ -87,6 +102,9 @@ public function postIn(Manager $assets)
'callback' => function($e) {},
]);
}
+
+ // Dispatch to userland.
+ (new DispatchStage($assets));
}
/**
2  lib/Proem/Api/Bootstrap/Filter/Event/Response.php
View
@@ -135,7 +135,7 @@ public function preOut(Manager $assets)
*/
public function outBound(Manager $assets)
{
- if ($assets->provides('Proem\IO\Response\Template\Template')) {
+ if ($assets->provides('Proem\IO\Response\Template')) {
$assets->get('response')->send();
}
}
63 lib/Proem/Api/Bootstrap/Filter/Event/Route.php
View
@@ -34,6 +34,7 @@
Proem\Bootstrap\Signal\Event\Bootstrap,
Proem\Service\Asset\Standard as Asset,
Proem\Routing\Router\Standard as Router,
+ Proem\Routing\Route\Standard as StandardRoute,
Proem\Filter\Event\Generic as Event;
/**
@@ -52,13 +53,13 @@ public function preIn(Manager $assets)
{
if ($assets->provides('events', '\Proem\Signal\Manager\Template')) {
$assets->get('events')->trigger([
- 'name' => 'pre.in.route',
+ 'name' => 'pre.in.router',
'params' => [],
'target' => $this,
'method' => __FUNCTION__,
'event' => (new Bootstrap())->setServiceManager($assets),
'callback' => function($e) use ($assets) {
- if ($e->provides('Proem\Routing\Router')) {
+ if ($e->provides('Proem\Routing\Router\Template')) {
$assets->set('router', $e);
}
},
@@ -77,8 +78,56 @@ public function inBound(Manager $assets)
$asset = new Asset;
$assets->set(
'router',
- $asset->set('Proem\Routing\Router', $asset->single(function() use ($assets) {
- return new Router($assets->get('request')->getRequestUri());
+ $asset->set('Proem\Routing\Router\Template', $asset->single(function() use ($assets) {
+ $router = (new Router($assets->get('request')->getRequestUri()))
+ ->map(
+ 'default-module-controller-action-params',
+ new StandardRoute([
+ 'rule' => '/:module/:controller/:action/:params'
+ ])
+ )
+ ->map(
+ 'default-module-controller-action-noparams',
+ new StandardRoute([
+ 'rule' => '/:module/:controller/:action'
+ ])
+ )
+ ->map(
+ 'default-module-controller-noaction',
+ new StandardRoute([
+ 'rule' => '/:module/:controller',
+ 'targets' => ['action' => 'index']
+ ])
+ )
+ ->map(
+ 'default-nomodule-controller',
+ new StandardRoute([
+ 'rule' => '/:controller',
+ 'targets' => ['module' => 'index', 'action' => 'index']
+ ])
+ )
+ ->map(
+ 'default-module-nocontroller',
+ new StandardRoute([
+ 'rule' => '/:module',
+ 'targets' => ['controller' => 'index', 'action' => 'index']
+ ])
+ )
+ ->map(
+ 'default-params',
+ new StandardRoute([
+ 'rule' => '/:params',
+ 'targets' => ['module' => 'index', 'controller' => 'index', 'action' => 'index']
+ ])
+ )
+ ->map(
+ 'default-noparams',
+ new StandardRoute([
+ 'rule' => '/',
+ 'targets' => ['module' => 'index', 'controller' => 'index', 'action' => 'index']
+ ])
+ );
+ return $router;
}))
);
}
@@ -93,7 +142,7 @@ public function postIn(Manager $assets)
{
if ($assets->provides('events', '\Proem\Signal\Manager\Template')) {
$assets->get('events')->trigger([
- 'name' => 'post.in.route',
+ 'name' => 'post.in.router',
'params' => [],
'target' => $this,
'method' => __FUNCTION__,
@@ -112,7 +161,7 @@ public function preOut(Manager $assets)
{
if ($assets->provides('events', '\Proem\Signal\Manager\Template')) {
$assets->get('events')->trigger([
- 'name' => 'pre.out.route',
+ 'name' => 'pre.out.router',
'params' => [],
'target' => $this,
'method' => __FUNCTION__,
@@ -141,7 +190,7 @@ public function postOut(Manager $assets)
{
if ($assets->provides('events', '\Proem\Signal\Manager\Template')) {
$assets->get('events')->trigger([
- 'name' => 'post.out.route',
+ 'name' => 'post.out.router',
'params' => [],
'target' => $this,
'method' => __FUNCTION__,
165 lib/Proem/Api/Dispatch/Stage.php
View
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 - 2012 Tony R Quilkey <trq@proemframework.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @namespace Proem\Api\Dispatch
+ */
+namespace Proem\Api\Dispatch;
+
+use Proem\Service\Manager\Template as Manager,
+ Proem\Routing\Signal\Event\RouteMatch,
+ Proem\Routing\Signal\Event\RouteExhausted;
+
+/**
+ * Proem\Dispatch\Stage
+ */
+class Stage
+{
+ /**
+ * Store the Services Manager.
+ *
+ * @var Proem\Services\Manager\Template
+ */
+ protected $assets;
+
+ /**
+ * Store a *Dispatchable* flag.
+ */
+ protected $dispatchable = false;
+
+ /**
+ * This object represents the Dispatch staging area.
+ *
+ * It is here that the Dispatch process puts on it's show.
+ */
+ public function __construct(Manager $assets)
+ {
+ $this->assets = $assets;
+
+ $this->registerRouteMatchListener();
+ $this->registerRouteExhaustedListener();
+
+ if ($this->processRoutes() && $this->dispatchable) {
+ $this->dispatch();
+ }
+ }
+
+ /**
+ * Register a callback ready to listen for the route.match Event.
+ */
+ private function registerRouteMatchListener()
+ {
+ if ($this->assets->has('events')) {
+ $this->assets->get('events')->attach([
+ 'name' => 'route.match',
+ 'callback' => [$this, 'isDispatchable']
+ ]);
+ }
+ }
+
+ /**
+ * Register a callback ready to listen for the route.exhausted Event.
+ */
+ private function registerRouteExhaustedListener()
+ {
+ if ($this->assets->has('events')) {
+ $this->assets->get('events')->attach([
+ 'name' => 'route.exhausted',
+ 'callback' => [$this, 'routesExhausted']
+ ]);
+ }
+ }
+
+ /**
+ * Iterate through matching routes and trigger a match.route Event
+ * on each iteration.
+ */
+ private function processRoutes()
+ {
+ if ($this->assets->has('router') && $this->assets->has('events')) {
+ $router = $this->assets->get('router');
+ while ($payload = $router->route()) {
+ $this->assets->get('events')->trigger([
+ 'name' => 'route.match',
+ 'event' => (new RouteMatch())->setPayload($payload),
+ 'callback' => function($e) {
+ if ($e) {
+ $this->dispatchable = true;
+ }
+ }
+ ]);
+
+ if ($this->dispatchable) {
+ return true;
+ }
+ }
+
+ // All routess have been exhaasted
+ $this->assets->get('events')->trigger([
+ 'name' => 'route.exhausted',
+ 'event' => (new RouteExhausted())
+ ]);
+ }
+ }
+
+ /**
+ * Dispatch the payload.
+ */
+ private function dispatch()
+ {
+ if ($this->assets->has('dispatch')) {
+ $this->assets->get('dispatch')->dispatch();
+ }
+ }
+
+ /**
+ * Listen for the route.event Event. If the RouteMatch event passed in
+ * produces a Dispatchable Payload return a Dispatchable flag and Dispatch
+ * the object.
+ */
+ public function isDispatchable($e)
+ {
+ if ($this->assets->has('dispatch')) {
+ return $this->assets->get('dispatch')
+ ->setPayload($e->getPayload())
+ ->isDispatchable();
+ }
+ }
+
+ /**
+ * Listen for a route.exhuasted Event.
+ *
+ * If triggered, dispatch a 404
+ */
+ public function routesExhausted()
+ {
+ if ($this->assets->has('response')) {
+ $this->assets->get('response')
+ ->setHttpStatus(404)
+ ->appendToBody('<h3>404 - Page Not Found</h3>');
+ }
+ }
+}
128 lib/Proem/Api/Dispatch/Standard.php
View
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 - 2012 Tony R Quilkey <trq@proemframework.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @namespace Proem\Api\Dispatch
+ */
+namespace Proem\Api\Dispatch;
+
+use Proem\Dispatch\Template as Template,
+ Proem\Service\Manager\Template as Manager,
+ Proem\Routing\Route\Payload as Payload;
+
+/**
+ * Proem\Dispatch\Standard
+ */
+class Standard implements Template
+{
+ /**
+ * Store the Assets manager
+ *
+ * @var Proem\Service\Manager\Template
+ */
+ protected $assets;
+
+ /**
+ * Store an array of patterns used to searching
+ * for classes within a namepspace.
+ */
+ protected $namespacePatterns = [];
+
+ /**
+ * Store the absolute namespace to the current class
+ */
+ protected $class;
+
+ /**
+ * Store the Router Payload.
+ *
+ * @var Proem\Routing\Route\Payload
+ */
+ protected $payload;
+
+ /**
+ * Store the module name from the payload
+ */
+ protected $module;
+
+ /**
+ * Store the controller name from the payload
+ */
+ protected $controller;
+
+ /**
+ * Store the action name from the payload
+ */
+ protected $action;
+
+ public function __construct(Manager $assets)
+ {
+ $this->assets = $assets;
+ $this->namespacePatterns = ['Module\:module\Controller\:controller'];
+ }
+
+ public function setPayload(Payload $payload)
+ {
+ $this->payload = $payload;
+ return $this;
+ }
+
+ public function isDispatchable()
+ {
+ $this->module = $this->payload->has('module') ? ucfirst(strtolower($this->payload->get('module'))) : '';
+ $this->controller = $this->payload->has('controller') ? ucfirst(strtolower($this->payload->get('controller'))) : '';
+ $this->action = $this->payload->has('action') ? $this->payload->get('action') : '';
+
+ foreach ($this->namespacePatterns as $pattern) {
+ $this->class = str_replace(
+ [':module', ':controller'],
+ [$this->module, $this->controller],
+ $pattern
+ );
+
+ if (class_exists($this->class)) {
+ $this->class = new $this->class($this->assets);
+ if (method_exists($this->class, $this->action)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public function dispatch()
+ {
+ if ($this->assets->has('request') && $this->payload->get('params') && is_array($this->payload->get('params'))) {
+ $this->assets->get('request')
+ ->setGetData($this->payload->get('params'));
+ }
+ $this->class->setUp();
+ $this->class->{$this->action}();
+ $this->class->tearDown();
+ return $this;
+ }
+}
47 lib/Proem/Api/Dispatch/Template.php
View
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 - 2012 Tony R Quilkey <trq@proemframework.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @namespace Proem\Api\Dispatch
+ */
+namespace Proem\Api\Dispatch;
+
+use Proem\Service\Manager\Template as Manager,
+ Proem\Routing\Route\Payload as Payload;
+
+/**
+ * Proem\Dispatch\Template
+ */
+interface Template
+{
+ public function __construct(Manager $assets);
+
+ public function setPayload(Payload $payload);
+
+ public function isDispatchable();
+
+ public function dispatch();
+}
8 lib/Proem/Api/IO/Request/Http/Standard.php
View
@@ -192,6 +192,14 @@ public function setMethod($method)
}
/**
+ * Set GET data
+ */
+ public function setGetData(array $data)
+ {
+ $this->data['get']->set($data);
+ }
+
+ /**
* Get request method.
*/
public function getMethod()
2  lib/Proem/Api/Proem.php
View
@@ -52,7 +52,7 @@ class Proem
/**
* Store the framework version
*/
- const VERSION = '0.2.5';
+ const VERSION = '0.2.6';
/**
* Store events
2  lib/Proem/Api/Routing/Route/Generic.php
View
@@ -30,7 +30,7 @@
*/
namespace Proem\Api\Routing\Route;
-use Proem\Dispatch\Payload,
+use Proem\Routing\Route\Payload,
Proem\Util\Opt\Options,
Proem\Util\Opt\Option,
Proem\Util\ArrayHelper,
6 lib/Proem/Api/Dispatch/Payload.php → lib/Proem/Api/Routing/Route/Payload.php
View
@@ -26,14 +26,14 @@
/**
- * @namespace Proem\Api\Dispatch
+ * @namespace Proem\Api\Routing\Route
*/
-namespace Proem\Api\Dispatch;
+namespace Proem\Api\Routing\Route;
use Proem\Util\Storage\KeyValStore;
/**
- * Proem\Api\Dispatch\Payload
+ * Proem\Api\Routing\Route\Payload
*/
class Payload extends KeyValStore
{
26 lib/Proem/Api/Routing/Route/Standard.php
View
@@ -41,7 +41,7 @@ class Standard extends Generic
/**
* Store default tokens.
*/
- private $_default_tokens = [];
+ private $default_tokens = [];
/**
* Store default filters.
@@ -54,7 +54,7 @@ class Standard extends Generic
public function __construct(array $options) {
parent::__construct($options);
- $this->_default_filters = [
+ $this->default_filters = [
':default' => '[a-zA-Z0-9_\+\-%]+',
':gobble' => '[a-zA-Z0-9_\+\-%\/]+',
':int' => '[0-9]+',
@@ -62,11 +62,11 @@ public function __construct(array $options) {
':slug' => '[a-zA-Z0-9_-]+'
];
- $this->_default_tokens = [
- 'module' => $this->_default_filters[':default'],
- 'controller' => $this->_default_filters[':default'],
- 'action' => $this->_default_filters[':default'],
- 'params' => $this->_default_filters[':gobble']
+ $this->default_tokens = [
+ 'module' => $this->default_filters[':default'],
+ 'controller' => $this->default_filters[':default'],
+ 'action' => $this->default_filters[':default'],
+ 'params' => $this->default_filters[':gobble']
];
}
@@ -105,8 +105,8 @@ public function process($uri)
$rule = $this->options->rule;
$target = $this->options->targets;
$custom_filters = $this->options->filters;
- $default_tokens = $this->_default_tokens;
- $default_filters = $this->_default_filters;
+ $default_tokens = $this->default_tokens;
+ $default_filters = $this->default_filters;
$keys = [];
$values = [];
@@ -129,7 +129,7 @@ function($matches) use ($custom_filters, $default_tokens, $default_filters)
} else if (array_key_exists($key, $default_tokens)) {
return '(' . $default_tokens[$key] . ')';
} else {
- return $default_filters['default'];
+ return $default_filters[':default'];
}
},
$rule
@@ -139,7 +139,9 @@ function($matches) use ($custom_filters, $default_tokens, $default_filters)
array_shift($values);
foreach ($keys as $index => $value) {
- $params[substr($value, 1)] = urldecode($values[$index]);
+ if (isset($values[$index])) {
+ $params[substr($value, 1)] = urldecode($values[$index]);
+ }
}
foreach ($target as $key => $value) {
@@ -152,7 +154,7 @@ function($matches) use ($custom_filters, $default_tokens, $default_filters)
// parse it into an array and send it to setParams() instead
// of the singular setParam.
if ($key == 'params' && strpos($value, '/') !== false) {
- $this->getPayload()->set($this->createAssocArray(explode('/', trim($value, '/'))));
+ $this->getPayload()->set('params', $this->createAssocArray(explode('/', trim($value, '/'))));
} else {
$this->getPayload()->set($key, $value);
}
34 lib/Proem/Api/Routing/Router/Standard.php
View
@@ -30,7 +30,10 @@
*/
namespace Proem\Api\Routing\Router;
-use Proem\Routing\Route\Template as Route;
+use Proem\Routing\Router\Template,
+ Proem\Routing\Route\Template as Route,
+ Proem\Routing\Signal\Event\RouteMatch,
+ Proem\Signal\Manager\Template as SignalManager;
/**
* Proem\Api\Routing\Router\Standard
@@ -54,9 +57,9 @@ class Standard implements Template
*
* @param string $requestUri
*/
- public function __construct($requestUri)
+ public function __construct($requestUrl)
{
- $this->requestUri = $requestUri;
+ $this->requestUrl = $requestUrl;
}
/**
@@ -64,21 +67,34 @@ public function __construct($requestUri)
*/
public function map($name, Route $route)
{
- $this->_routes[$name] = $route;
+ $this->routes[$name] = $route;
return $this;
}
/**
- * Test routes for matching route and found return a DispatchPayload
+ * Recurse through the Routes until a match is found.
+ *
+ * When called multiple times (in a loop for instance)
+ * this method will return a new matching route until
+ * all routes have been processed.
+ *
+ * Once exhausted this function returns false and the
+ * internal pointer is reset so the Router can be used
+ * again.
*/
public function route()
{
- foreach ($this->_routes as $name => $route) {
- $route->process($this->requestUri);
+ if ($route = current($this->routes)) {
+ next($this->routes);
+ $route->process($this->requestUrl);
+
if ($route->isMatch() && $route->getPayload()->isPopulated()) {
- break;
+ return $route->getPayload();
+ } else {
+ return $this->route();
}
}
- return $route->getPayload();
+ reset($this->routes);
+ return false;
}
}
43 lib/Proem/Api/Routing/Signal/Event/RouteExhausted.php
View
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 - 2012 Tony R Quilkey <trq@proemframework.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+/**
+ * @namespace Proem\Api\Routing\Signal\Event
+ */
+namespace Proem\Api\Routing\Signal\Event;
+
+use Proem\Signal\Event\Standard,
+ Proem\Routing\Route\Payload;
+
+/**
+ * Proem\Api\Bootstrap\Signal\Event\Bootstrap
+ *
+ * A custom event used by the router to communicate exhausted routes
+ */
+class RouteExhausted extends Standard
+{
+}
66 lib/Proem/Api/Routing/Signal/Event/RouteMatch.php
View
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * The MIT License
+ *
+ * Copyright (c) 2010 - 2012 Tony R Quilkey <trq@proemframework.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+/**
+ * @namespace Proem\Api\Routing\Signal\Event
+ */
+namespace Proem\Api\Routing\Signal\Event;
+
+use Proem\Signal\Event\Standard,
+ Proem\Routing\Route\Payload;
+
+/**
+ * Proem\Api\Bootstrap\Signal\Event\Bootstrap
+ *
+ * A custom event used by the router to communicate matching routes
+ */
+class RouteMatch extends Standard
+{
+ /**
+ * Store the routes payload
+ */
+ private $payload;
+
+ /**
+ * Set the payload
+ *
+ * @param Proem\Dispatch\Payload $payload
+ */
+ public function setPayload(Payload $payload)
+ {
+ $this->payload = $payload;
+ return $this;
+ }
+
+ /**
+ * Retrieve the payload
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+}
76 lib/Proem/Api/Signal/Manager/Standard.php
View
@@ -50,13 +50,23 @@ class Standard implements Template
use Options;
/**
- * Stores Events in a hash of priority queues.
+ * Wildcard used when listening for all events
+ */
+ const WILDCARD = '*';
+
+ /**
+ * Stores listeners in a hash of priority queues.
*
* @var array $queues
*/
private $queues = [];
/**
+ * Store listener callbacks
+ */
+ private $callbacks = [];
+
+ /**
* Register a listener attached to a particular named Event.
*
* All listeners are store within a hash of priority queues. Each Queue contains
@@ -83,11 +93,41 @@ public function attach(array $options)
'priority' => 0
], $options);
- if (isset($this->queues[$ops->name])) {
- $this->queues[$ops->name]->insert($ops->callback, $ops->priority);
+ $key = md5(microtime());
+ $this->callbacks[$key] = $ops->callback;
+
+ if (is_array($ops->name)) {
+ foreach ($ops->name as $event) {
+ if (isset($this->queues[$event])) {
+ if ($event == self::WILDCARD) {
+ $this->queues[self::WILDCARD][] = [$key, $ops->priority];
+ } else {
+ $this->queues[$event]->insert($key, $ops->priority);
+ }
+ } else {
+ if ($event == self::WILDCARD) {
+ $this->queues[self::WILDCARD][] = [$key, $ops->priority];
+ } else {
+ $this->queues[$event] = new Queue;
+ $this->queues[$event]->insert($key, $ops->priority);
+ }
+ }
+ }
} else {
- $this->queues[$ops->name] = new Queue;
- $this->queues[$ops->name]->insert($ops->callback, $ops->priority);
+ if (isset($this->queues[$ops->name])) {
+ if ($ops->name == self::WILDCARD) {
+ $this->queues[self::WILDCARD][] = [$key, $ops->priority];
+ } else {
+ $this->queues[$ops->name]->insert($key, $ops->priority);
+ }
+ } else {
+ if ($ops->name == self::WILDCARD) {
+ $this->queues[self::WILDCARD][] = [$key, $ops->priority];
+ } else {
+ $this->queues[$ops->name] = new Queue;
+ $this->queues[$ops->name]->insert($key, $ops->priority);
+ }
+ }
}
return $this;
@@ -119,17 +159,27 @@ public function trigger(array $options)
'event' => (new Option(new Event))->object('\Proem\Signal\Event\Template')
], $options);
- if (isset($this->queues[$ops->name])) {
- foreach ($this->queues[$ops->name] as $event) {
- $eventObj = $ops->event;
- if ($eventObj instanceof \Proem\Signal\Event\Template) {
+ if (isset($this->queues[$ops->name]) || isset($this->queues[self::WILDCARD])) {
+ if (isset($this->queues[self::WILDCARD])) {
+ foreach ($this->queues[self::WILDCARD] as $listener) {
+ if (isset($this->queues[$ops->name])) {
+ $this->queues[$ops->name]->insert($listener[0], $listener[1]);
+ } else {
+ $this->queues[$ops->name] = new Queue;
+ $this->queues[$ops->name]->insert($listener[0], $listener[1]);
+ }
+ }
+ }
+ foreach ($this->queues[$ops->name] as $key) {
+ $event = $ops->event;
+ if ($event instanceof \Proem\Signal\Event\Template) {
if ($ops->has('params')) {
- $eventObj->setParams($ops->params);
+ $event->setParams($ops->params);
}
}
- $eventObj->setTarget($ops->target);
- $eventObj->setMethod($ops->method);
- if ($return = $event($eventObj)) {
+ $event->setTarget($ops->target);
+ $event->setMethod($ops->method);
+ if ($return = (new Callback($this->callbacks[$key], $event))->call()) {
if ($ops->has('callback')) {
(new Callback($ops->callback, $return))->call();
}
2  tests/lib/Proem/Tests/Ext/Fixtures/MyApp/Module/Foo.php
View
@@ -8,7 +8,7 @@ class Foo extends \Proem\Ext\Module\Generic
{
public function init(Manager $assets, $env = null) {
$assets->get('events')->attach([
- 'name' => 'pre.in.route',
+ 'name' => 'pre.in.router',
'callback' => [$this, 'loadRoutes']
]);
}
4 tests/lib/Proem/Tests/ExtTest.php
View
@@ -40,7 +40,7 @@ public function setUp()
public function testFooModuleLoads()
{
- $this->expectOutputString('Foo Module Loaded');
+ $this->expectOutputString('Foo Module Loaded<h3>404 - Page Not Found</h3>');
(new \Proem\Proem)
->attachModule(new Foo)
@@ -54,7 +54,7 @@ public function testFooModuleLoads()
*/
public function testFooModuleWontLoadWhenAttachedTooLate()
{
- $this->expectOutputString('');
+ $this->expectOutputString('<h3>404 - Page Not Found</h3>');
(new \Proem\Proem)
->attachModule(new Foo, 'post.in.route')
4 tests/lib/Proem/Tests/ProemTest.php
View
@@ -106,13 +106,13 @@ public function testBootstrap()
}
])
->attachEventListener([
- 'name' => 'pre.in.route',
+ 'name' => 'pre.in.router',
'callback' => function($e) use ($results) {
$results->triggered++;
}
])
->attachEventListener([
- 'name' => 'post.in.route',
+ 'name' => 'post.in.router',
'callback' => function($e) use ($results) {
$results->triggered++;
}
4 tests/lib/Proem/Tests/Routing/RouterTest.php
View
@@ -48,7 +48,7 @@ public function testTargetedMapedRoute()
])
)->route();
- $this->assertInstanceOf('\Proem\Dispatch\Payload', $payload);
+ $this->assertInstanceOf('\Proem\Routing\Route\Payload', $payload);
$this->assertTrue($payload->isPopulated());
$this->assertEquals('auth', $payload->controller);
$this->assertEquals('login', $payload->action);
@@ -91,7 +91,7 @@ public function testSeriesOfMappedRoutes($uri, $controller, $action)
])
)->route();
- $this->assertInstanceOf('\Proem\Dispatch\Payload', $payload);
+ $this->assertInstanceOf('\Proem\Routing\Route\Payload', $payload);
$this->assertTrue($payload->isPopulated());
$this->assertEquals($controller, $payload->controller);
$this->assertEquals($action, $payload->get('action', 'index'));
4 tests/lib/Proem/Tests/Routing/StandardRouteTest.php
View
@@ -46,7 +46,7 @@ public function testController()
$this->assertTrue($route->getPayload()->isPopulated());
$this->assertEquals('foo', $route->getPayload()->controller);
$this->assertEquals('bar', $route->getPayload()->action);
- $this->assertEquals('b', $route->getPayload()->a);
+ $this->assertEquals('b', $route->getPayload()->params['a']);
}
public function testModule()
@@ -60,7 +60,7 @@ public function testModule()
$this->assertEquals('bob', $route->getPayload()->module);
$this->assertEquals('foo', $route->getPayload()->controller);
$this->assertEquals('bar', $route->getPayload()->action);
- $this->assertEquals('b', $route->getPayload()->a);
+ $this->assertEquals('b', $route->getPayload()->params['a']);
}
public function testAnotherRoute()
34 tests/lib/Proem/Tests/SignalTest.php
View
@@ -75,6 +75,40 @@ public function testCanTriggerEventMultipleTimes()
$this->assertEquals('YesYes', $r->out);
}
+ public function testListenerCanListenToMultipleEvents()
+ {
+ $r = new \StdClass;
+ $r->out = 0;
+ (new Manager)->attach([
+ 'name' => ['a', 'b', 'c'],
+ 'callback' => function($e) use ($r) {
+ $r->out++;
+ }
+ ])
+ ->trigger(['name' => 'a'])
+ ->trigger(['name' => 'b'])
+ ->trigger(['name' => 'c']);
+
+ $this->assertEquals(3, $r->out);
+ }
+
+ public function testListenerCanListenToAllEvents()
+ {
+ $r = new \StdClass;
+ $r->out = 0;
+ (new Manager)->attach([
+ 'name' => '*',
+ 'callback' => function($e) use ($r) {
+ $r->out++;
+ }
+ ])
+ ->trigger(['name' => 'a'])
+ ->trigger(['name' => 'b'])
+ ->trigger(['name' => 'c']);
+
+ $this->assertEquals(3, $r->out);
+ }
+
public function testListenerReceivesParams()
{
$r = new \StdClass;
Please sign in to comment.
Something went wrong with that request. Please try again.