PageRenderTime 69ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/cakephp/cakephp/src/Core/ObjectRegistry.php

https://gitlab.com/vannh/portal_training
PHP | 318 lines | 133 code | 20 blank | 165 comment | 21 complexity | 0c1c2b75dad46c11cc041febbe468cac MD5 | raw file
  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. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Core;
  16. use Cake\Event\EventListenerInterface;
  17. use RuntimeException;
  18. /**
  19. * Acts as a registry/factory for objects.
  20. *
  21. * Provides registry & factory functionality for object types. Used
  22. * as a super class for various composition based re-use features in CakePHP.
  23. *
  24. * Each subclass needs to implement the various abstract methods to complete
  25. * the template method load().
  26. *
  27. * The ObjectRegistry is EventManager aware, but each extending class will need to use
  28. * \Cake\Event\EventManagerTrait to attach and detach on set and bind
  29. *
  30. * @see \Cake\Controller\ComponentRegistry
  31. * @see \Cake\View\HelperRegistry
  32. * @see \Cake\Console\TaskRegistry
  33. */
  34. abstract class ObjectRegistry
  35. {
  36. /**
  37. * Map of loaded objects.
  38. *
  39. * @var array
  40. */
  41. protected $_loaded = [];
  42. /**
  43. * Loads/constructs an object instance.
  44. *
  45. * Will return the instance in the registry if it already exists.
  46. * If a subclass provides event support, you can use `$config['enabled'] = false`
  47. * to exclude constructed objects from being registered for events.
  48. *
  49. * Using Cake\Controller\Controller::$components as an example. You can alias
  50. * an object by setting the 'className' key, i.e.,
  51. *
  52. * ```
  53. * public $components = [
  54. * 'Email' => [
  55. * 'className' => '\App\Controller\Component\AliasedEmailComponent'
  56. * ];
  57. * ];
  58. * ```
  59. *
  60. * All calls to the `Email` component would use `AliasedEmail` instead.
  61. *
  62. * @param string $objectName The name/class of the object to load.
  63. * @param array $config Additional settings to use when loading the object.
  64. * @return mixed
  65. */
  66. public function load($objectName, $config = [])
  67. {
  68. list(, $name) = pluginSplit($objectName);
  69. $loaded = isset($this->_loaded[$name]);
  70. if ($loaded && !empty($config)) {
  71. $this->_checkDuplicate($name, $config);
  72. }
  73. if ($loaded) {
  74. return $this->_loaded[$name];
  75. }
  76. if (is_array($config) && isset($config['className'])) {
  77. $objectName = $config['className'];
  78. }
  79. $className = $this->_resolveClassName($objectName);
  80. if (!$className || (is_string($className) && !class_exists($className))) {
  81. list($plugin, $objectName) = pluginSplit($objectName);
  82. $this->_throwMissingClassError($objectName, $plugin);
  83. }
  84. $instance = $this->_create($className, $name, $config);
  85. $this->_loaded[$name] = $instance;
  86. return $instance;
  87. }
  88. /**
  89. * Check for duplicate object loading.
  90. *
  91. * If a duplicate is being loaded and has different configuration, that is
  92. * bad and an exception will be raised.
  93. *
  94. * An exception is raised, as replacing the object will not update any
  95. * references other objects may have. Additionally, simply updating the runtime
  96. * configuration is not a good option as we may be missing important constructor
  97. * logic dependent on the configuration.
  98. *
  99. * @param string $name The name of the alias in the registry.
  100. * @param array $config The config data for the new instance.
  101. * @return void
  102. * @throws \RuntimeException When a duplicate is found.
  103. */
  104. protected function _checkDuplicate($name, $config)
  105. {
  106. $existing = $this->_loaded[$name];
  107. $msg = sprintf('The "%s" alias has already been loaded', $name);
  108. $hasConfig = method_exists($existing, 'config');
  109. if (!$hasConfig) {
  110. throw new RuntimeException($msg);
  111. }
  112. if (empty($config)) {
  113. return;
  114. }
  115. $existingConfig = $existing->config();
  116. unset($config['enabled'], $existingConfig['enabled']);
  117. $fail = false;
  118. foreach ($config as $key => $value) {
  119. if (!array_key_exists($key, $existingConfig)) {
  120. $fail = true;
  121. break;
  122. }
  123. if (isset($existingConfig[$key]) && $existingConfig[$key] !== $value) {
  124. $fail = true;
  125. break;
  126. }
  127. }
  128. if ($fail) {
  129. $msg .= ' with the following config: ';
  130. $msg .= var_export($existingConfig, true);
  131. $msg .= ' which differs from ' . var_export($config, true);
  132. throw new RuntimeException($msg);
  133. }
  134. }
  135. /**
  136. * Should resolve the classname for a given object type.
  137. *
  138. * @param string $class The class to resolve.
  139. * @return string|false The resolved name or false for failure.
  140. */
  141. abstract protected function _resolveClassName($class);
  142. /**
  143. * Throw an exception when the requested object name is missing.
  144. *
  145. * @param string $class The class that is missing.
  146. * @param string $plugin The plugin $class is missing from.
  147. * @return void
  148. * @throws \Exception
  149. */
  150. abstract protected function _throwMissingClassError($class, $plugin);
  151. /**
  152. * Create an instance of a given classname.
  153. *
  154. * This method should construct and do any other initialization logic
  155. * required.
  156. *
  157. * @param string $class The class to build.
  158. * @param string $alias The alias of the object.
  159. * @param array $config The Configuration settings for construction
  160. * @return mixed
  161. */
  162. abstract protected function _create($class, $alias, $config);
  163. /**
  164. * Get the list of loaded objects.
  165. *
  166. * @return array List of object names.
  167. */
  168. public function loaded()
  169. {
  170. return array_keys($this->_loaded);
  171. }
  172. /**
  173. * Check whether or not a given object is loaded.
  174. *
  175. * @param string $name The object name to check for.
  176. * @return bool True is object is loaded else false.
  177. */
  178. public function has($name)
  179. {
  180. return isset($this->_loaded[$name]);
  181. }
  182. /**
  183. * Get loaded object instance.
  184. *
  185. * @param string $name Name of object.
  186. * @return object|null Object instance if loaded else null.
  187. */
  188. public function get($name)
  189. {
  190. if (isset($this->_loaded[$name])) {
  191. return $this->_loaded[$name];
  192. }
  193. return null;
  194. }
  195. /**
  196. * Provide public read access to the loaded objects
  197. *
  198. * @param string $name Name of property to read
  199. * @return mixed
  200. */
  201. public function __get($name)
  202. {
  203. return $this->get($name);
  204. }
  205. /**
  206. * Provide isset access to _loaded
  207. *
  208. * @param string $name Name of object being checked.
  209. * @return bool
  210. */
  211. public function __isset($name)
  212. {
  213. return isset($this->_loaded[$name]);
  214. }
  215. /**
  216. * Normalizes an object array, creates an array that makes lazy loading
  217. * easier
  218. *
  219. * @param array $objects Array of child objects to normalize.
  220. * @return array Array of normalized objects.
  221. */
  222. public function normalizeArray($objects)
  223. {
  224. $normal = [];
  225. foreach ($objects as $i => $objectName) {
  226. $config = [];
  227. if (!is_int($i)) {
  228. $config = (array)$objectName;
  229. $objectName = $i;
  230. }
  231. list(, $name) = pluginSplit($objectName);
  232. $normal[$name] = ['class' => $objectName, 'config' => $config];
  233. }
  234. return $normal;
  235. }
  236. /**
  237. * Clear loaded instances in the registry.
  238. *
  239. * If the registry subclass has an event manager, the objects will be detached from events as well.
  240. *
  241. * @return void
  242. */
  243. public function reset()
  244. {
  245. foreach (array_keys($this->_loaded) as $name) {
  246. $this->unload($name);
  247. }
  248. }
  249. /**
  250. * Set an object directly into the registry by name.
  251. *
  252. * If this collection implements events, the passed object will
  253. * be attached into the event manager
  254. *
  255. * @param string $objectName The name of the object to set in the registry.
  256. * @param object $object instance to store in the registry
  257. * @return void
  258. */
  259. public function set($objectName, $object)
  260. {
  261. list(, $name) = pluginSplit($objectName);
  262. $this->unload($objectName);
  263. if (isset($this->_eventManager) && $object instanceof EventListenerInterface) {
  264. $this->eventManager()->on($object);
  265. }
  266. $this->_loaded[$name] = $object;
  267. }
  268. /**
  269. * Remove an object from the registry.
  270. *
  271. * If this registry has an event manager, the object will be detached from any events as well.
  272. *
  273. * @param string $objectName The name of the object to remove from the registry.
  274. * @return void
  275. */
  276. public function unload($objectName)
  277. {
  278. if (empty($this->_loaded[$objectName])) {
  279. return;
  280. }
  281. $object = $this->_loaded[$objectName];
  282. if (isset($this->_eventManager) && $object instanceof EventListenerInterface) {
  283. $this->eventManager()->off($object);
  284. }
  285. unset($this->_loaded[$objectName]);
  286. }
  287. /**
  288. * Debug friendly object properties.
  289. *
  290. * @return array
  291. */
  292. public function __debugInfo()
  293. {
  294. $properties = get_object_vars($this);
  295. $properties['_loaded'] = array_keys($properties['_loaded']);
  296. return $properties;
  297. }
  298. }