Browse Source

Migrating View and Helpers events to use the CakeEvenManager

Jose Lorenzo Rodriguez 14 years ago
parent
commit
078a2dfd72

+ 61 - 11
lib/Cake/Test/Case/View/ViewTest.php

@@ -584,24 +584,74 @@ class ViewTest extends CakeTestCase {
 		$View->Helpers = $this->getMock('HelperCollection', array('trigger'), array($View));
 
 		$View->Helpers->expects($this->at(0))->method('trigger')
-			->with('beforeRender', $this->anything());
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.beforeRender'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
 		$View->Helpers->expects($this->at(1))->method('trigger')
-			->with('beforeRenderFile', $this->anything());
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.beforeRenderFile'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
+
 		$View->Helpers->expects($this->at(2))->method('trigger')
-			->with('afterRenderFile', $this->anything())
-			->will($this->returnValue(''));
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.afterRenderFile'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
 		$View->Helpers->expects($this->at(3))->method('trigger')
-			->with('afterRender', $this->anything());
-
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.afterRender'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
+			
 		$View->Helpers->expects($this->at(4))->method('trigger')
-			->with('beforeLayout', $this->anything());
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.beforeLayout'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
+
 		$View->Helpers->expects($this->at(5))->method('trigger')
-			->with('beforeRenderFile', $this->anything());
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.beforeRenderFile'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
+
 		$View->Helpers->expects($this->at(6))->method('trigger')
-			->with('afterRenderFile', $this->anything())
-			->will($this->returnValue('')) ;
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.afterRenderFile'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
+
 		$View->Helpers->expects($this->at(7))->method('trigger')
-			->with('afterLayout', $this->anything());
+			->with(
+				$this->logicalAnd(
+					$this->isInstanceOf('CakeEvent'),
+					$this->attributeEqualTo('_name', 'View.afterLayout'),
+					$this->attributeEqualTo('_subject', $View)
+				)
+			);
 
 		$View->render('index');
 	}

+ 10 - 4
lib/Cake/Utility/ObjectCollection.php

