Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' of git://git.zendframework.com/zf
Browse files Browse the repository at this point in the history
  • Loading branch information
DASPRiD committed Oct 3, 2011
6 parents db42bc8 + 4579f15 + c86ed1e + 16b8f20 + 83086b6 + a81c8a5 commit a85d989
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 36 deletions.
130 changes: 98 additions & 32 deletions src/EventManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
use Zend\Stdlib\CallbackHandler,
Zend\Stdlib\Exception\InvalidCallbackException,
Zend\Stdlib\PriorityQueue,
ArrayObject;
ArrayObject,
SplPriorityQueue,
Traversable;

/**
* Event manager: notification system
Expand All @@ -53,10 +55,10 @@ class EventManager implements EventCollection
protected $eventClass = 'Zend\EventManager\Event';

/**
* Identifier, used to pull static signals from StaticEventManager
* @var null|string
* Identifiers, used to pull static signals from StaticEventManager
* @var array
*/
protected $identifier;
protected $identifiers = array();

/**
* Static connections
Expand All @@ -67,15 +69,15 @@ class EventManager implements EventCollection
/**
* Constructor
*
* Allows optionally specifying an identifier to use to pull signals from a
* Allows optionally specifying identifier(s) to use to pull signals from a
* StaticEventManager.
*
* @param null|string|int $identifier
* @param null|string|int|array|Traversable $identifiers
* @return void
*/
public function __construct($identifier = null)
public function __construct($identifiers = null)
{
$this->identifier = $identifier;
$this->setIdentifiers($identifiers);
}

/**
Expand Down Expand Up @@ -119,6 +121,48 @@ public function getStaticConnections()
return $this->staticConnections;
}

/**
* Get the identifier(s) for this EventManager
*
* @return array
*/
public function getIdentifiers()
{
return $this->identifiers;
}

/**
* Set the identifiers (overrides any currently set identifiers)
*
* @param string|int|array|Traversable $identifiers
* @return ModuleManager
*/
public function setIdentifiers($identifiers)
{
if (is_array($identifiers) || $identifiers instanceof \Traversable) {
$this->identifiers = array_unique((array) $identifiers);
} elseif ($identifiers !== null) {
$this->identifiers = array($identifiers);
}
return $this;
}

/**
* Add some identifier(s) (appends to any currently set identifiers)
*
* @param string|int|array|Traversable $identifiers
* @return ModuleManager
*/
public function addIdentifiers($identifiers)
{
if (is_array($identifiers) || $identifiers instanceof \Traversable) {
$this->identifiers = array_unique($this->identifiers + (array) $identifiers);
} elseif ($identifiers !== null) {
$this->identifiers = array_unique($this->identifiers + array($identifiers));
}
return $this;
}

/**
* Trigger all listeners for a given event
*
Expand Down Expand Up @@ -345,62 +389,84 @@ protected function triggerListeners($event, EventDescription $e, $callback)
{
$responses = new ResponseCollection;

$listeners = $this->getListeners($event);
$listeners = clone $this->getListeners($event);
foreach ($this->getStaticListeners($event) as $listener) {
$priority = $listener->getOption('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 $this->triggerStaticListeners($callback, $e, $responses);
return $responses;
}

foreach ($listeners as $listener) {
// If we have an invalid listener, detach it, and move on to the next
if (!$listener->isValid()) {
$this->detach($listener);
continue;
}

// Trigger the listener's callback, and push its result onto the
// response collection
$responses->push(call_user_func($listener->getCallback(), $e));

// If the event was asked to stop propagating, do so
if ($e->propagationIsStopped()) {
$responses->setStopped(true);
break;
}

// If the result causes our validation callback to return true,
// stop propagation
if (call_user_func($callback, $responses->last())) {
$responses->setStopped(true);
break;
}
}

if (!$responses->stopped()) {
$this->triggerStaticListeners($callback, $e, $responses);
}
return $responses;
}

/**
* Emit listeners matching the current identifier found in the static listener
*
* @param callback $callback
* @param Event $event
* @param ResponseCollection $responses
* @return ResponseCollection
* Get list of all listeners attached to the static collection for
* identifiers registered by this instance
*
* @param string $event
* @return array
*/
protected function triggerStaticListeners($callback, Event $event, ResponseCollection $responses)
protected function getStaticListeners($event)
{
if (!$staticConnections = $this->getStaticConnections()) {
return $responses;
return array();
}

$identifiers = (array) $this->identifier;
$identifiers = $this->getIdentifiers();
$staticListeners = array();

foreach ($identifiers as $id) {
if (!$listeners = $staticConnections->getListeners($id, $event->getName())) {
if (!$listeners = $staticConnections->getListeners($id, $event)) {
continue;
}

if (!is_array($listeners) && !($listeners instanceof Traversable)) {
continue;
}

foreach ($listeners as $listener) {
$responses->push(call_user_func($listener->getCallback(), $event));
if ($event->propagationIsStopped()) {
$responses->setStopped(true);
break;
}
if (call_user_func($callback, $responses->last())) {
$responses->setStopped(true);
break;
if (!$listener instanceof CallbackHandler) {
continue;
}
$staticListeners[] = $listener;
}
}

return $responses;
return $staticListeners;
}
}
2 changes: 1 addition & 1 deletion src/StaticEventManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public static function resetInstance()
* @param int $priority Priority at which listener should execute
* @return void
*/
public function attach($id, $event, $callback, $priority = 1000)
public function attach($id, $event, $callback, $priority = 1)
{
$ids = (array) $id;
foreach ($ids as $id) {
Expand Down
47 changes: 47 additions & 0 deletions test/EventManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,51 @@ public function testTriggerCanTakeAnOptionalCallbackArgumentToEmulateTriggerUnti
});
$this->assertTrue($responses->stopped());
}

