Skip to content

Fixed an error in EventDispatcher::disconnect, Added support for "global" event listeners with $name = null #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 38 additions & 16 deletions src/Symfony/Component/EventDispatcher/EventDispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class EventDispatcher
/**
* Connects a listener to a given event name.
*
* @param string $name An event name
* @param mixed $listener A PHP callable
* @param integer $priority The priority (between -10 and 10 -- defaults to 0)
* @param string|null $name An event name or null to make the listener listen to all events
* @param mixed $listener A PHP callable
* @param integer $priority The priority (between -10 and 10 -- defaults to 0)
*/
public function connect($name, $listener, $priority = 0)
{
Expand All @@ -40,17 +40,22 @@ public function connect($name, $listener, $priority = 0)
/**
* Disconnects a listener for a given event name.
*
* @param string $name An event name
* @param mixed|null $listener A PHP callable or null to disconnect all listeners
* @param string|null $name An event name or null to disconnect a global listener
* @param mixed|null $listener A PHP callable or null to disconnect all listeners
*
* @return mixed false if listener does not exist, null otherwise
*/
public function disconnect($name, $listener = null)
public function disconnect($name=null, $listener = null)
{
if (!isset($this->listeners[$name])) {
return false;
}

if (null === $listener) {
unset($this->listeners[$name]);
return;
}

foreach ($this->listeners[$name] as $priority => $callables) {
foreach ($callables as $i => $callable) {
if ($listener === $callable) {
Expand All @@ -69,7 +74,7 @@ public function disconnect($name, $listener = null)
*/
public function notify(Event $event)
{
foreach ($this->getListeners($event->getName()) as $listener) {
foreach ($this->getListeners($event->getName(), true) as $listener) {
call_user_func($listener, $event);
}

Expand All @@ -85,7 +90,7 @@ public function notify(Event $event)
*/
public function notifyUntil(Event $event)
{
foreach ($this->getListeners($event->getName()) as $listener) {
foreach ($this->getListeners($event->getName(), true) as $listener) {
if (call_user_func($listener, $event)) {
$event->setProcessed(true);
break;
Expand All @@ -105,7 +110,7 @@ public function notifyUntil(Event $event)
*/
public function filter(Event $event, $value)
{
foreach ($this->getListeners($event->getName()) as $listener) {
foreach ($this->getListeners($event->getName(), true) as $listener) {
$value = call_user_func($listener, $event, $value);
}

Expand All @@ -117,30 +122,47 @@ public function filter(Event $event, $value)
/**
* Returns true if the given event name has some listeners.
*
* @param string $name The event name
* @param string $name The event name
* @param boolean $includeGlobals Flag whether the global listeners
* (name=null) should be included
*
* @return Boolean true if some listeners are connected, false otherwise
*/
public function hasListeners($name)
public function hasListeners($name, $includeGlobals=false)
{
return (Boolean) count($this->getListeners($name));
return (Boolean) count($this->getListeners($name, $includeGlobals));
}

/**
* Returns all listeners associated with a given event name.
*
* @param string $name The event name
*
* @param string $name The event name
* @param boolean $includeGlobals Flag whether the global listeners
* (name=null) should be included
* @return array An array of listeners
*/
public function getListeners($name)
public function getListeners($name, $includeGlobals=false)
{
if (!isset($this->listeners[$name])) {
return array();
}

$listeners = array();
$all = $this->listeners[$name];

// add global listeners if required and existing, but only if the
// it's not global collection which is requested
if (isset($this->listeners[null]) && $includeGlobals && $name != null) {
foreach ($this->listeners[null] as $prio => $globalListeners) {
if (isset($all[$prio])) {
$all[$prio] = array_merge($all[$prio], $globalListeners);
} else {
$all[$prio] = $globalListeners;
}
}
}

// sort with respect to priority and flatten array
ksort($all);
foreach ($all as $l) {
$listeners = array_merge($listeners, $l);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public function testConnectAndDisconnect()
$this->assertEquals(array('listenToBarBar'), $dispatcher->getListeners('barbar'), '->disconnect() disconnects a listener for an event name');

$this->assertFalse($dispatcher->disconnect('foobar', 'listen'), '->disconnect() returns false if the listener does not exist');

$dispatcher->disconnect('bar');
$this->assertEquals(array(), $dispatcher->getListeners('bar'), '->disconnect() without a listener disconnects all listeners of for an event name');
$this->assertEquals(array('listenToBarBar'), $dispatcher->getListeners('barbar'), '->disconnect() without a listener disconnects all listeners of for an event name');
}

public function testGetHasListeners()
Expand Down Expand Up @@ -100,6 +104,22 @@ public function testFilter()
$e = $dispatcher->filter($event = new Event(new \stdClass(), 'foo'), 'foo');
$this->assertEquals('*-foo-*', $e->getReturnValue(), '->filter() filters a value');
}

public function testGlobalConnectAndDisconnect()
{
$dispatcher = new EventDispatcher();
$dispatcher->connect('bar', 'listenToBar');
$dispatcher->connect('barbar', 'listenToBar');
$dispatcher->connect(null, 'listenToBarBar');
$this->assertEquals(array('listenToBar', 'listenToBarBar'), $dispatcher->getListeners('bar', true), '->connect() with event name null connects a global listener (1)');
$this->assertEquals(array('listenToBar', 'listenToBarBar'), $dispatcher->getListeners('barbar', true), '->connect() with event name null connects a global listener (2)');
$this->assertEquals(array('listenToBar'), $dispatcher->getListeners('bar', false), '->connect() with event name null connects a global listener (3)');
$this->assertEquals(array('listenToBar'), $dispatcher->getListeners('barbar', false), '->connect() with event name null connects a global listener (4)');

$dispatcher->disconnect(null, 'listenToBarBar');
$this->assertEquals(array('listenToBar'), $dispatcher->getListeners('bar', true), '->disconnect() with event name null disconnects a global listener');
}

}

class Listener
Expand Down