Skip to content

Commit

Permalink
[zendframework#40] Implement wildcard support in the EventManager
Browse files Browse the repository at this point in the history
- Allows $events->attach('*', $callback) to specify a listener that
  should be triggered for every event.
  • Loading branch information
weierophinney committed Mar 13, 2012
1 parent 23f1e50 commit 4f225ed
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
37 changes: 34 additions & 3 deletions library/Zend/EventManager/EventManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,24 +254,30 @@ public function triggerUntil($event, $target, $argv = null, $callback = null)
* executed. By default, this value is 1; however, you may set it for any
* integer value. Higher values have higher priority (i.e., execute first).
*
* You can specify "*" for the event name. In such cases, the listener will
* be triggered for every event.
*
* @param string|array|ListenerAggregate $event An event or array of event names. If a ListenerAggregate, proxies to {@link attachAggregate()}.
* @param callback|int $callback If string $event provided, expects PHP callback; for a ListenerAggregate $event, this will be the priority
* @param int $priority If provided, the priority at which to register the callback
* @return CallbackHandler|mixed CallbackHandler if attaching callback (to allow later unsubscribe); mixed if attaching aggregate
*/
public function attach($event, $callback = null, $priority = 1)
{
// Proxy ListenerAggregate arguments to attachAggregate()
if ($event instanceof ListenerAggregate) {
return $this->attachAggregate($event, $callback);
}

// Null callback is invalid
if (null === $callback) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: expects a callback; none provided',
__METHOD__
));
}

// Array of events should be registered individually, and return an array of all listeners
if (is_array($event)) {
$listeners = array();
foreach ($event as $name) {
Expand All @@ -280,10 +286,15 @@ public function attach($event, $callback = null, $priority = 1)
return $listeners;
}

// If we don't have a priority queue for the event yet, create one
if (empty($this->events[$event])) {
$this->events[$event] = new PriorityQueue();
}

// Create a callback handler, setting the event and priority in its metadata
$listener = new CallbackHandler($callback, array('event' => $event, 'priority' => $priority));

// Inject the callback handler into the queue
$this->events[$event]->insert($listener, $priority);
return $listener;
}
Expand Down Expand Up @@ -421,11 +432,16 @@ protected function triggerListeners($event, EventDescription $e, $callback = nul
$responses = new ResponseCollection;
$listeners = $this->getListeners($event);

// add static listeners to the list of listeners
// Add static/wildcard listeners to the list of listeners,
// but don't modify the listeners object
$staticListeners = $this->getStaticListeners($event);
if (count($staticListeners)) {
$staticListeners = $this->getStaticListeners($event);
$wildcardListeners = $this->getListeners('*');
if (count($staticListeners) || count($wildcardListeners)) {
$listeners = clone $listeners;
}

// Add static listeners
if (count($staticListeners)) {
foreach ($staticListeners as $listener) {
$priority = $listener->getMetadatum('priority');
if (null === $priority) {
Expand All @@ -439,6 +455,21 @@ protected function triggerListeners($event, EventDescription $e, $callback = nul
}
}

// Add wildcard listeners
if (count($wildcardListeners)) {
foreach ($wildcardListeners as $listener) {
$priority = $listener->getMetadatum('priority');
if (null === $priority) {
$priority = 1;
} elseif (is_array($priority)) {
// If we have an array, likely using PriorityQueue. Grab first
// element of the array, as that's the actual priority.
$priority = array_shift($priority);
}
$listeners->insert($listener, $priority);
}
}

if ($listeners->isEmpty()) {
return $responses;
}
Expand Down
23 changes: 20 additions & 3 deletions tests/Zend/EventManager/EventManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

namespace ZendTest\EventManager;

use Zend\EventManager\Event,
use ArrayIterator,
stdClass,
Zend\EventManager\Event,
Zend\EventManager\EventDescription,
Zend\EventManager\EventManager,
Zend\EventManager\ResponseCollection,
Expand Down Expand Up @@ -570,11 +572,26 @@ public function testIdentifierGetterSettersWorkWithArrays()

public function testIdentifierGetterSettersWorkWithTraversables()
{
$identifiers = new \ArrayIterator(array('foo', 'bar'));
$identifiers = new ArrayIterator(array('foo', 'bar'));
$this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->setIdentifiers($identifiers));
$this->assertSame($this->events->getIdentifiers(), (array) $identifiers);
$identifiers = new \ArrayIterator(array('foo', 'bar', 'baz'));
$identifiers = new ArrayIterator(array('foo', 'bar', 'baz'));
$this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->addIdentifiers($identifiers));
$this->assertSame($this->events->getIdentifiers(), (array) $identifiers);
}

public function testListenersAttachedWithWildcardAreTriggeredForAllEvents()
{
$test = new stdClass;
$test->events = array();
$callback = function($e) use ($test) {
$test->events[] = $e->getName();
};

$this->events->attach('*', $callback);
foreach (array('foo', 'bar', 'baz') as $event) {
$this->events->trigger($event);
$this->assertContains($event, $test->events);
}
}
}

0 comments on commit 4f225ed

Please sign in to comment.