cake/libs/class_registry.php

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