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

This commit is contained in:
Jose Lorenzo Rodriguez 2011-12-26 13:06:48 -04:30
parent 35ecbfebde
commit 1651257919
6 changed files with 104 additions and 65 deletions

View file

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

View file

@ -20,6 +20,7 @@
*/ */
App::uses('ObjectCollection', 'Utility'); App::uses('ObjectCollection', 'Utility');
App::uses('CakeEventListener', 'Event');
/** /**
* Model behavior collection class. * Model behavior collection class.
@ -28,7 +29,7 @@ App::uses('ObjectCollection', 'Utility');
* *
* @package Cake.Model * @package Cake.Model
*/ */
class BehaviorCollection extends ObjectCollection { class BehaviorCollection extends ObjectCollection implements CakeEventListener {
/** /**
* Stores a reference to the attached name * Stores a reference to the attached name
@ -271,4 +272,21 @@ class BehaviorCollection extends ObjectCollection {
return false; 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'
);
}
} }

View file

@ -27,6 +27,9 @@ App::uses('BehaviorCollection', 'Model');
App::uses('ModelBehavior', 'Model'); App::uses('ModelBehavior', 'Model');
App::uses('ConnectionManager', 'Model'); App::uses('ConnectionManager', 'Model');
App::uses('Xml', 'Utility'); App::uses('Xml', 'Utility');
App::uses('CakeEvent', 'Event');
App::uses('CakeEventListener', 'Event');
App::uses('CakeEventManager', 'Event');
/** /**
* Object-relational mapper. * Object-relational mapper.
@ -39,7 +42,7 @@ App::uses('Xml', 'Utility');
* @package Cake.Model * @package Cake.Model
* @link http://book.cakephp.org/2.0/en/models.html * @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 * The name of the DataSource connection that this Model uses
@ -607,6 +610,14 @@ class Model extends Object {
'neighbors' => true, 'list' => true, 'threaded' => true 'neighbors' => true, 'list' => true, 'threaded' => true
); );
/**
* 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. * Constructor. Binds the model's database table to the object.
* *
@ -712,6 +723,40 @@ class Model extends Object {
$this->Behaviors->init($this->alias, $this->actsAs); $this->Behaviors->init($this->alias, $this->actsAs);
} }
/**
* 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, * Handles custom method calls, like findBy<field> for DB models,
* and custom RPC calls for remote data sources. * and custom RPC calls for remote data sources.
@ -1585,10 +1630,10 @@ class Model extends Object {
} }
if ($options['callbacks'] === true || $options['callbacks'] === 'before') { if ($options['callbacks'] === true || $options['callbacks'] === 'before') {
$result = $this->Behaviors->trigger('beforeSave', array(&$this, $options), array( $event = new CakeEvent('Model.beforeSave', $this, array($options));
'break' => true, 'breakOn' => array(false, null) list($event->break, $event->breakOn) = array(true, array(false, null));
)); $this->getEventManager()->dispatch($event);
if (!$result || !$this->beforeSave($options)) { if (!$event->result) {
$this->whitelist = $_whitelist; $this->whitelist = $_whitelist;
return false; return false;
} }
@ -1672,8 +1717,8 @@ class Model extends Object {
} }
} }
if ($options['callbacks'] === true || $options['callbacks'] === 'after') { if ($options['callbacks'] === true || $options['callbacks'] === 'after') {
$this->Behaviors->trigger('afterSave', array(&$this, $created, $options)); $event = new CakeEvent('Model.afterSave', $this, array($created, $options));
$this->afterSave($created); $this->getEventManager()->dispatch($event);
} }
if (!empty($this->data)) { if (!empty($this->data)) {
$success = Set::merge($success, $this->data); $success = Set::merge($success, $this->data);
@ -2236,13 +2281,11 @@ class Model extends Object {
} }
$id = $this->id; $id = $this->id;
if ($this->beforeDelete($cascade)) { $event = new CakeEvent('Model.beforeDelete', $this, array($cascade));
$filters = $this->Behaviors->trigger( list($event->break, $event->breakOn) = array(true, array(false, null));
'beforeDelete', $this->getEventManager()->dispatch($event);
array(&$this, $cascade), if (!$event->isStopped()) {
array('break' => true, 'breakOn' => array(false, null)) if (!$this->exists()) {
);
if (!$filters || !$this->exists()) {
return false; return false;
} }
$db = $this->getDataSource(); $db = $this->getDataSource();
@ -2272,8 +2315,7 @@ class Model extends Object {
if ($updateCounterCache) { if ($updateCounterCache) {
$this->updateCounterCache($keys[$this->alias]); $this->updateCounterCache($keys[$this->alias]);
} }
$this->Behaviors->trigger('afterDelete', array(&$this)); $this->getEventManager()->dispatch(new CakeEvent('Model.afterDelete', $this));
$this->afterDelete();
$this->_clearCache(); $this->_clearCache();
$this->id = false; $this->id = false;
return true; return true;
@ -2566,24 +2608,13 @@ class Model extends Object {
$query['order'] = array($query['order']); $query['order'] = array($query['order']);
if ($query['callbacks'] === true || $query['callbacks'] === 'before') { if ($query['callbacks'] === true || $query['callbacks'] === 'before') {
$return = $this->Behaviors->trigger( $event = new CakeEvent('Model.beforeFind', $this, array($query));
'beforeFind', list($event->break, $event->breakOn, $event->modParams) = array(true, array(false, null), 0);
array(&$this, $query), $this->getEventManager()->dispatch($event);
array('break' => true, 'breakOn' => array(false, null), 'modParams' => 1) if ($event->isStopped()) {
);
$query = (is_array($return)) ? $return : $query;
if ($return === false) {
return null;
}
$return = $this->beforeFind($query);
$query = (is_array($return)) ? $return : $query;
if ($return === false) {
return null; return null;
} }
$query = $event->data[0];
} }
return $query; return $query;
@ -2814,15 +2845,10 @@ class Model extends Object {
* @return array Set of filtered results * @return array Set of filtered results
*/ */
protected function _filterResults($results, $primary = true) { protected function _filterResults($results, $primary = true) {
$return = $this->Behaviors->trigger( $event = new CakeEvent('Model.afterFind', $this, array($results, $primary));
'afterFind', $event->modParams = 0;
array(&$this, $results, $primary), $this->getEventManager()->dispatch($event);
array('modParams' => 1) return $event->result;
);
if ($return !== true) {
$results = $return;
}
return $this->afterFind($results, $primary);
} }
/** /**
@ -2936,14 +2962,10 @@ class Model extends Object {
* @see Model::validates() * @see Model::validates()
*/ */
public function invalidFields($options = array()) { public function invalidFields($options = array()) {
if ( $event = new CakeEvent('Model.beforeValidate', $this, array($options));
!$this->Behaviors->trigger( list($event->break, $event->breakOn) = array(true, false);
'beforeValidate', $this->getEventManager()->dispatch($event);
array(&$this, $options), if ($event->isStopped()) {
array('break' => true, 'breakOn' => false)
) ||
$this->beforeValidate($options) === false
) {
return false; return false;
} }

View file

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

View file

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

View file

@ -104,7 +104,7 @@ abstract class ObjectCollection {
$subject = $event->subject(); $subject = $event->subject();
} }
//TODO: Temporary BC check, while we move all the triggers system into the CakeEventManager //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})) { if (isset($event->{$opt})) {
$options[$opt] = $event->{$opt}; $options[$opt] = $event->{$opt};
} }