pictcode / lib / Cake / Utility / ClassRegistry.php @ f4a6dc2c
履歴 | 表示 | アノテート | ダウンロード (10.101 KB)
| 1 | 
      <?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 | 
       * @package       Cake.Utility
     | 
  
| 13 | 
       * @since         CakePHP(tm) v 0.9.2
     | 
  
| 14 | 
       * @license       http://www.opensource.org/licenses/mit-license.php MIT License
     | 
  
| 15 | 
       */
     | 
  
| 16 | 
       | 
  
| 17 | 
      /**
     | 
  
| 18 | 
       * Included libraries.
     | 
  
| 19 | 
       */
     | 
  
| 20 | 
      App::uses('Model', 'Model');  | 
  
| 21 | 
      App::uses('AppModel', 'Model');  | 
  
| 22 | 
      App::uses('ConnectionManager', 'Model');  | 
  
| 23 | 
       | 
  
| 24 | 
      /**
     | 
  
| 25 | 
       * Class Collections.
     | 
  
| 26 | 
       *
     | 
  
| 27 | 
       * A repository for class objects, each registered with a key.
     | 
  
| 28 | 
       * If you try to add an object with the same key twice, nothing will come of it.
     | 
  
| 29 | 
       * If you need a second instance of an object, give it another key.
     | 
  
| 30 | 
       *
     | 
  
| 31 | 
       * @package       Cake.Utility
     | 
  
| 32 | 
       */
     | 
  
