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