Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Migrating Controller events to use the CakeEventManager

  • Loading branch information...
commit 5d67195bf7e82fc9911984be1c6bbac9c87c494c 1 parent 0a49bd9
@lorenzo lorenzo authored
View
20 lib/Cake/Controller/ComponentCollection.php
@@ -18,6 +18,7 @@
App::uses('ObjectCollection', 'Utility');
App::uses('Component', 'Controller');
+App::uses('CakeEventListener', 'Event');
/**
* Components collection is used as a registry for loaded components and handles loading
@@ -25,7 +26,7 @@
*
* @package Cake.Controller
*/
-class ComponentCollection extends ObjectCollection {
+class ComponentCollection extends ObjectCollection implements CakeEventListener {
/**
* The controller that this collection was initialized with.
@@ -108,4 +109,21 @@ public function load($component, $settings = array()) {
return $this->_loaded[$alias];
}
+/**
+ * Returns the implemented events that will get routed to the trigger function
+ * in order to dispatch them separately on each component
+ *
+ * @return array
+ */
+ public function implementedEvents() {
+ return array(
+ 'Controller.startup' => array(
+ array('callable' => 'trigger', 'priority' => 9),
+ array('callable' => 'trigger')
+ ),
+ 'Controller.beforeRender' => array('callable' => 'trigger'),
+ 'Controller.beforeRedirect' => array('callable' => 'trigger'),
+ 'Controller.shutdown' => array('callable' => 'trigger', 'priority' => 9),
+ );
+ }
}
View
54 lib/Cake/Controller/Controller.php
@@ -24,6 +24,9 @@
App::uses('ClassRegistry', 'Utility');
App::uses('ComponentCollection', 'Controller');
App::uses('View', 'View');
+App::uses('CakeEvent', 'Event');
+App::uses('CakeEventListener', 'Event');
+App::uses('CakeEventManager', 'Event');
/**
* Application controller class for organization of business logic.
@@ -57,7 +60,7 @@
* @property SessionComponent $Session
* @link http://book.cakephp.org/2.0/en/controllers.html
*/
-class Controller extends Object {
+class Controller extends Object implements CakeEventListener {
/**
* The name of this controller. Controller names are plural, named after the model they manipulate.
@@ -295,6 +298,14 @@ class Controller extends Object {
protected $_mergeParent = 'AppController';
/**
+ * Instance of the CakeEventManager this controller is using
+ * to dispatch inner events.
+ *
+ * @var CakeEventManager
+ */
+ protected $_eventManager = null;
+
+/**
* Constructor.
*
* @param CakeRequest $request Request object for this controller. Can be null for testing,
@@ -571,6 +582,21 @@ protected function _mergeControllerVars() {
}
/**
+ * Returns a list of all events that will fire in the controller during it's lifecycle.
+ * You can override this function to add you own listener callbacks
+ *
+ * @return array
+ */
+ public function implementedEvents() {
+ return array(
+ 'Controller.startup' => 'beforeFilter',
+ 'Controller.beforeRender' => 'beforeRender',
+ 'Controller.beforeRedirect' => array('callable' => 'beforeRedirect', 'passParams' => true),
+ 'Controller.shutdown' => 'afterFilter'
+ );
+ }
+
+/**
* Loads Model classes based on the uses property
* see Controller::loadModel(); for more info.
* Loads Components and prepares them for initialization.
@@ -591,6 +617,22 @@ public function constructClasses() {
}
/**
+ * Returns the CakeEventManager manager instance that is handling any callbacks.
+ * You can use this instance to register any new listeners or callbacks to the
+ * controller events, or create your own events and trigger them at will.
+ *
+ * @return CakeEventManager
+ */
+ public function getEventManager() {
+ if (empty($this->_eventManager)) {
+ $this->_eventManager = new CakeEventManager();
+ $this->_eventManager->attach($this);
+ $this->_eventManager->attach($this->Components);
+ }
+ return $this->_eventManager;
+ }
+
+/**
* Perform the startup process for this controller.
* Fire the Components and Controller callbacks in the correct order.
*
@@ -601,9 +643,7 @@ public function constructClasses() {
* @return void
*/
public function startupProcess() {
- $this->Components->trigger('initialize', array(&$this));
- $this->beforeFilter();
- $this->Components->trigger('startup', array(&$this));
+ $this->getEventManager()->dispatch(new CakeEvent('Controller.startup', $this));
}
/**
@@ -616,8 +656,7 @@ public function startupProcess() {
* @return void
*/
public function shutdownProcess() {
- $this->Components->trigger('shutdown', array(&$this));
- $this->afterFilter();
+ $this->getEventManager()->dispatch(new CakeEvent('Controller.shutdown', $this));
}
/**
@@ -862,8 +901,7 @@ public function validateErrors() {
* @link http://book.cakephp.org/2.0/en/controllers.html#Controller::render
*/
public function render($view = null, $layout = null) {
- $this->beforeRender();
- $this->Components->trigger('beforeRender', array(&$this));
+ $this->getEventManager()->dispatch(new CakeEvent('Controller.beforeRender', $this));
$viewClass = $this->viewClass;
if ($this->viewClass != 'View') {
View
71 lib/Cake/Test/Case/Controller/ControllerTest.php
@@ -313,7 +313,7 @@ public function beforeRedirect() {
*
* @return void
*/
- public function initialize(&$controller) {
+ public function initialize($controller) {
}
/**
@@ -321,7 +321,7 @@ public function initialize(&$controller) {
*
* @return void
*/
- public function startup(&$controller) {
+ public function startup($controller) {
}
/**
@@ -329,7 +329,7 @@ public function startup(&$controller) {
*
* @return void
*/
- public function shutdown(&$controller) {
+ public function shutdown($controller) {
}
/**
@@ -337,7 +337,7 @@ public function shutdown(&$controller) {
*
* @return void
*/
- public function beforeRender(&$controller) {
+ public function beforeRender($controller) {
if ($this->viewclass) {
$controller->viewClass = $this->viewclass;
}
@@ -1111,17 +1111,35 @@ public function testControllerHttpCodes() {
* @return void
*/
public function testStartupProcess() {
- $Controller = $this->getMock('Controller', array('beforeFilter', 'afterFilter'));
+ $Controller = $this->getMock('Controller', array('getEventManager'));
+
+ $eventManager = $this->getMock('CakeEventManager');
+ $eventManager->expects($this->once())->method('dispatch')
+ ->with(
+ $this->logicalAnd(
+ $this->isInstanceOf('CakeEvent'),
+ $this->attributeEqualTo('_name', 'Controller.startup'),
+ $this->attributeEqualTo('_subject', $Controller)
+ )
+ );
+ $Controller->expects($this->once())->method('getEventManager')
+ ->will($this->returnValue($eventManager));
+ $Controller->startupProcess();
+ }
- $Controller->components = array('MockStartup');
- $Controller->Components = $this->getMock('ComponentCollection');
+/**
+ * Tests that the shutdown process calls the correct functions
+ *
+ * @return void
+ */
+ public function testStartupProcessIndirect() {
+ $Controller = $this->getMock('Controller', array('beforeFilter'));
- $Controller->expects($this->once())->method('beforeFilter');
- $Controller->Components->expects($this->at(0))->method('trigger')
- ->with('initialize', array(&$Controller));
+ $Controller->components = array('MockShutdown');
+ $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
- $Controller->Components->expects($this->at(1))->method('trigger')
- ->with('startup', array(&$Controller));
+ $Controller->expects($this->once())->method('beforeFilter');
+ $Controller->Components->expects($this->exactly(2))->method('trigger')->with($this->isInstanceOf('CakeEvent'));
$Controller->startupProcess();
}
@@ -1132,14 +1150,35 @@ public function testStartupProcess() {
* @return void
*/
public function testShutdownProcess() {
- $Controller = $this->getMock('Controller', array('beforeFilter', 'afterFilter'));
+ $Controller = $this->getMock('Controller', array('getEventManager'));
+
+ $eventManager = $this->getMock('CakeEventManager');
+ $eventManager->expects($this->once())->method('dispatch')
+ ->with(
+ $this->logicalAnd(
+ $this->isInstanceOf('CakeEvent'),
+ $this->attributeEqualTo('_name', 'Controller.shutdown'),
+ $this->attributeEqualTo('_subject', $Controller)
+ )
+ );
+ $Controller->expects($this->once())->method('getEventManager')
+ ->will($this->returnValue($eventManager));
+ $Controller->shutdownProcess();
+ }
+
+/**
+ * Tests that the shutdown process calls the correct functions
+ *
+ * @return void
+ */
+ public function testShutdownProcessIndirect() {
+ $Controller = $this->getMock('Controller', array('afterFilter'));
$Controller->components = array('MockShutdown');
- $Controller->Components = $this->getMock('ComponentCollection');
+ $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
$Controller->expects($this->once())->method('afterFilter');
- $Controller->Components->expects($this->once())->method('trigger')
- ->with('shutdown', array(&$Controller));
+ $Controller->Components->expects($this->exactly(1))->method('trigger')->with($this->isInstanceOf('CakeEvent'));
$Controller->shutdownProcess();
}
View
13 lib/Cake/Utility/ObjectCollection.php
@@ -82,8 +82,10 @@
* Defaults to false.
*
*
- * @param string $callback Method to fire on all the objects. Its assumed all the objects implement
- * the method you are calling.
+ * @param string $callback|CakeEvent Method to fire on all the objects. Its assumed all the objects implement
+ * the method you are calling. If an instance of CakeEvent is provided, then then Event name will parsed to
+ * get the callback name. This is done by getting the last word after any dot in the event name
+ * (eg. `Model.afterSave` event will trigger the `afterSave` callback)
* @param array $params Array of parameters for the triggered callback.
* @param array $options Array of options.
* @return mixed Either the last result or all results if collectReturn is on.
@@ -93,6 +95,13 @@ public function trigger($callback, $params = array(), $options = array()) {
if (empty($this->_enabled)) {
return true;
}
+ if ($callback instanceof CakeEvent) {
+ if (is_array($callback->data)) {
+ $params = $callback->data;
+ }
+ $params = array($callback->subject());
@majna
majna added a note

Missing else {} here?

@lorenzo Owner
lorenzo added a note

The code changed quite a bit after this commit :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ $callback = array_pop(explode('.', $callback->name()));
+ }
$options = array_merge(
array(
'break' => false,
Please sign in to comment.
Something went wrong with that request. Please try again.