Skip to content

Commit

Permalink
Clean up Event system.
Browse files Browse the repository at this point in the history
* Remove passParams. This option is now enabled always implicitly. You
  cannot turn it off.
* Update Event class to make data protected and expose data() method.
* Update tests.

This change simplifies the event system a bit and removes additional
mostly useless configuration.
  • Loading branch information
markstory committed Jul 3, 2013
1 parent acf6949 commit 63b9b68
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 67 deletions.
33 changes: 20 additions & 13 deletions lib/Cake/Event/Event.php
@@ -1,6 +1,5 @@
<?php
/**
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
Expand All @@ -10,11 +9,11 @@
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Observer
* @since CakePHP(tm) v 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Observer
* @since CakePHP(tm) v 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Event;

Expand Down Expand Up @@ -46,7 +45,7 @@ class Event {
*
* @var mixed $data
*/
public $data = null;
protected $_data = null;

/**
* Property used to retain the result value of the event listeners
Expand All @@ -65,21 +64,20 @@ class Event {
/**
* Constructor
*
* @param string $name Name of the event
* @param object $subject the object that this event applies to (usually the object that is generating the event)
* @param mixed $data any value you wish to be transported with this event to it can be read by listeners
*
* ## Examples of usage:
*
* {{{
* $event = new Event('Order.afterBuy', $this, array('buyer' => $userData));
* $event = new Event('User.afterRegister', $UserModel);
* }}}
*
* @param string $name Name of the event
* @param object $subject the object that this event applies to (usually the object that is generating the event)
* @param array $data any value you wish to be transported with this event to it can be read by listeners
*/
public function __construct($name, $subject = null, $data = null) {
$this->_name = $name;
$this->data = $data;
$this->_data = $data;
$this->_subject = $subject;
}

