pictcode / lib / Cake / Utility / ObjectCollection.php @ 304d523f
履歴 | 表示 | アノテート | ダウンロード (10.903 KB)
| 1 | 635eef61 | spyder1211 | <?php
 | 
      
|---|---|---|---|
| 2 | /**
 | 
      ||
| 3 |  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 | 
      ||
| 4 |  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 | 
      ||
| 5 |  *
 | 
      ||
| 6 |  * Licensed under The MIT License
 | 
      ||
| 7 |  * For full copyright and license information, please see the LICENSE.txt
 | 
      ||
| 8 |  * Redistributions of files must retain the above copyright notice.
 | 
      ||
| 9 |  *
 | 
      ||
| 10 |  * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 | 
      ||
| 11 |  * @link          http://cakephp.org CakePHP(tm) Project
 | 
      ||
| 12 |  * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 | 
      ||
| 13 |  */
 | 
      ||
| 14 | |||
| 15 | /**
 | 
      ||
| 16 |  * Deals with Collections of objects. Keeping registries of those objects,
 | 
      ||
| 17 |  * loading and constructing new objects and triggering callbacks. Each subclass needs
 | 
      ||
| 18 |  * to implement its own load() functionality.
 | 
      ||
| 19 |  *
 | 
      ||
| 20 |  * All core subclasses of ObjectCollection by convention loaded objects are stored
 | 
      ||
| 21 |  * in `$this->_loaded`. Enabled objects are stored in `$this->_enabled`. In addition,
 | 
      ||
| 22 |  * they all support an `enabled` option that controls the enabled/disabled state of the object
 | 
      ||
| 23 |  * when loaded.
 | 
      ||
| 24 |  *
 | 
      ||
| 25 |  * @package       Cake.Utility
 | 
      ||
| 26 |  * @since CakePHP(tm) v 2.0
 | 
      ||
| 27 |  */
 | 
      ||
