Making the CakeEvent -> ObjectCollection bridge more intelligent, adding tests

This commit is contained in:
Jose Lorenzo Rodriguez 2011-12-25 23:17:08 -04:30
parent 7fdc1cc8d4
commit 35ecbfebde
4 changed files with 103 additions and 6 deletions

View file

@ -768,7 +768,7 @@ class ControllerTest extends CakeTestCase {
}
/**
* test that beforeRedirect callback returnning null doesn't affect things.
* test that beforeRedirect callback returning null doesn't affect things.
*
* @return void
*/
@ -790,7 +790,7 @@ class ControllerTest extends CakeTestCase {
}
/**
* test that beforeRedirect callback returnning null doesn't affect things.
* test that beforeRedirect callback returning null doesn't affect things.
*
* @return void
*/
@ -823,7 +823,7 @@ class ControllerTest extends CakeTestCase {
}
/**
* test that beforeRedirect callback returnning false in controller
* test that beforeRedirect callback returning false in controller
*
* @return void
*/
@ -833,6 +833,7 @@ class ControllerTest extends CakeTestCase {
$Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
$Controller->expects($this->once())->method('beforeRedirect')
->with('http://cakephp.org')
->will($this->returnValue(false));
$Controller->response->expects($this->never())->method('header');
$Controller->expects($this->never())->method('_stop');

View file

@ -18,6 +18,7 @@
*/
App::uses('ObjectCollection', 'Utility');
App::uses('CakeEvent', 'Event');
/**
* A generic object class
@ -525,4 +526,59 @@ class ObjectCollectionTest extends CakeTestCase {
$this->assertEquals($expected, $result);
}
/**
* tests that passing an instance of CakeEvent to trigger will prepend the subject to the list of arguments
*
* @return void
*/
public function testDispatchEventWithSubject() {
$this->_makeMockClasses();
$this->Objects->load('TriggerMockFirst');
$this->Objects->load('TriggerMockSecond');
$this->mockObjects[] = $this->Objects->TriggerMockFirst;
$this->mockObjects[] = $this->Objects->TriggerMockSecond;
$subjectClass = new Object();
$this->Objects->TriggerMockFirst->expects($this->once())
->method('callback')
->with($subjectClass, 'first argument')
->will($this->returnValue(true));
$this->Objects->TriggerMockSecond->expects($this->once())
->method('callback')
->with($subjectClass, 'first argument')
->will($this->returnValue(true));
$event = new CakeEvent('callback', $subjectClass, array('first argument'));
$this->assertTrue($this->Objects->trigger($event));
}
/**
* tests that passing an instance of CakeEvent to trigger with omitSubject property
* will NOT prepend the subject to the list of arguments
*
* @return void
*/
public function testDispatchEventNoSubject() {
$this->_makeMockClasses();
$this->Objects->load('TriggerMockFirst');
$this->Objects->load('TriggerMockSecond');
$this->mockObjects[] = $this->Objects->TriggerMockFirst;
$this->mockObjects[] = $this->Objects->TriggerMockSecond;
$subjectClass = new Object();
$this->Objects->TriggerMockFirst->expects($this->once())
->method('callback')
->with('first argument')
->will($this->returnValue(true));
$this->Objects->TriggerMockSecond->expects($this->once())
->method('callback')
->with('first argument')
->will($this->returnValue(true));
$event = new CakeEvent('callback', $subjectClass, array('first argument'));
$event->omitSubject = true;
$this->assertTrue($this->Objects->trigger($event));
}
}

View file

@ -99,8 +99,9 @@ abstract class ObjectCollection {
$event = $callback;
if (is_array($event->data)) {
$params =& $event->data;
} else {
$params = array($event->subject());
}
if (empty($event->omitSubject)) {
$subject = $event->subject();
}
//TODO: Temporary BC check, while we move all the triggers system into the CakeEventManager
foreach (array('breakOn', 'collectReturn', 'modParams') as $opt) {
@ -125,7 +126,7 @@ abstract class ObjectCollection {
throw new CakeException(__d('cake_dev', 'Cannot use modParams with indexes that do not exist.'));
}
foreach ($list as $name) {
$result = call_user_func_array(array($this->_loaded[$name], $callback), $params);
$result = call_user_func_array(array($this->_loaded[$name], $callback), compact('subject') + $params);
if ($options['collectReturn'] === true) {
$collected[] = $result;
}

View file

@ -113,4 +113,43 @@ class HelperCollection extends ObjectCollection implements CakeEventListener {
'View.afterLayout' => 'trigger'
);
}
/**
* Trigger a callback method on every object in the collection.
* Used to trigger methods on objects in the collection. Will fire the methods in the
* order they were attached.
*
* ### Options
*
* - `breakOn` Set to the value or values you want the callback propagation to stop on.
* Can either be a scalar value, or an array of values to break on. Defaults to `false`.
*
* - `break` Set to true to enabled breaking. When a trigger is broken, the last returned value
* will be returned. If used in combination with `collectReturn` the collected results will be returned.
* Defaults to `false`.
*
* - `collectReturn` Set to true to collect the return of each object into an array.
* This array of return values will be returned from the trigger() call. Defaults to `false`.
*
* - `modParams` Allows each object the callback gets called on to modify the parameters to the next object.
* Setting modParams to an integer value will allow you to modify the parameter with that index.
* Any non-null value will modify the parameter index indicated.
* Defaults to false.
*
*
* @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.
* @throws CakeException when modParams is used with an index that does not exist.
*/
public function trigger($callback, $params = array(), $options = array()) {
if ($callback instanceof CakeEvent) {
$callback->omitSubject = true;
}
return parent::trigger($callback, $params, $options);
}
}