public function testWeakRefsAreHonoredWhenTriggering()
{
if (!class_exists('WeakRef', false)) {
$this->markTestSkipped('Requires pecl/weakref');
}

$functor = new TestAsset\Functor;
$this->events->attach('test', $functor);

unset($functor);

$result = $this->events->trigger('test', $this, array());
$message = $result->last();
$this->assertNull($message);
}

public function testDuplicateIdentifiersAreNotRegistered()
{
$events = new EventManager(array(__CLASS__, get_class($this)));
$identifiers = $events->getIdentifiers();
$this->assertSame(count($identifiers), 1);
$this->assertSame($identifiers[0], __CLASS__);
$events->addIdentifiers(__CLASS__);
$this->assertSame(count($identifiers), 1);
$this->assertSame($identifiers[0], __CLASS__);
}

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

public function testIdentifierGetterSettersWorkWithTraversables()
{
$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'));
$this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->addIdentifiers($identifiers));
$this->assertSame($this->events->getIdentifiers(), (array) $identifiers);
}
}
25 changes: 22 additions & 3 deletions test/StaticIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function ($e) use ($counter) {
$this->assertEquals(1, $counter->count);
}

public function testLocalHandlersAreExecutedPriorToStaticHandlers()
public function testLocalHandlersAreExecutedPriorToStaticHandlersWhenSetWithSamePriority()
{
$test = (object) array('results' => array());
StaticEventManager::getInstance()->attach(
Expand All @@ -73,7 +73,7 @@ function ($e) use ($test) {
$this->assertEquals(array('local', 'static'), $test->results);
}

public function testLocalHandlersAreExecutedPriorToStaticHandlersRegardlessOfPriority()
public function testLocalHandlersAreExecutedInPriorityOrderRegardlessOfStaticOrLocalRegistration()
{
$test = (object) array('results' => array());
StaticEventManager::getInstance()->attach(
Expand All @@ -95,7 +95,7 @@ function ($e) use ($test) {
$test->results[] = 'local3';
}, 15000); // highest priority
$class->foo();
$this->assertEquals(array('local3', 'local2', 'local', 'static'), $test->results);
$this->assertEquals(array('local3', 'static', 'local2', 'local'), $test->results);
}

public function testPassingNullValueToSetStaticConnectionsDisablesStaticConnections()
Expand Down Expand Up @@ -131,4 +131,23 @@ function ($e) use ($counter) {
$class->foo();
$this->assertEquals(0, $counter->count);
}

public function testTriggerMergesPrioritiesOfStaticAndInstanceListeners()
{
$test = (object) array('results' => array());
StaticEventManager::getInstance()->attach(
'ZendTest\EventManager\TestAsset\ClassWithEvents',
'foo',
function ($e) use ($test) {
$test->results[] = 'static';
},
100
);
$class = new TestAsset\ClassWithEvents();
$class->events()->attach('foo', function ($e) use ($test) {
$test->results[] = 'local';
}, -100);
$class->foo();
$this->assertEquals(array('static', 'local'), $test->results);
}
}
11 changes: 11 additions & 0 deletions test/TestAsset/Functor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace ZendTest\EventManager\TestAsset;

class Functor
{
public function __invoke($e)
{
return __METHOD__;
}
}

0 comments on commit a85d989

Please sign in to comment.