Browse Source

Migrating all model callbacks to the CakeEventManager, fixing some minor bugs. All tests passing again

Jose Lorenzo Rodriguez 14 years ago
parent
commit
1651257919

+ 2 - 3
lib/Cake/Controller/Controller.php

@@ -732,9 +732,8 @@ class Controller extends Object implements CakeEventListener {
 			extract($status, EXTR_OVERWRITE);
 		}
 		$event = new CakeEvent('Controller.beforeRedirect', $this, array($url, $status, $exit));
-		//TODO: Remove the following two lines when the events are fully migrated to the CakeEventManager
-		$event->breakOn = false;
-		$event->collectReturn = true;
+		//TODO: Remove the following line when the events are fully migrated to the CakeEventManager
+		list($event->break, $event->breakOn, $event->collectReturn) = array(true, false, true);
 		$this->getEventManager()->dispatch($event);
 
 		if ($event->isStopped()) {

+ 19 - 1
lib/Cake/Model/BehaviorCollection.php

@@ -20,6 +20,7 @@
  */
 
 App::uses('ObjectCollection', 'Utility');
+App::uses('CakeEventListener', 'Event');
 
 /**
  * Model behavior collection class.
@@ -28,7 +29,7 @@ App::uses('ObjectCollection', 'Utility');
  *
  * @package       Cake.Model
  */
-class BehaviorCollection extends ObjectCollection {
+class BehaviorCollection extends ObjectCollection implements CakeEventListener {
 
 /**
  * Stores a reference to the attached name
@@ -271,4 +272,21 @@ class BehaviorCollection extends ObjectCollection {
 		return false;
 	}
 
+/**
+ * Returns the implemented events that will get routed to the trigger function
+ * in order to dispatch them separately on each behavior
+ *
+ * @return array
+ */
+	public function implementedEvents() {
+		return array(
+			'Model.beforeFind' => 'trigger',
+			'Model.afterFind' => 'trigger',
+			'Model.beforeValidate' => 'trigger',
+			'Model.beforeSave' => 'trigger',
+			'Model.afterSave' => 'trigger',
+			'Model.beforeDelete' => 'trigger',
+			'Model.afterDelete' => 'trigger'
+		);
+	}
 }

+ 71 - 49
lib/Cake/Model/Model.php

@@ -27,6 +27,9 @@ App::uses('BehaviorCollection', 'Model');
 App::uses('ModelBehavior', 'Model');
 App::uses('ConnectionManager', 'Model');
 App::uses('Xml', 'Utility');
+App::uses('CakeEvent', 'Event');
+App::uses('CakeEventListener', 'Event');
+App::uses('CakeEventManager', 'Event');
 
 /**
  * Object-relational mapper.
@@ -39,7 +42,7 @@ App::uses('Xml', 'Utility');
  * @package       Cake.Model
  * @link          http://book.cakephp.org/2.0/en/models.html
  */
-class Model extends Object {
+class Model extends Object implements CakeEventListener {
 
 /**
  * The name of the DataSource connection that this Model uses
@@ -608,6 +611,14 @@ class Model extends Object {
 	);
 
 /**
+ * Instance of the CakeEventManager this model is using
+ * to dispatch inner events.
+ *
+ * @var CakeEventManager
+ */
+	protected $_eventManager = null;
+
+/**
  * Constructor. Binds the model's database table to the object.
  *
  * If `$id` is an array it can be used to pass several options into the model.
@@ -713,6 +724,40 @@ class Model extends Object {
 	}
 
 /**
+ * Returns a list of all events that will fire in the model during it's lifecycle.
+ * You can override this function to add you own listener callbacks
+ *
+ * @return array
+ */
+	public function implementedEvents() {
+		return array(
+			'Model.beforeFind' => array('callable' => 'beforeFind', 'passParams' => true),
+			'Model.afterFind' => array('callable' => 'afterFind', 'passParams' => true),
+			'Model.beforeValidate' => array('callable' => 'beforeValidate', 'passParams' => true),
+			'Model.beforeSave' => array('callable' => 'beforeSave', 'passParams' => true),
+			'Model.afterSave' => array('callable' => 'afterSave', 'passParams' => true),
+			'Model.beforeDelete' => array('callable' => 'beforeDelete', 'passParams' => true, 'priority' => 9),
+			'Model.afterDelete' => array('callable' => 'afterDelete'),
+		);
+	}
+
+/**
+ * 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->Behaviors);
+			$this->_eventManager->attach($this);
+		}
+		return $this->_eventManager;
+	}
+
+/**
  * Handles custom method calls, like findBy<field> for DB models,
  * and custom RPC calls for remote data sources.
  *
@@ -1585,10 +1630,10 @@ class Model extends Object {
 		}
 
 		if ($options['callbacks'] === true || $options['callbacks'] === 'before') {
-			$result = $this->Behaviors->trigger('beforeSave', array(&$this, $options), array(
-				'break' => true, 'breakOn' => array(false, null)
-			));
-			if (!$result || !$this->beforeSave($options)) {
+			$event = new CakeEvent('Model.beforeSave', $this, array($options));
+			list($event->break, $event->breakOn) = array(true, array(false, null));
+			$this->getEventManager()->dispatch($event);
+			if (!$event->result) {
 				$this->whitelist = $_whitelist;
 				return false;
 			}
@@ -1672,8 +1717,8 @@ class Model extends Object {
 				}
 			}
 			if ($options['callbacks'] === true || $options['callbacks'] === 'after') {
-				$this->Behaviors->trigger('afterSave', array(&$this, $created, $options));
-				$this->afterSave($created);
+				$event = new CakeEvent('Model.afterSave', $this, array($created, $options));
+				$this->getEventManager()->dispatch($event);
 			}
 			if (!empty($this->data)) {
 				$success = Set::merge($success, $this->data);
@@ -2236,13 +2281,11 @@ class Model extends Object {
 		}
 		$id = $this->id;
 
-		if ($this->beforeDelete($cascade)) {
-			$filters = $this->Behaviors->trigger(
-				'beforeDelete',
-				array(&$this, $cascade),
-				array('break' => true, 'breakOn' => array(false, null))
-			);
-			if (!$filters || !$this->exists()) {
+		$event = new CakeEvent('Model.beforeDelete', $this, array($cascade));
+		list($event->break, $event->breakOn) = array(true, array(false, null));
+		$this->getEventManager()->dispatch($event);
+		if (!$event->isStopped()) {
+			if (!$this->exists()) {
 				return false;
 			}
 			$db = $this->getDataSource();
@@ -2272,8 +2315,7 @@ class Model extends Object {
 				if ($updateCounterCache) {
 					$this->updateCounterCache($keys[$this->alias]);
 				}
-				$this->Behaviors->trigger('afterDelete', array(&$this));
-				$this->afterDelete();
+				$this->getEventManager()->dispatch(new CakeEvent('Model.afterDelete', $this));
 				$this->_clearCache();
 				$this->id = false;
 				return true;
@@ -2566,24 +2608,13 @@ class Model extends Object {
 		$query['order'] = array($query['order']);
 
 		if ($query['callbacks'] === true || $query['callbacks'] === 'before') {
-			$return = $this->Behaviors->trigger(
-				'beforeFind',
-				array(&$this, $query),
-				array('break' => true, 'breakOn' => array(false, null), 'modParams' => 1)
-			);
-
-			$query = (is_array($return)) ? $return : $query;
-
-			if ($return === false) {
-				return null;
-			}
-
-			$return = $this->beforeFind($query);
-			$query = (is_array($return)) ? $return : $query;
-
-			if ($return === false) {
+			$event = new CakeEvent('Model.beforeFind', $this, array($query));
+			list($event->break, $event->breakOn, $event->modParams) = array(true, array(false, null), 0);
+			$this->getEventManager()->dispatch($event);
+			if ($event->isStopped()) {
 				return null;
 			}
+			$query = $event->data[0];
 		}
 
 		return $query;
@@ -2814,15 +2845,10 @@ class Model extends Object {
  * @return array Set of filtered results
  */
 	protected function _filterResults($results, $primary = true) {
-		$return = $this->Behaviors->trigger(
-			'afterFind',
-			array(&$this, $results, $primary),
-			array('modParams' => 1)
-		);
-		if ($return !== true) {
-			$results = $return;
-		}
-		return $this->afterFind($results, $primary);
+		$event = new CakeEvent('Model.afterFind', $this, array($results, $primary));
+		$event->modParams = 0;
+		$this->getEventManager()->dispatch($event);
+		return $event->result;
 	}
 
 /**
@@ -2936,14 +2962,10 @@ class Model extends Object {
  * @see Model::validates()
  */
 	public function invalidFields($options = array()) {
-		if (
-			!$this->Behaviors->trigger(
-				'beforeValidate',
-				array(&$this, $options),
-				array('break' => true, 'breakOn' => false)
-			) ||
-			$this->beforeValidate($options) === false
-		) {
+		$event = new CakeEvent('Model.beforeValidate', $this, array($options));
+		list($event->break, $event->breakOn) = array(true, false);
+		$this->getEventManager()->dispatch($event);
+		if ($event->isStopped()) {
 			return false;
 		}
 

+ 10 - 10
lib/Cake/Test/Case/Model/BehaviorCollectionTest.php

@@ -859,31 +859,31 @@ class BehaviorCollectionTest extends CakeTestCase {
 
 		$Sample->Behaviors->attach('Test', array('beforeSave' => 'on'));
 		$Sample->create();
-		$this->assertSame($Sample->save($record), false);
+		$this->assertSame(false, $Sample->save($record));
 
 		$Sample->Behaviors->attach('Test', array('beforeSave' => 'off'));
 		$Sample->create();
 		$result = $Sample->save($record);
 		$expected = $record;
 		$expected['Sample']['id'] = $Sample->id;
-		$this->assertSame($result, $expected);
+		$this->assertSame($expected, $result);
 
 		$Sample->Behaviors->attach('Test', array('beforeSave' => 'test'));
 		$Sample->create();
 		$result = $Sample->save($record);
 		$expected = $record;
 		$expected['Sample']['id'] = $Sample->id;
-		$this->assertSame($result, $expected);
+		$this->assertSame($expected, $result);
 
 		$Sample->Behaviors->attach('Test', array('beforeSave' => 'modify'));
 		$expected = Set::insert($record, 'Sample.name', 'sample99 modified before');
 		$Sample->create();
 		$result = $Sample->save($record);
 		$expected['Sample']['id'] = $Sample->id;
-		$this->assertSame($result, $expected);
+		$this->assertSame($expected, $result);
 
 		$Sample->Behaviors->disable('Test');
-		$this->assertSame($Sample->save($record), $record);
+		$this->assertSame($record, $Sample->save($record));
 
 		$Sample->Behaviors->attach('Test', array('beforeSave' => 'off', 'afterSave' => 'on'));
 		$expected = Set::merge($record, array('Sample' => array('aftersave' => 'modified after on create')));
@@ -897,21 +897,21 @@ class BehaviorCollectionTest extends CakeTestCase {
 		$Sample->create();
 		$result = $Sample->save($record);
 		$expected['Sample']['id'] = $Sample->id;
-		$this->assertSame($result, $expected);
+		$this->assertSame($expected, $result);
 
 		$Sample->Behaviors->attach('Test', array('beforeSave' => 'off', 'afterSave' => 'test'));
 		$Sample->create();
 		$expected = $record;
 		$result = $Sample->save($record);
 		$expected['Sample']['id'] = $Sample->id;
-		$this->assertSame($result, $expected);
+		$this->assertSame($expected, $result);
 
 		$Sample->Behaviors->attach('Test', array('afterSave' => 'test2'));
 		$Sample->create();
 		$expected = $record;
 		$result = $Sample->save($record);
 		$expected['Sample']['id'] = $Sample->id;
-		$this->assertSame($result, $expected);
+		$this->assertSame($expected, $result);
 
 		$Sample->Behaviors->attach('Test', array('beforeFind' => 'off', 'afterFind' => 'off'));
 		$Sample->recursive = -1;
@@ -920,12 +920,12 @@ class BehaviorCollectionTest extends CakeTestCase {
 		$Sample->Behaviors->attach('Test', array('afterSave' => 'on'));
 		$expected = Set::merge($record2, array('Sample' => array('aftersave' => 'modified after')));
 		$Sample->create();
-		$this->assertSame($Sample->save($record2), $expected);
+		$this->assertSame($expected, $Sample->save($record2));
 
 		$Sample->Behaviors->attach('Test', array('afterSave' => 'modify'));
 		$expected = Set::merge($record2, array('Sample' => array('name' => 'sample1 modified after')));
 		$Sample->create();
-		$this->assertSame($Sample->save($record2), $expected);
+		$this->assertSame($expected, $Sample->save($record2));
 	}
 
 /**

+ 1 - 1
lib/Cake/Test/Case/Model/ModelReadTest.php

@@ -5041,7 +5041,7 @@ class ModelReadTest extends BaseModelTest {
  * @return void
  */
 	public function testCallbackSourceChangeUnknownDatasource() {
-		$this->loadFixtures('Post');
+		$this->loadFixtures('Post', 'Author');
 		$TestModel = new Post();
 		$this->assertFalse($TestModel->find('all', array('connection' => 'foo')));
 	}

+ 1 - 1
lib/Cake/Utility/ObjectCollection.php

@@ -104,7 +104,7 @@ abstract class ObjectCollection {
 				$subject = $event->subject();
 			}
 			//TODO: Temporary BC check, while we move all the triggers system into the CakeEventManager
-			foreach (array('breakOn', 'collectReturn', 'modParams') as $opt) {
+			foreach (array('break', 'breakOn', 'collectReturn', 'modParams') as $opt) {
 				if (isset($event->{$opt})) {
 					$options[$opt] = $event->{$opt};
 				}