| 33 | 
      class ClassRegistry {  | 
  
| 34 | 
       | 
  
| 35 | 
      /**
     | 
  
| 36 | 
       * Names of classes with their objects.
     | 
  
| 37 | 
       *
     | 
  
| 38 | 
       * @var array
     | 
  
| 39 | 
       */
     | 
  
| 40 | 
      protected $_objects = array();  | 
  
| 41 | 
       | 
  
| 42 | 
      /**
     | 
  
| 43 | 
       * Names of class names mapped to the object in the registry.
     | 
  
| 44 | 
       *
     | 
  
| 45 | 
       * @var array
     | 
  
| 46 | 
       */
     | 
  
| 47 | 
      protected $_map = array();  | 
  
| 48 | 
       | 
  
| 49 | 
      /**
     | 
  
| 50 | 
       * Default constructor parameter settings, indexed by type
     | 
  
| 51 | 
       *
     | 
  
| 52 | 
       * @var array
     | 
  
| 53 | 
       */
     | 
  
| 54 | 
      protected $_config = array();  | 
  
| 55 | 
       | 
  
| 56 | 
      /**
     | 
  
| 57 | 
       * Return a singleton instance of the ClassRegistry.
     | 
  
| 58 | 
       *
     | 
  
| 59 | 
       * @return ClassRegistry instance
     | 
  
| 60 | 
       */
     | 
  
| 61 | 
      public static function getInstance() {  | 
  
| 62 | 
      static $instance = array();  | 
  
| 63 | 
      if (!$instance) {  | 
  
| 64 | 
      $instance[0] = new ClassRegistry();  | 
  
| 65 | 
      }  | 
  
| 66 | 
      return $instance[0];  | 
  
| 67 | 
      }  | 
  
| 68 | 
       | 
  
| 69 | 
      /**
     | 
  
| 70 | 
       * Loads a class, registers the object in the registry and returns instance of the object. ClassRegistry::init()
     | 
  
| 71 | 
       * is used as a factory for models, and handle correct injecting of settings, that assist in testing.
     | 
  
| 72 | 
       *
     | 
  
| 73 | 
       * Examples
     | 
  
| 74 | 
       * Simple Use: Get a Post model instance ```ClassRegistry::init('Post');```
     | 
  
| 75 | 
       *
     | 
  
| 76 | 
       * Expanded: ```array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry');```
     | 
  
| 77 | 
       *
     | 
  
| 78 | 
       * Model Classes can accept optional ```array('id' => $id, 'table' => $table, 'ds' => $ds, 'alias' => $alias);```
     | 
  
| 79 | 
       *
     | 
  
| 80 | 
       * When $class is a numeric keyed array, multiple class instances will be stored in the registry,
     | 
  
| 81 | 
       *  no instance of the object will be returned
     | 
  
| 82 | 
       * ```
     | 
  
| 83 | 
       * array(
     | 
  
| 84 | 
       *                array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry'),
     | 
  
| 85 | 
       *                array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry'),
     | 
  
| 86 | 
       *                array('class' => 'ClassName', 'alias' => 'AliasNameStoredInTheRegistry')
     | 
  
| 87 | 
       * );
     | 
  
| 88 | 
       * ```
     | 
  
| 89 | 
       *
     | 
  
| 90 | 
       * @param string|array $class as a string or a single key => value array instance will be created,
     | 
  
| 91 | 
       *  stored in the registry and returned.
     | 
  
| 92 | 
       * @param bool $strict if set to true it will return false if the class was not found instead
     | 
  
| 93 | 
       *        of trying to create an AppModel
     | 
  
| 94 | 
       * @return $class instance of ClassName.
     | 
  
| 95 | 
       * @throws CakeException when you try to construct an interface or abstract class.
     | 
  
| 96 | 
       */
     | 
  
| 97 | 
      public static function init($class, $strict = false) {  | 
  
| 98 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 99 | 
       | 
  
| 100 | 
      if (is_array($class)) {  | 
  
| 101 | 
      $objects = $class;  | 
  
| 102 | 
      if (!isset($class[0])) {  | 
  
| 103 | 
      $objects = array($class);  | 
  
| 104 | 
      }  | 
  
| 105 | 
                      } else {
     | 
  
| 106 | 
      $objects = array(array('class' => $class));  | 
  
| 107 | 
      }  | 
  
| 108 | 
      $defaults = array();  | 
  
| 109 | 
      if (isset($_this->_config['Model'])) {  | 
  
| 110 | 
      $defaults = $_this->_config['Model'];  | 
  
| 111 | 
      }  | 
  
| 112 | 
      $count = count($objects);  | 
  
| 113 | 
      $availableDs = null;  | 
  
| 114 | 
       | 
  
| 115 | 
      foreach ($objects as $settings) {  | 
  
| 116 | 
      if (is_numeric($settings)) {  | 
  
| 117 | 
      trigger_error(__d('cake_dev', '(ClassRegistry::init() Attempted to create instance of a class with a numeric name'), E_USER_WARNING);  | 
  
| 118 | 
      return false;  | 
  
| 119 | 
      }  | 
  
| 120 | 
       | 
  
| 121 | 
      if (is_array($settings)) {  | 
  
| 122 | 
      $pluginPath = null;  | 
  
| 123 | 
      $settings += $defaults;  | 
  
| 124 | 
      $class = $settings['class'];  | 
  
| 125 | 
       | 
  
| 126 | 
      list($plugin, $class) = pluginSplit($class);  | 
  
| 127 | 
      if ($plugin) {  | 
  
| 128 | 
      $pluginPath = $plugin . '.';  | 
  
| 129 | 
      $settings['plugin'] = $plugin;  | 
  
| 130 | 
      }  | 
  
| 131 | 
       | 
  
| 132 | 
      if (empty($settings['alias'])) {  | 
  
| 133 | 
      $settings['alias'] = $class;  | 
  
| 134 | 
      }  | 
  
| 135 | 
      $alias = $settings['alias'];  | 
  
| 136 | 
       | 
  
| 137 | 
      $model = $_this->_duplicate($alias, $class);  | 
  
| 138 | 
      if ($model) {  | 
  
| 139 | 
      $_this->map($alias, $class);  | 
  
| 140 | 
      return $model;  | 
  
| 141 | 
      }  | 
  
| 142 | 
       | 
  
| 143 | 
      App::uses($plugin . 'AppModel', $pluginPath . 'Model');  | 
  
| 144 | 
      App::uses($class, $pluginPath . 'Model');  | 
  
| 145 | 
       | 
  
| 146 | 
      if (class_exists($class) || interface_exists($class)) {  | 
  
| 147 | 
      $reflection = new ReflectionClass($class);  | 
  
| 148 | 
      if ($reflection->isAbstract() || $reflection->isInterface()) {  | 
  
| 149 | 
      throw new CakeException(__d('cake_dev', 'Cannot create instance of %s, as it is abstract or is an interface', $class));  | 
  
| 150 | 
      }  | 
  
| 151 | 
      $testing = isset($settings['testing']) ? $settings['testing'] : false;  | 
  
| 152 | 
      if ($testing) {  | 
  
| 153 | 
      $settings['ds'] = 'test';  | 
  
| 154 | 
      $defaultProperties = $reflection->getDefaultProperties();  | 
  
| 155 | 
      if (isset($defaultProperties['useDbConfig'])) {  | 
  
| 156 | 
      $useDbConfig = $defaultProperties['useDbConfig'];  | 
  
| 157 | 
      if ($availableDs === null) {  | 
  
| 158 | 
      $availableDs = array_keys(ConnectionManager::enumConnectionObjects());  | 
  
| 159 | 
      }  | 
  
| 160 | 
      if (in_array('test_' . $useDbConfig, $availableDs)) {  | 
  
| 161 | 
      $useDbConfig = 'test_' . $useDbConfig;  | 
  
| 162 | 
      }  | 
  
| 163 | 
      if (strpos($useDbConfig, 'test') === 0) {  | 
  
| 164 | 
      $settings['ds'] = $useDbConfig;  | 
  
| 165 | 
      }  | 
  
| 166 | 
      }  | 
  
| 167 | 
      }  | 
  
| 168 | 
      if ($reflection->getConstructor()) {  | 
  
| 169 | 
      $instance = $reflection->newInstance($settings);  | 
  
| 170 | 
                                              } else {
     | 
  
| 171 | 
      $instance = $reflection->newInstance();  | 
  
| 172 | 
      }  | 
  
| 173 | 
      if ($strict && !$instance instanceof Model) {  | 
  
| 174 | 
      $instance = null;  | 
  
| 175 | 
      }  | 
  
| 176 | 
      }  | 
  
| 177 | 
      if (!isset($instance)) {  | 
  
| 178 | 
      $appModel = 'AppModel';  | 
  
| 179 | 
      if ($strict) {  | 
  
| 180 | 
      return false;  | 
  
| 181 | 
      } elseif ($plugin && class_exists($plugin . 'AppModel')) {  | 
  
| 182 | 
      $appModel = $plugin . 'AppModel';  | 
  
| 183 | 
      }  | 
  
| 184 | 
       | 
  
| 185 | 
      $settings['name'] = $class;  | 
  
| 186 | 
      $instance = new $appModel($settings);  | 
  
| 187 | 
      }  | 
  
| 188 | 
      $_this->map($alias, $class);  | 
  
| 189 | 
      }  | 
  
| 190 | 
      }  | 
  
| 191 | 
       | 
  
| 192 | 
      if ($count > 1) {  | 
  
| 193 | 
      return true;  | 
  
| 194 | 
      }  | 
  
| 195 | 
      return $instance;  | 
  
| 196 | 
      }  | 
  
| 197 | 
       | 
  
| 198 | 
      /**
     | 
  
| 199 | 
       * Add $object to the registry, associating it with the name $key.
     | 
  
| 200 | 
       *
     | 
  
| 201 | 
       * @param string $key Key for the object in registry
     | 
  
| 202 | 
       * @param object $object Object to store
     | 
  
| 203 | 
       * @return bool True if the object was written, false if $key already exists
     | 
  
| 204 | 
       */
     | 
  
| 205 | 
      public static function addObject($key, $object) {  | 
  
| 206 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 207 | 
      $key = Inflector::underscore($key);  | 
  
| 208 | 
      if (!isset($_this->_objects[$key])) {  | 
  
| 209 | 
      $_this->_objects[$key] = $object;  | 
  
| 210 | 
      return true;  | 
  
| 211 | 
      }  | 
  
| 212 | 
      return false;  | 
  
| 213 | 
      }  | 
  
| 214 | 
       | 
  
| 215 | 
      /**
     | 
  
| 216 | 
       * Remove object which corresponds to given key.
     | 
  
| 217 | 
       *
     | 
  
| 218 | 
       * @param string $key Key of object to remove from registry
     | 
  
| 219 | 
       * @return void
     | 
  
| 220 | 
       */
     | 
  
| 221 | 
      public static function removeObject($key) {  | 
  
| 222 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 223 | 
      $key = Inflector::underscore($key);  | 
  
| 224 | 
      if (isset($_this->_objects[$key])) {  | 
  
| 225 | 
      unset($_this->_objects[$key]);  | 
  
| 226 | 
      }  | 
  
| 227 | 
      }  | 
  
| 228 | 
       | 
  
| 229 | 
      /**
     | 
  
| 230 | 
       * Returns true if given key is present in the ClassRegistry.
     | 
  
| 231 | 
       *
     | 
  
| 232 | 
       * @param string $key Key to look for
     | 
  
| 233 | 
       * @return bool true if key exists in registry, false otherwise
     | 
  
| 234 | 
       */
     | 
  
| 235 | 
      public static function isKeySet($key) {  | 
  
| 236 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 237 | 
      $key = Inflector::underscore($key);  | 
  
| 238 | 
       | 
  
| 239 | 
      return isset($_this->_objects[$key]) || isset($_this->_map[$key]);  | 
  
| 240 | 
      }  | 
  
| 241 | 
       | 
  
| 242 | 
      /**
     | 
  
| 243 | 
       * Get all keys from the registry.
     | 
  
| 244 | 
       *
     | 
  
| 245 | 
       * @return array Set of keys stored in registry
     | 
  
| 246 | 
       */
     | 
  
| 247 | 
      public static function keys() {  | 
  
| 248 | 
      return array_keys(ClassRegistry::getInstance()->_objects);  | 
  
| 249 | 
      }  | 
  
| 250 | 
       | 
  
| 251 | 
      /**
     | 
  
| 252 | 
       * Return object which corresponds to given key.
     | 
  
| 253 | 
       *
     | 
  
| 254 | 
       * @param string $key Key of object to look for
     | 
  
| 255 | 
       * @return mixed Object stored in registry or boolean false if the object does not exist.
     | 
  
| 256 | 
       */
     | 
  
| 257 | 
      public static function getObject($key) {  | 
  
| 258 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 259 | 
      $key = Inflector::underscore($key);  | 
  
| 260 | 
      $return = false;  | 
  
| 261 | 
      if (isset($_this->_objects[$key])) {  | 
  
| 262 | 
      $return = $_this->_objects[$key];  | 
  
| 263 | 
                      } else {
     | 
  
| 264 | 
      $key = $_this->_getMap($key);  | 
  
| 265 | 
      if (isset($_this->_objects[$key])) {  | 
  
| 266 | 
      $return = $_this->_objects[$key];  | 
  
| 267 | 
      }  | 
  
| 268 | 
      }  | 
  
| 269 | 
      return $return;  | 
  
| 270 | 
      }  | 
  
| 271 | 
       | 
  
| 272 | 
      /**
     | 
  
| 273 | 
       * Sets the default constructor parameter for an object type
     | 
  
| 274 | 
       *
     | 
  
| 275 | 
       * @param string $type Type of object. If this parameter is omitted, defaults to "Model"
     | 
  
| 276 | 
       * @param array $param The parameter that will be passed to object constructors when objects
     | 
  
| 277 | 
       *                      of $type are created
     | 
  
| 278 | 
       * @return mixed Void if $param is being set. Otherwise, if only $type is passed, returns
     | 
  
| 279 | 
       *               the previously-set value of $param, or null if not set.
     | 
  
| 280 | 
       */
     | 
  
| 281 | 
      public static function config($type, $param = array()) {  | 
  
| 282 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 283 | 
       | 
  
| 284 | 
      if (empty($param) && is_array($type)) {  | 
  
| 285 | 
      $param = $type;  | 
  
| 286 | 
      $type = 'Model';  | 
  
| 287 | 
      } elseif ($param === null) {  | 
  
| 288 | 
      unset($_this->_config[$type]);  | 
  
| 289 | 
      } elseif (empty($param) && is_string($type)) {  | 
  
| 290 | 
      return isset($_this->_config[$type]) ? $_this->_config[$type] : null;  | 
  
| 291 | 
      }  | 
  
| 292 | 
      if (isset($_this->_config[$type]['testing'])) {  | 
  
| 293 | 
      $param['testing'] = true;  | 
  
| 294 | 
      }  | 
  
| 295 | 
      $_this->_config[$type] = $param;  | 
  
| 296 | 
      }  | 
  
| 297 | 
       | 
  
| 298 | 
      /**
     | 
  
| 299 | 
       * Checks to see if $alias is a duplicate $class Object
     | 
  
| 300 | 
       *
     | 
  
| 301 | 
       * @param string $alias Alias to check.
     | 
  
| 302 | 
       * @param string $class Class name.
     | 
  
| 303 | 
       * @return bool
     | 
  
| 304 | 
       */
     | 
  
| 305 | 
      protected function &_duplicate($alias, $class) {  | 
  
| 306 | 
      $duplicate = false;  | 
  
| 307 | 
      if ($this->isKeySet($alias)) {  | 
  
| 308 | 
      $model = $this->getObject($alias);  | 
  
| 309 | 
      if (is_object($model) && ($model instanceof $class || $model->alias === $class)) {  | 
  
| 310 | 
      $duplicate = $model;  | 
  
| 311 | 
      }  | 
  
| 312 | 
      unset($model);  | 
  
| 313 | 
      }  | 
  
| 314 | 
      return $duplicate;  | 
  
| 315 | 
      }  | 
  
| 316 | 
       | 
  
| 317 | 
      /**
     | 
  
| 318 | 
       * Add a key name pair to the registry to map name to class in the registry.
     | 
  
| 319 | 
       *
     | 
  
| 320 | 
       * @param string $key Key to include in map
     | 
  
| 321 | 
       * @param string $name Key that is being mapped
     | 
  
| 322 | 
       * @return void
     | 
  
| 323 | 
       */
     | 
  
| 324 | 
      public static function map($key, $name) {  | 
  
| 325 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 326 | 
      $key = Inflector::underscore($key);  | 
  
| 327 | 
      $name = Inflector::underscore($name);  | 
  
| 328 | 
      if (!isset($_this->_map[$key])) {  | 
  
| 329 | 
      $_this->_map[$key] = $name;  | 
  
| 330 | 
      }  | 
  
| 331 | 
      }  | 
  
| 332 | 
       | 
  
| 333 | 
      /**
     | 
  
| 334 | 
       * Get all keys from the map in the registry.
     | 
  
| 335 | 
       *
     | 
  
| 336 | 
       * @return array Keys of registry's map
     | 
  
| 337 | 
       */
     | 
  
| 338 | 
      public static function mapKeys() {  | 
  
| 339 | 
      return array_keys(ClassRegistry::getInstance()->_map);  | 
  
| 340 | 
      }  | 
  
| 341 | 
       | 
  
| 342 | 
      /**
     | 
  
| 343 | 
       * Return the name of a class in the registry.
     | 
  
| 344 | 
       *
     | 
  
| 345 | 
       * @param string $key Key to find in map
     | 
  
| 346 | 
       * @return string Mapped value
     | 
  
| 347 | 
       */
     | 
  
| 348 | 
      protected function _getMap($key) {  | 
  
| 349 | 
      if (isset($this->_map[$key])) {  | 
  
| 350 | 
      return $this->_map[$key];  | 
  
| 351 | 
      }  | 
  
| 352 | 
      }  | 
  
| 353 | 
       | 
  
| 354 | 
      /**
     | 
  
| 355 | 
       * Flushes all objects from the ClassRegistry.
     | 
  
| 356 | 
       *
     | 
  
| 357 | 
       * @return void
     | 
  
| 358 | 
       */
     | 
  
| 359 | 
      public static function flush() {  | 
  
| 360 | 
      $_this = ClassRegistry::getInstance();  | 
  
| 361 | 
      $_this->_objects = array();  | 
  
| 362 | 
      $_this->_map = array();  | 
  
| 363 | 
      }  | 
  
| 364 | 
       | 
  
| 365 | 
      }  |