@@ -96,11 +96,17 @@ abstract class ObjectCollection {
 			return true;
 		}
 		if ($callback instanceof CakeEvent) {
-			if (is_array($callback->data)) {
-				$params = $callback->data;
+			$event = $callback;
+			if (is_array($event->data)) {
+				$params =& $event->data;
+			} else {
+				$params = array($event->subject());
 			}
-			$params = array($callback->subject());
-			$callback = array_pop(explode('.', $callback->name()));
+			//TODO: Temporary BC check, while we move all the triggers system into the CakeEventManager
+			if (isset($event->modParams)) {
+				$options['modParams'] = $event->modParams;
+			}
+			$callback = array_pop(explode('.', $event->name()));
 		}
 		$options = array_merge(
 			array(

+ 17 - 1
lib/Cake/View/HelperCollection.php

@@ -17,6 +17,7 @@
  */
 
 App::uses('ObjectCollection', 'Utility');
+App::uses('CakeEventListener', 'Event');
 
 /**
  * Helpers collection is used as a registry for loaded helpers and handles loading
@@ -24,7 +25,7 @@ App::uses('ObjectCollection', 'Utility');
  *
  * @package       Cake.View
  */
-class HelperCollection extends ObjectCollection {
+class HelperCollection extends ObjectCollection implements CakeEventListener {
 
 /**
  * View object to use when making helpers.
@@ -97,4 +98,19 @@ class HelperCollection extends ObjectCollection {
 		return $this->_loaded[$alias];
 	}
 
+/**
+ * Returns a list of all events that will fire in the View during it's lifecycle.
+ *
+ * @return array
+ */
+	public function implementedEvents() {
+		return array(
+			'View.beforeRenderFile' => 'trigger',
+			'View.afterRenderFile' => 'trigger',
+			'View.beforeRender' => 'trigger',
+			'View.afterRender' => 'trigger',
+			'View.beforeLayout' => 'trigger',
+			'View.afterLayout' => 'trigger'
+		);
+	}
 }

+ 48 - 15
lib/Cake/View/View.php

@@ -21,6 +21,8 @@ App::uses('HelperCollection', 'View');
 App::uses('AppHelper', 'View/Helper');
 App::uses('Router', 'Routing');
 App::uses('ViewBlock', 'View');
+App::uses('CakeEvent', 'Event');
+App::uses('CakeEventManager', 'Event');
 
 /**
  * View, the V in the MVC triad. View interacts with Helpers and view variables passed
@@ -262,6 +264,23 @@ class View extends Object {
  */
 	protected $_stack = array();
 
+/**
+ * Instance of the CakeEventManager this View object is using
+ * to dispatch inner events. Usually the manager is shared with
+ * the controller, so it it possible to register view events in
+ * the controller layer.
+ *
+ * @var CakeEventManager
+ */
+	protected $_eventManager = null;
+
+/**
+ * Whether the event manager was already configured for this object
+ *
+ * @var boolean
+ */
+	protected $_eventManagerConfigured = false;
+
 	const TYPE_VIEW = 'view';
 	const TYPE_ELEMENT = 'element';
 	const TYPE_LAYOUT = 'layout';
@@ -278,6 +297,7 @@ class View extends Object {
 				$var = $this->_passedVars[$j];
 				$this->{$var} = $controller->{$var};
 			}
+			$this->_eventManager = $controller->getEventManager();
 		}
 		$this->Helpers = new HelperCollection($this);
 		$this->Blocks = new ViewBlock();
@@ -285,6 +305,22 @@ class View extends Object {
 	}
 
 /**
+ * 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->_eventManagerConfigured) {
+			$this->_eventManager = new CakeEventManager();
+			$this->_eventManager->attach($this->Helpers);
+			$this->_eventManagerConfigured = true;
+		}
+		return $this->_eventManager;
+	}
+
+/**
  * Renders a piece of PHP with provided parameters and returns HTML, XML, or any other string.
  *
  * This realizes the concept of Elements, (or "partial layouts") and the $params array is used to send
@@ -347,14 +383,14 @@ class View extends Object {
 				$this->loadHelpers();
 			}
 			if ($callbacks) {
-				$this->Helpers->trigger('beforeRender', array($file));
+				$this->getEventManager()->dispatch(new CakeEvent('View.beforeRender', $this, array($file)));
 			}
 
 			$this->_currentType = self::TYPE_ELEMENT;
 			$element = $this->_render($file, array_merge($this->viewVars, $data));
 
 			if ($callbacks) {
-				$this->Helpers->trigger('afterRender', array($file, $element));
+				$this->getEventManager()->dispatch(new CakeEvent('View.afterRender', $this, array($file, $element)));
 			}
 			if (isset($options['cache'])) {
 				Cache::write($key, $element, $caching['config']);
@@ -397,9 +433,9 @@ class View extends Object {
 
 		if ($view !== false && $viewFileName = $this->_getViewFileName($view)) {
 			$this->_currentType = self::TYPE_VIEW;
-			$this->Helpers->trigger('beforeRender', array($viewFileName));
+			$this->getEventManager()->dispatch(new CakeEvent('View.beforeRender', $this, array($viewFileName)));
 			$this->Blocks->set('content', $this->_render($viewFileName));
-			$this->Helpers->trigger('afterRender', array($viewFileName));
+			$this->getEventManager()->dispatch(new CakeEvent('View.afterRender', $this, array($viewFileName)));
 		}
 
 		if ($layout === null) {
@@ -447,7 +483,7 @@ class View extends Object {
 		if (empty($content)) {
 			$content = $this->Blocks->get('content');
 		}
-		$this->Helpers->trigger('beforeLayout', array($layoutFileName));
+		$this->getEventManager()->dispatch(new CakeEvent('View.beforeLayout', $this, array($layoutFileName)));
 
 		$scripts = implode("\n\t", $this->_scripts);
 		$scripts .= $this->get('meta') . $this->get('css') . $this->get('script');
@@ -464,7 +500,7 @@ class View extends Object {
 		$this->_currentType = self::TYPE_LAYOUT;
 		$this->Blocks->set('content', $this->_render($layoutFileName));
 
-		$this->Helpers->trigger('afterLayout', array($layoutFileName));
+		$this->getEventManager()->dispatch(new CakeEvent('View.afterLayout', $this, array($layoutFileName)));
 		return $this->Blocks->get('content');
 	}
 
@@ -768,19 +804,16 @@ class View extends Object {
 		}
 		$this->_current = $viewFile;
 
-		$this->Helpers->trigger('beforeRenderFile', array($viewFile));
+		$this->getEventManager()->dispatch(new CakeEvent('View.beforeRenderFile', $this, array($viewFile)));
 		$content = $this->_evaluate($viewFile, $data);
 		if ($this->Blocks->active()) {
 			throw new CakeException(__d('cake_dev', 'The "%s" block was left open.', $this->Blocks->active()));
 		}
-		$result = $this->Helpers->trigger(
-			'afterRenderFile',
-			array($viewFile, $content),
-			array('modParams' => 1)
-		);
-		if ($result !== true) {
-			$content = $result;
-		}
+		$afterEvent = new CakeEvent('View.afterRenderFile', $this, array($viewFile, $content));
+		//TODO: For BC puporses, set extra info in the event object. Remove when appropriate
+		$afterEvent->modParams = 1;
+		$this->getEventManager()->dispatch($afterEvent);
+		$content = $afterEvent->data[1];
 
 		if (isset($this->_parents[$viewFile])) {
 			$this->_stack[] = $this->fetch('content');