Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
12345 anikendra 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 object 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
					if (!empty($appModel)) {
185
						$settings['name'] = $class;
186
						$instance = new $appModel($settings);
187
					}
188
 
189
					if (!isset($instance)) {
190
						trigger_error(__d('cake_dev', '(ClassRegistry::init() could not create instance of %s', $class), E_USER_WARNING);
191
						return false;
192
					}
193
				}
194
				$_this->map($alias, $class);
195
			}
196
		}
197
 
198
		if ($count > 1) {
199
			return true;
200
		}
201
		return $instance;
202
	}
203
 
204
/**
205
 * Add $object to the registry, associating it with the name $key.
206
 *
207
 * @param string $key Key for the object in registry
208
 * @param object $object Object to store
209
 * @return bool True if the object was written, false if $key already exists
210
 */
211
	public static function addObject($key, $object) {
212
		$_this = ClassRegistry::getInstance();
213
		$key = Inflector::underscore($key);
214
		if (!isset($_this->_objects[$key])) {
215
			$_this->_objects[$key] = $object;
216
			return true;
217
		}
218
		return false;
219
	}
220
 
221
/**
222
 * Remove object which corresponds to given key.
223
 *
224
 * @param string $key Key of object to remove from registry
225
 * @return void
226
 */
227
	public static function removeObject($key) {
228
		$_this = ClassRegistry::getInstance();
229
		$key = Inflector::underscore($key);
230
		if (isset($_this->_objects[$key])) {
231
			unset($_this->_objects[$key]);
232
		}
233
	}
234
 
235
/**
236
 * Returns true if given key is present in the ClassRegistry.
237
 *
238
 * @param string $key Key to look for
239
 * @return bool true if key exists in registry, false otherwise
240
 */
241
	public static function isKeySet($key) {
242
		$_this = ClassRegistry::getInstance();
243
		$key = Inflector::underscore($key);
244
 
245
		return isset($_this->_objects[$key]) || isset($_this->_map[$key]);
246
	}
247
 
248
/**
249
 * Get all keys from the registry.
250
 *
251
 * @return array Set of keys stored in registry
252
 */
253
	public static function keys() {
254
		return array_keys(ClassRegistry::getInstance()->_objects);
255
	}
256
 
257
/**
258
 * Return object which corresponds to given key.
259
 *
260
 * @param string $key Key of object to look for
261
 * @return mixed Object stored in registry or boolean false if the object does not exist.
262
 */
263
	public static function getObject($key) {
264
		$_this = ClassRegistry::getInstance();
265
		$key = Inflector::underscore($key);
266
		$return = false;
267
		if (isset($_this->_objects[$key])) {
268
			$return = $_this->_objects[$key];
269
		} else {
270
			$key = $_this->_getMap($key);
271
			if (isset($_this->_objects[$key])) {
272
				$return = $_this->_objects[$key];
273
			}
274
		}
275
		return $return;
276
	}
277
 
278
/**
279
 * Sets the default constructor parameter for an object type
280
 *
281
 * @param string $type Type of object. If this parameter is omitted, defaults to "Model"
282
 * @param array $param The parameter that will be passed to object constructors when objects
283
 *                      of $type are created
284
 * @return mixed Void if $param is being set. Otherwise, if only $type is passed, returns
285
 *               the previously-set value of $param, or null if not set.
286
 */
287
	public static function config($type, $param = array()) {
288
		$_this = ClassRegistry::getInstance();
289
 
290
		if (empty($param) && is_array($type)) {
291
			$param = $type;
292
			$type = 'Model';
293
		} elseif ($param === null) {
294
			unset($_this->_config[$type]);
295
		} elseif (empty($param) && is_string($type)) {
296
			return isset($_this->_config[$type]) ? $_this->_config[$type] : null;
297
		}
298
		if (isset($_this->_config[$type]['testing'])) {
299
			$param['testing'] = true;
300
		}
301
		$_this->_config[$type] = $param;
302
	}
303
 
304
/**
305
 * Checks to see if $alias is a duplicate $class Object
306
 *
307
 * @param string $alias Alias to check.
308
 * @param string $class Class name.
309
 * @return bool
310
 */
311
	protected function &_duplicate($alias, $class) {
312
		$duplicate = false;
313
		if ($this->isKeySet($alias)) {
314
			$model = $this->getObject($alias);
315
			if (is_object($model) && ($model instanceof $class || $model->alias === $class)) {
316
				$duplicate = $model;
317
			}
318
			unset($model);
319
		}
320
		return $duplicate;
321
	}
322
 
323
/**
324
 * Add a key name pair to the registry to map name to class in the registry.
325
 *
326
 * @param string $key Key to include in map
327
 * @param string $name Key that is being mapped
328
 * @return void
329
 */
330
	public static function map($key, $name) {
331
		$_this = ClassRegistry::getInstance();
332
		$key = Inflector::underscore($key);
333
		$name = Inflector::underscore($name);
334
		if (!isset($_this->_map[$key])) {
335
			$_this->_map[$key] = $name;
336
		}
337
	}
338
 
339
/**
340
 * Get all keys from the map in the registry.
341
 *
342
 * @return array Keys of registry's map
343
 */
344
	public static function mapKeys() {
345
		return array_keys(ClassRegistry::getInstance()->_map);
346
	}
347
 
348
/**
349
 * Return the name of a class in the registry.
350
 *
351
 * @param string $key Key to find in map
352
 * @return string Mapped value
353
 */
354
	protected function _getMap($key) {
355
		if (isset($this->_map[$key])) {
356
			return $this->_map[$key];
357
		}
358
	}
359
 
360
/**
361
 * Flushes all objects from the ClassRegistry.
362
 *
363
 * @return void
364
 */
365
	public static function flush() {
366
		$_this = ClassRegistry::getInstance();
367
		$_this->_objects = array();
368
		$_this->_map = array();
369
	}
370
 
371
}