| 28 | abstract class ObjectCollection {  | 
      ||
| 29 | |||
| 30 | /**
 | 
      ||
| 31 |  * List of the currently-enabled objects
 | 
      ||
| 32 |  *
 | 
      ||
| 33 |  * @var array
 | 
      ||
| 34 |  */
 | 
      ||
| 35 | protected $_enabled = array();  | 
      ||
| 36 | |||
| 37 | /**
 | 
      ||
| 38 |  * A hash of loaded objects, indexed by name
 | 
      ||
| 39 |  *
 | 
      ||
| 40 |  * @var array
 | 
      ||
| 41 |  */
 | 
      ||
| 42 | protected $_loaded = array();  | 
      ||
| 43 | |||
| 44 | /**
 | 
      ||
| 45 |  * Default object priority. A non zero integer.
 | 
      ||
| 46 |  *
 | 
      ||
| 47 |  * @var int
 | 
      ||
| 48 |  */
 | 
      ||
| 49 | public $defaultPriority = 10;  | 
      ||
| 50 | |||
| 51 | /**
 | 
      ||
| 52 |  * Loads a new object onto the collection. Can throw a variety of exceptions
 | 
      ||
| 53 |  *
 | 
      ||
| 54 |  * Implementations of this class support a `$options['enabled']` flag which enables/disables
 | 
      ||
| 55 |  * a loaded object.
 | 
      ||
| 56 |  *
 | 
      ||
| 57 |  * @param string $name Name of object to load.
 | 
      ||
| 58 |  * @param array $options Array of configuration options for the object to be constructed.
 | 
      ||
| 59 |  * @return object the constructed object
 | 
      ||
| 60 |  */
 | 
      ||
| 61 | abstract public function load($name, $options = array());  | 
      ||
| 62 | |||
| 63 | /**
 | 
      ||
| 64 |  * Trigger a callback method on every object in the collection.
 | 
      ||
| 65 |  * Used to trigger methods on objects in the collection. Will fire the methods in the
 | 
      ||
| 66 |  * order they were attached.
 | 
      ||
| 67 |  *
 | 
      ||
| 68 |  * ### Options
 | 
      ||
| 69 |  *
 | 
      ||
| 70 |  * - `breakOn` Set to the value or values you want the callback propagation to stop on.
 | 
      ||
| 71 |  *    Can either be a scalar value, or an array of values to break on. Defaults to `false`.
 | 
      ||
| 72 |  *
 | 
      ||
| 73 |  * - `break` Set to true to enabled breaking. When a trigger is broken, the last returned value
 | 
      ||
| 74 |  *    will be returned. If used in combination with `collectReturn` the collected results will be returned.
 | 
      ||
| 75 |  *    Defaults to `false`.
 | 
      ||
| 76 |  *
 | 
      ||
| 77 |  * - `collectReturn` Set to true to collect the return of each object into an array.
 | 
      ||
| 78 |  *    This array of return values will be returned from the trigger() call. Defaults to `false`.
 | 
      ||
| 79 |  *
 | 
      ||
| 80 |  * - `modParams` Allows each object the callback gets called on to modify the parameters to the next object.
 | 
      ||
| 81 |  *    Setting modParams to an integer value will allow you to modify the parameter with that index.
 | 
      ||
| 82 |  *    Any non-null value will modify the parameter index indicated.
 | 
      ||
| 83 |  *    Defaults to false.
 | 
      ||
| 84 |  *
 | 
      ||
| 85 |  * @param string|CakeEvent $callback Method to fire on all the objects. Its assumed all the objects implement
 | 
      ||
| 86 |  *   the method you are calling. If an instance of CakeEvent is provided, then then Event name will parsed to
 | 
      ||
| 87 |  *   get the callback name. This is done by getting the last word after any dot in the event name
 | 
      ||
| 88 |  *   (eg. `Model.afterSave` event will trigger the `afterSave` callback)
 | 
      ||
| 89 |  * @param array $params Array of parameters for the triggered callback.
 | 
      ||
| 90 |  * @param array $options Array of options.
 | 
      ||
| 91 |  * @return mixed Either the last result or all results if collectReturn is on.
 | 
      ||
| 92 |  * @throws CakeException when modParams is used with an index that does not exist.
 | 
      ||
| 93 |  */
 | 
      ||
| 94 | public function trigger($callback, $params = array(), $options = array()) {  | 
      ||
| 95 | if (empty($this->_enabled)) {  | 
      ||
| 96 | return true;  | 
      ||
| 97 | }  | 
      ||
| 98 | if ($callback instanceof CakeEvent) {  | 
      ||
| 99 | $event = $callback;  | 
      ||
| 100 | if (is_array($event->data)) {  | 
      ||
| 101 | $params =& $event->data;  | 
      ||
| 102 | }  | 
      ||
| 103 | if (empty($event->omitSubject)) {  | 
      ||
| 104 | $subject = $event->subject();  | 
      ||
| 105 | }  | 
      ||
| 106 | |||
| 107 | foreach (array('break', 'breakOn', 'collectReturn', 'modParams') as $opt) {  | 
      ||
| 108 | if (isset($event->{$opt})) {  | 
      ||
| 109 | $options[$opt] = $event->{$opt};  | 
      ||
| 110 | }  | 
      ||
| 111 | }  | 
      ||
| 112 | $parts = explode('.', $event->name());  | 
      ||
| 113 | $callback = array_pop($parts);  | 
      ||
| 114 | }  | 
      ||
| 115 | $options += array(  | 
      ||
| 116 | 'break' => false,  | 
      ||
| 117 | 'breakOn' => false,  | 
      ||
| 118 | 'collectReturn' => false,  | 
      ||
| 119 | 'modParams' => false  | 
      ||
| 120 | );  | 
      ||
| 121 | $collected = array();  | 
      ||
| 122 | $list = array_keys($this->_enabled);  | 
      ||
| 123 | if ($options['modParams'] !== false && !isset($params[$options['modParams']])) {  | 
      ||
| 124 | throw new CakeException(__d('cake_dev', 'Cannot use modParams with indexes that do not exist.'));  | 
      ||
| 125 | }  | 
      ||
| 126 | $result = null;  | 
      ||
| 127 | foreach ($list as $name) {  | 
      ||
| 128 | $result = call_user_func_array(array($this->_loaded[$name], $callback), compact('subject') + $params);  | 
      ||
| 129 | if ($options['collectReturn'] === true) {  | 
      ||
| 130 | $collected[] = $result;  | 
      ||
| 131 | }  | 
      ||
| 132 | if ($options['break'] && ($result === $options['breakOn'] ||  | 
      ||
| 133 | (is_array($options['breakOn']) && in_array($result, $options['breakOn'], true)))  | 
      ||
| 134 |                         ) {
 | 
      ||
| 135 | return $result;  | 
      ||
| 136 | } elseif ($options['modParams'] !== false && !in_array($result, array(true, false, null), true)) {  | 
      ||
| 137 | $params[$options['modParams']] = $result;  | 
      ||
| 138 | }  | 
      ||
| 139 | }  | 
      ||
| 140 | if ($options['modParams'] !== false) {  | 
      ||
| 141 | return $params[$options['modParams']];  | 
      ||
| 142 | }  | 
      ||
| 143 | return $options['collectReturn'] ? $collected : $result;  | 
      ||
| 144 | }  | 
      ||
| 145 | |||
| 146 | /**
 | 
      ||
| 147 |  * Provide public read access to the loaded objects
 | 
      ||
| 148 |  *
 | 
      ||
| 149 |  * @param string $name Name of property to read
 | 
      ||
| 150 |  * @return mixed
 | 
      ||
| 151 |  */
 | 
      ||
| 152 | public function __get($name) {  | 
      ||
| 153 | if (isset($this->_loaded[$name])) {  | 
      ||
| 154 | return $this->_loaded[$name];  | 
      ||
| 155 | }  | 
      ||
| 156 | return null;  | 
      ||
| 157 | }  | 
      ||
| 158 | |||
| 159 | /**
 | 
      ||
| 160 |  * Provide isset access to _loaded
 | 
      ||
| 161 |  *
 | 
      ||
| 162 |  * @param string $name Name of object being checked.
 | 
      ||
| 163 |  * @return bool
 | 
      ||
| 164 |  */
 | 
      ||
| 165 | public function __isset($name) {  | 
      ||
| 166 | return isset($this->_loaded[$name]);  | 
      ||
| 167 | }  | 
      ||
| 168 | |||
| 169 | /**
 | 
      ||
| 170 |  * Enables callbacks on an object or array of objects
 | 
      ||
| 171 |  *
 | 
      ||
| 172 |  * @param string|array $name CamelCased name of the object(s) to enable (string or array)
 | 
      ||
| 173 |  * @param bool $prioritize Prioritize enabled list after enabling object(s)
 | 
      ||
| 174 |  * @return void
 | 
      ||
| 175 |  */
 | 
      ||
| 176 | public function enable($name, $prioritize = true) {  | 
      ||
| 177 | $enabled = false;  | 
      ||
| 178 | foreach ((array)$name as $object) {  | 
      ||
| 179 | list(, $object) = pluginSplit($object);  | 
      ||
| 180 | if (isset($this->_loaded[$object]) && !isset($this->_enabled[$object])) {  | 
      ||
| 181 | $priority = $this->defaultPriority;  | 
      ||
| 182 | if (isset($this->_loaded[$object]->settings['priority'])) {  | 
      ||
| 183 | $priority = $this->_loaded[$object]->settings['priority'];  | 
      ||
| 184 | }  | 
      ||
| 185 | $this->_enabled[$object] = array($priority);  | 
      ||
| 186 | $enabled = true;  | 
      ||
| 187 | }  | 
      ||
| 188 | }  | 
      ||
| 189 | if ($prioritize && $enabled) {  | 
      ||
| 190 |                         $this->prioritize();
 | 
      ||
| 191 | }  | 
      ||
| 192 | }  | 
      ||
| 193 | |||
| 194 | /**
 | 
      ||
| 195 |  * Prioritize list of enabled object
 | 
      ||
| 196 |  *
 | 
      ||
| 197 |  * @return array Prioritized list of object
 | 
      ||
| 198 |  */
 | 
      ||
| 199 | public function prioritize() {  | 
      ||
| 200 | $i = 1;  | 
      ||
| 201 | foreach ($this->_enabled as $name => $priority) {  | 
      ||
| 202 | $priority[1] = $i++;  | 
      ||
| 203 | $this->_enabled[$name] = $priority;  | 
      ||
| 204 | }  | 
      ||
| 205 | asort($this->_enabled);  | 
      ||
| 206 | return $this->_enabled;  | 
      ||
| 207 | }  | 
      ||
| 208 | |||
| 209 | /**
 | 
      ||
| 210 |  * Set priority for an object or array of objects
 | 
      ||
| 211 |  *
 | 
      ||
| 212 |  * @param string|array $name CamelCased name of the object(s) to enable (string or array)
 | 
      ||
| 213 |  *         If string the second param $priority is used else it should be an associative array
 | 
      ||
| 214 |  *         with keys as object names and values as priorities to set.
 | 
      ||
| 215 |  * @param int|null $priority Integer priority to set or null for default
 | 
      ||
| 216 |  * @return void
 | 
      ||
| 217 |  */
 | 
      ||
| 218 | public function setPriority($name, $priority = null) {  | 
      ||
| 219 | if (is_string($name)) {  | 
      ||
| 220 | $name = array($name => $priority);  | 
      ||
| 221 | }  | 
      ||
| 222 | foreach ($name as $object => $objectPriority) {  | 
      ||
| 223 | list(, $object) = pluginSplit($object);  | 
      ||
| 224 | if (isset($this->_loaded[$object])) {  | 
      ||
| 225 | if ($objectPriority === null) {  | 
      ||
| 226 | $objectPriority = $this->defaultPriority;  | 
      ||
| 227 | }  | 
      ||
| 228 | $this->_loaded[$object]->settings['priority'] = $objectPriority;  | 
      ||
| 229 | if (isset($this->_enabled[$object])) {  | 
      ||
| 230 | $this->_enabled[$object] = array($objectPriority);  | 
      ||
| 231 | }  | 
      ||
| 232 | }  | 
      ||
| 233 | }  | 
      ||
| 234 |                 $this->prioritize();
 | 
      ||
| 235 | }  | 
      ||
| 236 | |||
| 237 | /**
 | 
      ||
| 238 |  * Disables callbacks on an object or array of objects. Public object methods are still
 | 
      ||
| 239 |  * callable as normal.
 | 
      ||
| 240 |  *
 | 
      ||
| 241 |  * @param string|array $name CamelCased name of the objects(s) to disable (string or array)
 | 
      ||
| 242 |  * @return void
 | 
      ||
| 243 |  */
 | 
      ||
| 244 | public function disable($name) {  | 
      ||
| 245 | foreach ((array)$name as $object) {  | 
      ||
| 246 | list(, $object) = pluginSplit($object);  | 
      ||
| 247 | unset($this->_enabled[$object]);  | 
      ||
| 248 | }  | 
      ||
| 249 | }  | 
      ||
| 250 | |||
| 251 | /**
 | 
      ||
| 252 |  * Gets the list of currently-enabled objects, or, the current status of a single objects
 | 
      ||
| 253 |  *
 | 
      ||
| 254 |  * @param string $name Optional. The name of the object to check the status of. If omitted,
 | 
      ||
| 255 |  *   returns an array of currently-enabled object
 | 
      ||
| 256 |  * @return mixed If $name is specified, returns the boolean status of the corresponding object.
 | 
      ||
| 257 |  *   Otherwise, returns an array of all enabled objects.
 | 
      ||
| 258 |  */
 | 
      ||
| 259 | public function enabled($name = null) {  | 
      ||
| 260 | if (!empty($name)) {  | 
      ||
| 261 | list(, $name) = pluginSplit($name);  | 
      ||
| 262 | return isset($this->_enabled[$name]);  | 
      ||
| 263 | }  | 
      ||
| 264 | return array_keys($this->_enabled);  | 
      ||
| 265 | }  | 
      ||
| 266 | |||
| 267 | /**
 | 
      ||
| 268 |  * Gets the list of attached objects, or, whether the given object is attached
 | 
      ||
| 269 |  *
 | 
      ||
| 270 |  * @param string $name Optional. The name of the object to check the status of. If omitted,
 | 
      ||
| 271 |  *   returns an array of currently-attached objects
 | 
      ||
| 272 |  * @return mixed If $name is specified, returns the boolean status of the corresponding object.
 | 
      ||
| 273 |  *    Otherwise, returns an array of all attached objects.
 | 
      ||
| 274 |  * @deprecated 3.0.0 Will be removed in 3.0. Use loaded instead.
 | 
      ||
| 275 |  */
 | 
      ||
| 276 | public function attached($name = null) {  | 
      ||
| 277 | return $this->loaded($name);  | 
      ||
| 278 | }  | 
      ||
| 279 | |||
| 280 | /**
 | 
      ||
| 281 |  * Gets the list of loaded objects, or, whether the given object is loaded
 | 
      ||
| 282 |  *
 | 
      ||
| 283 |  * @param string $name Optional. The name of the object to check the status of. If omitted,
 | 
      ||
| 284 |  *   returns an array of currently-loaded objects
 | 
      ||
| 285 |  * @return mixed If $name is specified, returns the boolean status of the corresponding object.
 | 
      ||
| 286 |  *    Otherwise, returns an array of all loaded objects.
 | 
      ||
| 287 |  */
 | 
      ||
| 288 | public function loaded($name = null) {  | 
      ||
| 289 | if (!empty($name)) {  | 
      ||
| 290 | list(, $name) = pluginSplit($name);  | 
      ||
| 291 | return isset($this->_loaded[$name]);  | 
      ||
| 292 | }  | 
      ||
| 293 | return array_keys($this->_loaded);  | 
      ||
| 294 | }  | 
      ||
| 295 | |||
| 296 | /**
 | 
      ||
| 297 |  * Name of the object to remove from the collection
 | 
      ||
| 298 |  *
 | 
      ||
| 299 |  * @param string $name Name of the object to delete.
 | 
      ||
| 300 |  * @return void
 | 
      ||
| 301 |  */
 | 
      ||
| 302 | public function unload($name) {  | 
      ||
| 303 | list(, $name) = pluginSplit($name);  | 
      ||
| 304 | unset($this->_loaded[$name], $this->_enabled[$name]);  | 
      ||
| 305 | }  | 
      ||
| 306 | |||
| 307 | /**
 | 
      ||
| 308 |  * Adds or overwrites an instantiated object to the collection
 | 
      ||
| 309 |  *
 | 
      ||
| 310 |  * @param string $name Name of the object
 | 
      ||
| 311 |  * @param Object $object The object to use
 | 
      ||
| 312 |  * @return array Loaded objects
 | 
      ||
| 313 |  */
 | 
      ||
| 314 | public function set($name = null, $object = null) {  | 
      ||
| 315 | if (!empty($name) && !empty($object)) {  | 
      ||
| 316 | list(, $name) = pluginSplit($name);  | 
      ||
| 317 | $this->_loaded[$name] = $object;  | 
      ||
| 318 | }  | 
      ||
| 319 | return $this->_loaded;  | 
      ||
| 320 | }  | 
      ||
| 321 | |||
| 322 | /**
 | 
      ||
| 323 |  * Normalizes an object array, creates an array that makes lazy loading
 | 
      ||
| 324 |  * easier
 | 
      ||
| 325 |  *
 | 
      ||
| 326 |  * @param array $objects Array of child objects to normalize.
 | 
      ||
| 327 |  * @return array Array of normalized objects.
 | 
      ||
| 328 |  */
 | 
      ||
| 329 | public static function normalizeObjectArray($objects) {  | 
      ||
| 330 | $normal = array();  | 
      ||
| 331 | foreach ($objects as $i => $objectName) {  | 
      ||
| 332 | $options = array();  | 
      ||
| 333 | if (!is_int($i)) {  | 
      ||
| 334 | $options = (array)$objectName;  | 
      ||
| 335 | $objectName = $i;  | 
      ||
| 336 | }  | 
      ||
| 337 | list(, $name) = pluginSplit($objectName);  | 
      ||
| 338 | $normal[$name] = array('class' => $objectName, 'settings' => $options);  | 
      ||
| 339 | }  | 
      ||
| 340 | return $normal;  | 
      ||
| 341 | }  | 
      ||
| 342 | |||
| 343 | }  |