Implemented priority based triggering of callbacks for objects in collection

This commit is contained in:
ADmad 2011-11-07 03:30:17 +05:30
parent 02912b6eeb
commit 90b007ef75
7 changed files with 213 additions and 44 deletions

View file

@ -75,10 +75,6 @@ class TaskCollection extends ObjectCollection {
$this->_loaded[$name] = new $taskClass(
$this->_Shell->stdout, $this->_Shell->stderr, $this->_Shell->stdin
);
$enable = isset($settings['enabled']) ? $settings['enabled'] : true;
if ($enable === true) {
$this->_enabled[] = $name;
}
return $this->_loaded[$name];
}

View file

@ -96,8 +96,8 @@ class ComponentCollection extends ObjectCollection {
}
$this->_loaded[$alias] = new $componentClass($this, $settings);
$enable = isset($settings['enabled']) ? $settings['enabled'] : true;
if ($enable === true) {
$this->_enabled[] = $alias;
if ($enable) {
$this->enable($alias);
}
return $this->_loaded[$alias];
}

View file

@ -165,10 +165,10 @@ class BehaviorCollection extends ObjectCollection {
}
}
$configDisabled = isset($config['enabled']) && $config['enabled'] === false;
if (!in_array($alias, $this->_enabled) && !$configDisabled) {
$enable = isset($config['enabled']) ? $config['enabled'] : true;
if ($enable) {
$this->enable($alias);
} elseif ($configDisabled) {
} else {
$this->disable($alias);
}
return true;
@ -184,14 +184,13 @@ class BehaviorCollection extends ObjectCollection {
list($plugin, $name) = pluginSplit($name);
if (isset($this->_loaded[$name])) {
$this->_loaded[$name]->cleanup(ClassRegistry::getObject($this->modelName));
unset($this->_loaded[$name]);
parent::unload($name);
}
foreach ($this->_methods as $m => $callback) {
if (is_array($callback) && $callback[0] == $name) {
unset($this->_methods[$m]);
}
}
$this->_enabled = array_values(array_diff($this->_enabled, (array)$name));
}
/**

View file

@ -53,22 +53,8 @@ class TaskCollectionTest extends CakeTestCase {
$result = $this->Tasks->attached();
$this->assertEquals(array('DbConfig'), $result, 'attached() results are wrong.');
$this->assertTrue($this->Tasks->enabled('DbConfig'));
}
/**
* test load and enable = false
*
* @return void
*/
public function testLoadWithEnableFalse() {
$result = $this->Tasks->load('DbConfig', array('enabled' => false));
$this->assertInstanceOf('DbConfigTask', $result);
$this->assertInstanceOf('DbConfigTask', $this->Tasks->DbConfig);
$this->assertFalse($this->Tasks->enabled('DbConfig'), 'DbConfigTask should be disabled');
}
/**
* test missingtask exception
*

View file

@ -23,6 +23,16 @@ App::uses('ObjectCollection', 'Utility');
* A generic object class
*/
class GenericObject {
/**
* Constructor
*
* @param GenericObjectCollection $collection
* @param array $settings
*/
public function __construct(GenericObjectCollection $collection, $settings = array()) {
$this->_Collection = $collection;
$this->settings = $settings;
}
}
/**
@ -44,6 +54,14 @@ class SecondGenericObject extends GenericObject {
}
}
/**
* Third Extension of Generic Object
*/
class ThirdGenericObject extends GenericObject {
public function callback() {
}
}
/**
* A collection of Generic objects
*/
@ -65,7 +83,7 @@ class GenericObjectCollection extends ObjectCollection {
$this->_loaded[$name] = new $objectClass($this, $settings);
$enable = isset($settings['enabled']) ? $settings['enabled'] : true;
if ($enable === true) {
$this->_enabled[] = $name;
$this->enable($name);
}
return $this->_loaded[$name];
}
@ -143,10 +161,10 @@ class ObjectCollectionTest extends CakeTestCase {
$result = $this->Objects->attached();
$this->assertEquals(array('First'), $result, 'loaded objects are wrong');
$result = $this->Objects->set('First', new SecondGenericObject());
$result = $this->Objects->set('First', new SecondGenericObject($this->Objects));
$this->assertInstanceOf('SecondGenericObject', $result['First'], 'set failed');
$result = $this->Objects->set('Second', new SecondGenericObject());
$result = $this->Objects->set('Second', new SecondGenericObject($this->Objects));
$this->assertInstanceOf('SecondGenericObject', $result['Second'], 'set failed');
$this->assertEquals(count($result), 2);
@ -164,6 +182,9 @@ class ObjectCollectionTest extends CakeTestCase {
if (!class_exists('TriggerMockSecondGenericObject')) {
$this->getMock('SecondGenericObject', array(), array(), 'TriggerMockSecondGenericObject', false);
}
if (!class_exists('TriggerMockThirdGenericObject')) {
$this->getMock('ThirdGenericObject', array(), array(), 'TriggerMockThirdGenericObject', false);
}
}
/**
@ -358,6 +379,118 @@ class ObjectCollectionTest extends CakeTestCase {
$this->assertEquals(array('new value'), $result);
}
/**
* test order of callbacks trigerring based on priority.
*
* @return void
*/
public function testTriggerPriority() {
$this->_makeMockClasses();
$this->Objects->load('TriggerMockFirst');
$this->Objects->load('TriggerMockSecond', array('priority' => 5));
$this->mockObjects[] = $this->Objects->TriggerMockFirst;
$this->mockObjects[] = $this->Objects->TriggerMockSecond;
$this->Objects->TriggerMockFirst->expects($this->any())
->method('callback')
->will($this->returnValue('1st'));
$this->Objects->TriggerMockSecond->expects($this->any())
->method('callback')
->will($this->returnValue('2nd'));
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'1st'
);
$this->assertEquals($expected, $result);
$this->Objects->load('TriggerMockThird', array('priority' => 7));
$this->mockObjects[] = $this->Objects->TriggerMockThird;
$this->Objects->TriggerMockThird->expects($this->any())
->method('callback')
->will($this->returnValue('3rd'));
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'3rd',
'1st'
);
$this->assertEquals($expected, $result);
$this->Objects->disable('TriggerMockFirst');
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'3rd'
);
$this->assertEquals($expected, $result);
$this->Objects->enable('TriggerMockFirst');
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'3rd',
'1st'
);
$this->assertEquals($expected, $result);
$this->Objects->disable('TriggerMockThird');
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'1st'
);
$this->assertEquals($expected, $result);
$this->Objects->enable('TriggerMockThird', false);
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'1st',
'3rd'
);
$this->assertEquals($expected, $result);
$this->Objects->setPriority('TriggerMockThird', 1);
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'3rd',
'2nd',
'1st'
);
$this->assertEquals($expected, $result);
$this->Objects->disable('TriggerMockThird');
$this->Objects->setPriority('TriggerMockThird', 11);
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'1st'
);
$this->assertEquals($expected, $result);
$this->Objects->enable('TriggerMockThird');
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'1st',
'3rd'
);
$this->assertEquals($expected, $result);
$this->Objects->setPriority('TriggerMockThird');
$result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
$expected = array(
'2nd',
'1st',
'3rd'
);
$this->assertEquals($expected, $result);
}
/**
* test normalizeObjectArray
*

View file

@ -39,6 +39,13 @@ abstract class ObjectCollection {
*/
protected $_loaded = array();
/**
* Default object priority. A non zero integer.
*
* @var int
*/
public $defaultPriority = 10;
/**
* Loads a new object onto the collection. Can throw a variety of exceptions
*
@ -95,7 +102,7 @@ abstract class ObjectCollection {
$options
);
$collected = array();
$list = $this->_enabled;
$list = array_keys($this->_enabled);
if ($options['modParams'] !== false && !isset($params[$options['modParams']])) {
throw new CakeException(__d('cake_dev', 'Cannot use modParams with indexes that do not exist.'));
}
@ -145,30 +152,77 @@ abstract class ObjectCollection {
/**
* Enables callbacks on an object or array of objects
*
* @param mixed $name CamelCased name of the object(s) to enable (string or array)
* @param string|array $name CamelCased name of the object(s) to enable (string or array)
* @param boolean Prioritize enabled list after enabling object(s)
* @return void
*/
public function enable($name) {
public function enable($name, $prioritize = true) {
$enabled = false;
foreach ((array)$name as $object) {
if (isset($this->_loaded[$object]) && array_search($object, $this->_enabled) === false) {
$this->_enabled[] = $object;
if (isset($this->_loaded[$object]) && !isset($this->_enabled[$object])) {
$priority = isset($this->_loaded[$object]->settings['priority']) ? $this->_loaded[$object]->settings['priority'] : $this->defaultPriority;
$this->_enabled[$object] = array($priority);
$enabled = true;
}
}
if ($prioritize && $enabled) {
$this->prioritize();
}
}
/**
* Prioritize list of enabled object
*
* @return array Prioritized list of object
*/
public function prioritize() {
$i = 1;
foreach ($this->_enabled as $name => $priority) {
$priority[1] = $i++;
$this->_enabled[$name] = $priority;
}
asort($this->_enabled);
return $this->_enabled;
}
/**
* Set priority for an object or array of objects
*
* @param string|array $name CamelCased name of the object(s) to enable (string or array)
* If string the second param $priority is used else it should be an associative array
* with keys as object names and values as priorities to set.
* @param int|null Integer priority to set or null for default
* @return void
*/
public function setPriority($name, $priority = null) {
if (is_string($name)) {
$name = array($name => $priority);
}
foreach ($name as $obj => $prio) {
if (isset($this->_loaded[$obj])) {
if (is_null($prio)) {
$prio = $this->defaultPriority;
}
$this->_loaded[$obj]->settings['priority'] = $prio;
if (isset($this->_enabled[$obj])) {
$this->_enabled[$obj] = array($prio);
}
}
}
$this->prioritize();
}
/**
* Disables callbacks on a object or array of objects. Public object methods are still
* callable as normal.
*
* @param mixed $name CamelCased name of the objects(s) to disable (string or array)
* @param string|array $name CamelCased name of the objects(s) to disable (string or array)
* @return void
*/
public function disable($name) {
foreach ((array)$name as $object) {
$index = array_search($object, $this->_enabled);
unset($this->_enabled[$index]);
unset($this->_enabled[$object]);
}
$this->_enabled = array_values($this->_enabled);
}
/**
@ -181,9 +235,9 @@ abstract class ObjectCollection {
*/
public function enabled($name = null) {
if (!empty($name)) {
return in_array($name, $this->_enabled);
return isset($this->_enabled[$name]);
}
return $this->_enabled;
return array_keys($this->_enabled);
}
/**
@ -210,7 +264,7 @@ abstract class ObjectCollection {
public function unload($name) {
list($plugin, $name) = pluginSplit($name);
unset($this->_loaded[$name]);
$this->_enabled = array_values(array_diff($this->_enabled, (array)$name));
unset($this->_enabled[$name]);
}
/**
@ -248,4 +302,5 @@ abstract class ObjectCollection {
}
return $normal;
}
}
}

View file

@ -85,10 +85,10 @@ class HelperCollection extends ObjectCollection {
$this->_loaded[$alias]->{$var} = $this->_View->{$var};
}
$enable = isset($settings['enabled']) ? $settings['enabled'] : true;
if ($enable === true) {
$this->_enabled[] = $alias;
if ($enable) {
$this->enable($alias);
}
return $this->_loaded[$alias];
}
}
}