From b2250852e4509ec0cc225209bfc6466593624646 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 4 Jul 2010 00:43:39 -0400 Subject: [PATCH] Moving BehaviorCollection into its own file. Changing how behaviors are stored in the collection object. Makes it work the same as HelperCollection. --- cake/libs/model/behavior_collection.php | 279 ++++++++++++++++++++++++ cake/libs/model/model.php | 1 + cake/libs/model/model_behavior.php | 255 ---------------------- 3 files changed, 280 insertions(+), 255 deletions(-) create mode 100644 cake/libs/model/behavior_collection.php diff --git a/cake/libs/model/behavior_collection.php b/cake/libs/model/behavior_collection.php new file mode 100644 index 000000000..bb58b8db2 --- /dev/null +++ b/cake/libs/model/behavior_collection.php @@ -0,0 +1,279 @@ +modelName = $modelName; + + if (!empty($behaviors)) { + foreach (Set::normalize($behaviors) as $behavior => $config) { + $this->attach($behavior, $config); + } + } + } + +/** + * Backwards compatible alias for load() + * + * @return void + * @deprecated Replaced with load() + */ + public function attach($behavior, $config = array()) { + return $this->load($behavior, $config); + } + +/** + * Loads a behavior into the collection. + * + * @param string $behavior CamelCased name of the behavior to load + * @param array $config Behavior configuration parameters + * @param boolean $enable Whether or not this helper should be enabled by default + * @return boolean True on success, false on failure + * @throws MissingBehaviorFileException or MissingBehaviorClassException when a behavior could not be found. + */ + public function load($behavior, $config = array(), $enable = true) { + list($plugin, $name) = pluginSplit($behavior); + $class = $name . 'Behavior'; + + if (!App::import('Behavior', $behavior)) { + throw new MissingBehaviorFileException(Inflector::underscore($behavior) . '.php'); + } + if (!class_exists($class)) { + throw new MissingBehaviorClassException(Inflector::underscore($class)); + } + + if (!isset($this->{$name})) { + if (ClassRegistry::isKeySet($class)) { + $this->_loaded[$name] = ClassRegistry::getObject($class); + } else { + $this->_loaded[$name] = new $class(); + ClassRegistry::addObject($class, $this->_loaded[$name]); + if (!empty($plugin)) { + ClassRegistry::addObject($plugin . '.' . $class, $this->_loaded[$name]); + } + } + } elseif (isset($this->_loaded[$name]->settings) && isset($this->_loaded[$name]->settings[$this->modelName])) { + if ($config !== null && $config !== false) { + $config = array_merge($this->_loaded[$name]->settings[$this->modelName], $config); + } else { + $config = array(); + } + } + if (empty($config)) { + $config = array(); + } + $this->_loaded[$name]->setup(ClassRegistry::getObject($this->modelName), $config); + + foreach ($this->_loaded[$name]->mapMethods as $method => $alias) { + $this->__mappedMethods[$method] = array($alias, $name); + } + $methods = get_class_methods($this->_loaded[$name]); + $parentMethods = array_flip(get_class_methods('ModelBehavior')); + $callbacks = array( + 'setup', 'cleanup', 'beforeFind', 'afterFind', 'beforeSave', 'afterSave', + 'beforeDelete', 'afterDelete', 'afterError' + ); + + foreach ($methods as $m) { + if (!isset($parentMethods[$m])) { + $methodAllowed = ( + $m[0] != '_' && !array_key_exists($m, $this->__methods) && + !in_array($m, $callbacks) + ); + if ($methodAllowed) { + $this->__methods[$m] = array($m, $name); + } + } + } + + if (!in_array($name, $this->_attached)) { + $this->_attached[] = $name; + } + if (in_array($name, $this->_disabled) && !(isset($config['enabled']) && $config['enabled'] === false)) { + $this->enable($name); + } elseif (isset($config['enabled']) && $config['enabled'] === false) { + $this->disable($name); + } + return true; + } + +/** + * Detaches a behavior from a model + * + * @param string $name CamelCased name of the behavior to unload + * @return void + */ + public function unload($name) { + list($plugin, $name) = pluginSplit($name); + if (isset($this->_loaded[$name])) { + $this->_loaded[$name]->cleanup(ClassRegistry::getObject($this->modelName)); + unset($this->_loaded[$name]); + } + foreach ($this->__methods as $m => $callback) { + if (is_array($callback) && $callback[1] == $name) { + unset($this->__methods[$m]); + } + } + $this->_attached = array_values(array_diff($this->_attached, (array)$name)); + } + +/** + * Backwards compatible alias for unload() + * + * @param string $name Name of behavior + * @return void + * @deprecated Use unload instead. + */ + public function detach($name) { + return $this->unload($name); + } + +/** + * Dispatches a behavior method + * + * @return array All methods for all behaviors attached to this object + */ + public function dispatchMethod(&$model, $method, $params = array(), $strict = false) { + $methods = array_keys($this->__methods); + foreach ($methods as $key => $value) { + $methods[$key] = strtolower($value); + } + $method = strtolower($method); + $check = array_flip($methods); + $found = isset($check[$method]); + $call = null; + + if ($strict && !$found) { + trigger_error(sprintf(__("BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior"), $method), E_USER_WARNING); + return null; + } elseif ($found) { + $methods = array_combine($methods, array_values($this->__methods)); + $call = $methods[$method]; + } else { + $count = count($this->__mappedMethods); + $mapped = array_keys($this->__mappedMethods); + + for ($i = 0; $i < $count; $i++) { + if (preg_match($mapped[$i] . 'i', $method)) { + $call = $this->__mappedMethods[$mapped[$i]]; + array_unshift($params, $method); + break; + } + } + } + + if (!empty($call)) { + return $this->_loaded[$call[1]]->dispatchMethod($model, $call[0], $params); + } + return array('unhandled'); + } + +/** + * Dispatches a behavior callback on all attached behavior objects + * + * @param model $model + * @param string $callback + * @param array $params + * @param array $options + * @return mixed + */ + public function trigger(&$model, $callback, $params = array(), $options = array()) { + if (empty($this->_attached)) { + return true; + } + $options = array_merge(array('break' => false, 'breakOn' => array(null, false), 'modParams' => false), $options); + $count = count($this->_attached); + + for ($i = 0; $i < $count; $i++) { + $name = $this->_attached[$i]; + if (in_array($name, $this->_disabled)) { + continue; + } + $result = $this->_loaded[$name]->dispatchMethod($model, $callback, $params); + + if ($options['break'] && ($result === $options['breakOn'] || (is_array($options['breakOn']) && in_array($result, $options['breakOn'], true)))) { + return $result; + } elseif ($options['modParams'] && is_array($result)) { + $params[0] = $result; + } + } + if ($options['modParams'] && isset($params[0])) { + return $params[0]; + } + return true; + } + +/** + * Gets the method list for attached behaviors, i.e. all public, non-callback methods + * + * @return array All public methods for all behaviors attached to this collection + */ + public function methods() { + return $this->__methods; + } + +} + +/** + * Runtime Exceptions for behaviors + */ +class MissingBehaviorFileException extends RuntimeException { } +class MissingBehaviorClassException extends RuntimeException { } \ No newline at end of file diff --git a/cake/libs/model/model.php b/cake/libs/model/model.php index b5e0beb6f..65ec0935f 100644 --- a/cake/libs/model/model.php +++ b/cake/libs/model/model.php @@ -24,6 +24,7 @@ * Included libs */ App::import('Core', array('ClassRegistry', 'Validation', 'Set', 'String')); +App::import('Model', 'BehaviorCollection', false); App::import('Model', 'ModelBehavior', false); App::import('Model', 'ConnectionManager', false); diff --git a/cake/libs/model/model_behavior.php b/cake/libs/model/model_behavior.php index d066f7460..41342605c 100644 --- a/cake/libs/model/model_behavior.php +++ b/cake/libs/model/model_behavior.php @@ -20,8 +20,6 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'ObjectCollection'); - /** * Model behavior base class. * @@ -204,256 +202,3 @@ class ModelBehavior extends Object { } } -/** - * Model behavior collection class. - * - * Defines the Behavior interface, and contains common model interaction functionality. - * - * @package cake - * @subpackage cake.cake.libs.model - */ -class BehaviorCollection extends ObjectCollection { - -/** - * Stores a reference to the attached name - * - * @var string - * @access public - */ - public $modelName = null; - -/** - * Keeps a list of all methods of attached behaviors - * - * @var array - */ - private $__methods = array(); - -/** - * Keeps a list of all methods which have been mapped with regular expressions - * - * @var array - */ - private $__mappedMethods = array(); - -/** - * Attaches a model object and loads a list of behaviors - * - * @todo Make this method a constructor instead.. - * @access public - * @return void - */ - function init($modelName, $behaviors = array()) { - $this->modelName = $modelName; - - if (!empty($behaviors)) { - foreach (Set::normalize($behaviors) as $behavior => $config) { - $this->attach($behavior, $config); - } - } - } - -/** - * Backwards compatible alias for load() - * - * @return void - * @deprecated Replaced with load() - */ - public function attach($behavior, $config = array()) { - return $this->load($behavior, $config); - } - -/** - * Loads a behavior into the collection. - * - * @param string $behavior CamelCased name of the behavior to load - * @param array $config Behavior configuration parameters - * @param boolean $enable Whether or not this helper should be enabled by default - * @return boolean True on success, false on failure - * @throws MissingBehaviorFileException or MissingBehaviorClassException when a behavior could not be found. - */ - public function load($behavior, $config = array(), $enable = true) { - list($plugin, $name) = pluginSplit($behavior); - $class = $name . 'Behavior'; - - if (!App::import('Behavior', $behavior)) { - throw new MissingBehaviorFileException(Inflector::underscore($behavior) . '.php'); - } - if (!class_exists($class)) { - throw new MissingBehaviorClassException(Inflector::underscore($class)); - } - - if (!isset($this->{$name})) { - if (ClassRegistry::isKeySet($class)) { - $this->{$name} = ClassRegistry::getObject($class); - } else { - $this->{$name} = new $class(); - - ClassRegistry::addObject($class, $this->{$name}); - if (!empty($plugin)) { - ClassRegistry::addObject($plugin.'.'.$class, $this->{$name}); - } - } - } elseif (isset($this->{$name}->settings) && isset($this->{$name}->settings[$this->modelName])) { - if ($config !== null && $config !== false) { - $config = array_merge($this->{$name}->settings[$this->modelName], $config); - } else { - $config = array(); - } - } - if (empty($config)) { - $config = array(); - } - $this->{$name}->setup(ClassRegistry::getObject($this->modelName), $config); - - foreach ($this->{$name}->mapMethods as $method => $alias) { - $this->__mappedMethods[$method] = array($alias, $name); - } - $methods = get_class_methods($this->{$name}); - $parentMethods = array_flip(get_class_methods('ModelBehavior')); - $callbacks = array( - 'setup', 'cleanup', 'beforeFind', 'afterFind', 'beforeSave', 'afterSave', - 'beforeDelete', 'afterDelete', 'afterError' - ); - - foreach ($methods as $m) { - if (!isset($parentMethods[$m])) { - $methodAllowed = ( - $m[0] != '_' && !array_key_exists($m, $this->__methods) && - !in_array($m, $callbacks) - ); - if ($methodAllowed) { - $this->__methods[$m] = array($m, $name); - } - } - } - - if (!in_array($name, $this->_attached)) { - $this->_attached[] = $name; - } - if (in_array($name, $this->_disabled) && !(isset($config['enabled']) && $config['enabled'] === false)) { - $this->enable($name); - } elseif (isset($config['enabled']) && $config['enabled'] === false) { - $this->disable($name); - } - return true; - } - -/** - * Detaches a behavior from a model - * - * @param string $name CamelCased name of the behavior to unload - * @return void - */ - public function unload($name) { - list($plugin, $name) = pluginSplit($name); - if (isset($this->{$name})) { - $this->{$name}->cleanup(ClassRegistry::getObject($this->modelName)); - unset($this->{$name}); - } - foreach ($this->__methods as $m => $callback) { - if (is_array($callback) && $callback[1] == $name) { - unset($this->__methods[$m]); - } - } - $this->_attached = array_values(array_diff($this->_attached, (array)$name)); - } - -/** - * Backwards compatible alias for unload() - * - * @param string $name Name of behavior - * @return void - * @deprecated Use unload instead. - */ - public function detach($name) { - return $this->unload($name); - } - -/** - * Dispatches a behavior method - * - * @return array All methods for all behaviors attached to this object - */ - public function dispatchMethod(&$model, $method, $params = array(), $strict = false) { - $methods = array_keys($this->__methods); - $check = array_flip($methods); - $found = isset($check[$method]); - $call = null; - - if ($strict && !$found) { - trigger_error(sprintf(__("BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior"), $method), E_USER_WARNING); - return null; - } elseif ($found) { - $methods = array_combine($methods, array_values($this->__methods)); - $call = $methods[$method]; - } else { - $count = count($this->__mappedMethods); - $mapped = array_keys($this->__mappedMethods); - - for ($i = 0; $i < $count; $i++) { - if (preg_match($mapped[$i] . 'i', $method)) { - $call = $this->__mappedMethods[$mapped[$i]]; - array_unshift($params, $method); - break; - } - } - } - - if (!empty($call)) { - return $this->{$call[1]}->dispatchMethod($model, $call[0], $params); - } - return array('unhandled'); - } - -/** - * Dispatches a behavior callback on all attached behavior objects - * - * @param model $model - * @param string $callback - * @param array $params - * @param array $options - * @return mixed - */ - public function trigger(&$model, $callback, $params = array(), $options = array()) { - if (empty($this->_attached)) { - return true; - } - $options = array_merge(array('break' => false, 'breakOn' => array(null, false), 'modParams' => false), $options); - $count = count($this->_attached); - - for ($i = 0; $i < $count; $i++) { - $name = $this->_attached[$i]; - if (in_array($name, $this->_disabled)) { - continue; - } - $result = $this->{$name}->dispatchMethod($model, $callback, $params); - - if ($options['break'] && ($result === $options['breakOn'] || (is_array($options['breakOn']) && in_array($result, $options['breakOn'], true)))) { - return $result; - } elseif ($options['modParams'] && is_array($result)) { - $params[0] = $result; - } - } - if ($options['modParams'] && isset($params[0])) { - return $params[0]; - } - return true; - } - -/** - * Gets the method list for attached behaviors, i.e. all public, non-callback methods - * - * @return array All public methods for all behaviors attached to this collection - */ - public function methods() { - return $this->__methods; - } - -} - -/** - * Runtime Exceptions for behaviors - */ -class MissingBehaviorFileException extends RuntimeException { } -class MissingBehaviorClassException extends RuntimeException { }