Expand All @@ -90,7 +88,7 @@ public function __construct($name, $subject = null, $data = null) {
* @return mixed
*/
public function __get($attribute) {
if ($attribute === 'name' || $attribute === 'subject') {
if ($attribute === 'data' || $attribute === 'name' || $attribute === 'subject') {
return $this->{$attribute}();
}
}
Expand Down Expand Up @@ -131,4 +129,13 @@ public function isStopped() {
return $this->_stopped;
}

/**
* Access the event data/payload.
*
* @return array
*/
public function data() {
return (array)$this->_data;
}

}
16 changes: 8 additions & 8 deletions lib/Cake/Event/EventManager.php
Expand Up @@ -82,7 +82,7 @@ public static function instance($manager = null) {
}

/**
* Adds a new listener to an event. Listeners
* Adds a new listener to an event.
*
* @param callback|Cake\Event\EventListener $callable PHP valid callback type or instance of Cake\Event\EventListener to be called
* when the event named with $eventKey is triggered. If a Cake\Event\EventListener instance is passed, then the `implementedEvents`
Expand All @@ -92,10 +92,9 @@ public static function instance($manager = null) {
* @param string $eventKey The event unique identifier name with which the callback will be associated. If $callable
* is an instance of Cake\Event\EventListener this argument will be ignored
*
* @param array $options used to set the `priority` and `passParams` flags to the listener.
* @param array $options used to set the `priority` flag to the listener. In the future more options may be added.
* Priorities are handled like queues, and multiple attachments added to the same priority queue will be treated in
* the order of insertion. `passParams` means that the event data property will be converted to function arguments
* when the listener is called. If $called is an instance of Cake\Event\EventListener, this parameter will be ignored
* the order of insertion.
*
* @return void
* @throws InvalidArgumentException When event key is missing or callable is not an
Expand All @@ -109,10 +108,9 @@ public function attach($callable, $eventKey = null, $options = array()) {
$this->_attachSubscriber($callable);
return;
}
$options = $options + array('priority' => static::$defaultPriority, 'passParams' => false);
$options = $options + array('priority' => static::$defaultPriority);
$this->_listeners[$eventKey][$options['priority']][] = array(
'callable' => $callable,
'passParams' => $options['passParams'],
);
}

Expand Down Expand Up @@ -243,8 +241,10 @@ public function dispatch($event) {
if ($event->isStopped()) {
break;
}
if ($listener['passParams'] === true) {
$result = call_user_func_array($listener['callable'], $event->data);
$data = $event->data();
if ($data !== null) {
array_unshift($data, $event);
$result = call_user_func_array($listener['callable'], $data);
} else {
$result = call_user_func($listener['callable'], $event);
}
Expand Down
83 changes: 37 additions & 46 deletions lib/Cake/Test/TestCase/Event/EventManagerTest.php
@@ -1,9 +1,5 @@
<?php
/**
* ControllerTestCaseTest file
*
* Test Case for ControllerTestCase class
*
* PHP 5
*
* CakePHP : Rapid Development Framework (http://cakephp.org)
Expand All @@ -13,11 +9,11 @@
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP Project
* @package Cake.Test.Case.Event
* @since CakePHP v 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP Project
* @package Cake.Test.Case.Event
* @since CakePHP v 2.1
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\TestCase\Event;

Expand Down Expand Up @@ -75,7 +71,7 @@ class CustomTestEventListerner extends EventTestListener implements EventListene
public function implementedEvents() {
return array(
'fake.event' => 'listenerFunction',
'another.event' => array('callable' => 'secondListenerFunction', 'passParams' => true),
'another.event' => array('callable' => 'secondListenerFunction'),
'multiple.handlers' => array(
array('callable' => 'listenerFunction'),
array('callable' => 'thirdListenerFunction')
Expand Down Expand Up @@ -109,12 +105,12 @@ public function testAttachListeners() {
$manager = new EventManager;
$manager->attach('fakeFunction', 'fake.event');
$expected = array(
array('callable' => 'fakeFunction', 'passParams' => false)
array('callable' => 'fakeFunction')
);
$this->assertEquals($expected, $manager->listeners('fake.event'));

$manager->attach('fakeFunction2', 'fake.event');
$expected[] = array('callable' => 'fakeFunction2', 'passParams' => false);
$expected[] = array('callable' => 'fakeFunction2');
$this->assertEquals($expected, $manager->listeners('fake.event'));

$manager->attach('inQ5', 'fake.event', array('priority' => 5));
Expand All @@ -123,9 +119,9 @@ public function testAttachListeners() {

$expected = array_merge(
array(
array('callable' => 'inQ1', 'passParams' => false),
array('callable' => 'inQ5', 'passParams' => false),
array('callable' => 'otherInQ5', 'passParams' => false)
array('callable' => 'inQ1'),
array('callable' => 'inQ5'),
array('callable' => 'otherInQ5')
),
$expected
);
Expand All @@ -141,15 +137,15 @@ public function testAttachMultipleEventKeys() {
$manager = new EventManager;
$manager->attach('fakeFunction', 'fake.event');
$manager->attach('fakeFunction2', 'another.event');
$manager->attach('fakeFunction3', 'another.event', array('priority' => 1, 'passParams' => true));
$manager->attach('fakeFunction3', 'another.event', array('priority' => 1));
$expected = array(
array('callable' => 'fakeFunction', 'passParams' => false)
array('callable' => 'fakeFunction')
);
$this->assertEquals($expected, $manager->listeners('fake.event'));

$expected = array(
array('callable' => 'fakeFunction3', 'passParams' => true),
array('callable' => 'fakeFunction2', 'passParams' => false)
array('callable' => 'fakeFunction3'),
array('callable' => 'fakeFunction2')
);
$this->assertEquals($expected, $manager->listeners('another.event'));
}
Expand All @@ -170,7 +166,7 @@ public function testDetach() {

$manager->detach(array('AClass', 'anotherMethod'), 'another.event');
$expected = array(
array('callable' => 'fakeFunction', 'passParams' => false)
array('callable' => 'fakeFunction')
);
$this->assertEquals($expected, $manager->listeners('another.event'));

Expand All @@ -191,7 +187,7 @@ public function testDetachFromAll() {

$manager->detach(array('AClass', 'aMethod'));
$expected = array(
array('callable' => 'fakeFunction', 'passParams' => false)
array('callable' => 'fakeFunction')
);
$this->assertEquals($expected, $manager->listeners('another.event'));
$this->assertEquals(array(), $manager->listeners('fake.event'));
Expand Down Expand Up @@ -302,50 +298,45 @@ public function testDispatchPrioritized() {
$this->assertEquals($expected, $listener->callStack);
}

/**
* Tests event dispatching with passed params
*
* @return void
*/
public function testDispatchPassingParams() {
$manager = new EventManager;
$listener = $this->getMock(__NAMESPACE__ . '\EventTestListener');
$anotherListener = $this->getMock(__NAMESPACE__ . '\EventTestListener');
$manager->attach(array($listener, 'listenerFunction'), 'fake.event');
$manager->attach(array($anotherListener, 'secondListenerFunction'), 'fake.event', array('passParams' => true));
$event = new Event('fake.event', $this, array('some' => 'data'));

$listener->expects($this->once())->method('listenerFunction')->with($event);
$anotherListener->expects($this->once())->method('secondListenerFunction')->with('data');
$manager->dispatch($event);
}

/**
* Tests subscribing a listener object and firing the events it subscribed to
*
* @return void
*/
public function testAttachSubscriber() {
$manager = new EventManager;
$manager = new EventManager();
$listener = $this->getMock(__NAMESPACE__ . '\CustomTestEventListerner', array('secondListenerFunction'));
$manager->attach($listener);
$event = new Event('fake.event');

$event = new Event('fake.event');
$manager->dispatch($event);

$expected = array('listenerFunction');
$this->assertEquals($expected, $listener->callStack);

$listener->expects($this->at(0))->method('secondListenerFunction')->with('data');
$event = new Event('another.event', $this, array('some' => 'data'));
$listener->expects($this->at(0))
->method('secondListenerFunction')
->with($event, 'data');
$manager->dispatch($event);
}

/**
* Test implementedEvents binding multiple callbacks to the same event name.
*
* @return void
*/
public function testAttachSubscriberMultiple() {
$manager = new EventManager;
$listener = $this->getMock(__NAMESPACE__ . '\CustomTestEventListerner', array('listenerFunction', 'thirdListenerFunction'));
$manager->attach($listener);
$event = new Event('multiple.handlers');
$listener->expects($this->once())->method('listenerFunction')->with($event);
$listener->expects($this->once())->method('thirdListenerFunction')->with($event);
$listener->expects($this->once())
->method('listenerFunction')
->with($event);
$listener->expects($this->once())
->method('thirdListenerFunction')
->with($event);
$manager->dispatch($event);
}

Expand All @@ -359,11 +350,11 @@ public function testDetachSubscriber() {
$listener = $this->getMock(__NAMESPACE__ . '\CustomTestEventListerner', array('secondListenerFunction'));
$manager->attach($listener);
$expected = array(
array('callable' => array($listener, 'secondListenerFunction'), 'passParams' => true)
array('callable' => array($listener, 'secondListenerFunction'))
);
$this->assertEquals($expected, $manager->listeners('another.event'));
$expected = array(
array('callable' => array($listener, 'listenerFunction'), 'passParams' => false)
array('callable' => array($listener, 'listenerFunction'))
);
$this->assertEquals($expected, $manager->listeners('fake.event'));
$manager->detach($listener);
Expand Down

0 comments on commit 63b9b68

Please sign in to comment.