/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php

https://gitlab.com/vannh/portal_training · PHP · 249 lines · 113 code · 21 blank · 115 comment · 10 complexity · 4c3caf460046918b066c88bd5f4fd91a 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\ORM;
  16. use BadMethodCallException;
  17. use Cake\Core\App;
  18. use Cake\Core\ObjectRegistry;
  19. use Cake\Event\EventManagerTrait;
  20. use Cake\ORM\Behavior;
  21. use Cake\ORM\Exception\MissingBehaviorException;
  22. use Cake\ORM\Table;
  23. use LogicException;
  24. /**
  25. * BehaviorRegistry is used as a registry for loaded behaviors and handles loading
  26. * and constructing behavior objects.
  27. *
  28. * This class also provides method for checking and dispatching behavior methods.
  29. */
  30. class BehaviorRegistry extends ObjectRegistry
  31. {
  32. use EventManagerTrait;
  33. /**
  34. * The table using this registry.
  35. *
  36. * @var \Cake\ORM\Table
  37. */
  38. protected $_table;
  39. /**
  40. * Method mappings.
  41. *
  42. * @var array
  43. */
  44. protected $_methodMap = [];
  45. /**
  46. * Finder method mappings.
  47. *
  48. * @var array
  49. */
  50. protected $_finderMap = [];
  51. /**
  52. * Constructor
  53. *
  54. * @param \Cake\ORM\Table $table The table this registry is attached to
  55. */
  56. public function __construct(Table $table)
  57. {
  58. $this->_table = $table;
  59. $this->eventManager($table->eventManager());
  60. }
  61. /**
  62. * Resolve a behavior classname.
  63. *
  64. * Part of the template method for Cake\Core\ObjectRegistry::load()
  65. *
  66. * @param string $class Partial classname to resolve.
  67. * @return string|false Either the correct classname or false.
  68. */
  69. protected function _resolveClassName($class)
  70. {
  71. $result = App::className($class, 'Model/Behavior', 'Behavior');
  72. if (!$result) {
  73. $result = App::className($class, 'ORM/Behavior', 'Behavior');
  74. }
  75. return $result;
  76. }
  77. /**
  78. * Throws an exception when a behavior is missing.
  79. *
  80. * Part of the template method for Cake\Core\ObjectRegistry::load()
  81. *
  82. * @param string $class The classname that is missing.
  83. * @param string $plugin The plugin the behavior is missing in.
  84. * @return void
  85. * @throws \Cake\ORM\Exception\MissingBehaviorException
  86. */
  87. protected function _throwMissingClassError($class, $plugin)
  88. {
  89. throw new MissingBehaviorException([
  90. 'class' => $class . 'Behavior',
  91. 'plugin' => $plugin
  92. ]);
  93. }
  94. /**
  95. * Create the behavior instance.
  96. *
  97. * Part of the template method for Cake\Core\ObjectRegistry::load()
  98. * Enabled behaviors will be registered with the event manager.
  99. *
  100. * @param string $class The classname that is missing.
  101. * @param string $alias The alias of the object.
  102. * @param array $config An array of config to use for the behavior.
  103. * @return Behavior The constructed behavior class.
  104. */
  105. protected function _create($class, $alias, $config)
  106. {
  107. $instance = new $class($this->_table, $config);
  108. $enable = isset($config['enabled']) ? $config['enabled'] : true;
  109. if ($enable) {
  110. $this->eventManager()->on($instance);
  111. }
  112. $methods = $this->_getMethods($instance, $class, $alias);
  113. $this->_methodMap += $methods['methods'];
  114. $this->_finderMap += $methods['finders'];
  115. return $instance;
  116. }
  117. /**
  118. * Get the behavior methods and ensure there are no duplicates.
  119. *
  120. * Use the implementedEvents() method to exclude callback methods.
  121. * Methods starting with `_` will be ignored, as will methods
  122. * declared on Cake\ORM\Behavior
  123. *
  124. * @param \Cake\ORM\Behavior $instance The behavior to get methods from.
  125. * @param string $class The classname that is missing.
  126. * @param string $alias The alias of the object.
  127. * @return array A list of implemented finders and methods.
  128. * @throws \LogicException when duplicate methods are connected.
  129. */
  130. protected function _getMethods(Behavior $instance, $class, $alias)
  131. {
  132. $finders = array_change_key_case($instance->implementedFinders());
  133. $methods = array_change_key_case($instance->implementedMethods());
  134. foreach ($finders as $finder => $methodName) {
  135. if (isset($this->_finderMap[$finder]) && $this->has($this->_finderMap[$finder][0])) {
  136. $duplicate = $this->_finderMap[$finder];
  137. $error = sprintf(
  138. '%s contains duplicate finder "%s" which is already provided by "%s"',
  139. $class,
  140. $finder,
  141. $duplicate[0]
  142. );
  143. throw new LogicException($error);
  144. }
  145. $finders[$finder] = [$alias, $methodName];
  146. }
  147. foreach ($methods as $method => $methodName) {
  148. if (isset($this->_methodMap[$method]) && $this->has($this->_methodMap[$method][0])) {
  149. $duplicate = $this->_methodMap[$method];
  150. $error = sprintf(
  151. '%s contains duplicate method "%s" which is already provided by "%s"',
  152. $class,
  153. $method,
  154. $duplicate[0]
  155. );
  156. throw new LogicException($error);
  157. }
  158. $methods[$method] = [$alias, $methodName];
  159. }
  160. return compact('methods', 'finders');
  161. }
  162. /**
  163. * Check if any loaded behavior implements a method.
  164. *
  165. * Will return true if any behavior provides a public non-finder method
  166. * with the chosen name.
  167. *
  168. * @param string $method The method to check for.
  169. * @return bool
  170. */
  171. public function hasMethod($method)
  172. {
  173. $method = strtolower($method);
  174. return isset($this->_methodMap[$method]);
  175. }
  176. /**
  177. * Check if any loaded behavior implements the named finder.
  178. *
  179. * Will return true if any behavior provides a public method with
  180. * the chosen name.
  181. *
  182. * @param string $method The method to check for.
  183. * @return bool
  184. */
  185. public function hasFinder($method)
  186. {
  187. $method = strtolower($method);
  188. return isset($this->_finderMap[$method]);
  189. }
  190. /**
  191. * Invoke a method on a behavior.
  192. *
  193. * @param string $method The method to invoke.
  194. * @param array $args The arguments you want to invoke the method with.
  195. * @return mixed The return value depends on the underlying behavior method.
  196. * @throws \BadMethodCallException When the method is unknown.
  197. */
  198. public function call($method, array $args = [])
  199. {
  200. $method = strtolower($method);
  201. if ($this->hasMethod($method) && $this->has($this->_methodMap[$method][0])) {
  202. list($behavior, $callMethod) = $this->_methodMap[$method];
  203. return call_user_func_array([$this->_loaded[$behavior], $callMethod], $args);
  204. }
  205. throw new BadMethodCallException(
  206. sprintf('Cannot call "%s" it does not belong to any attached behavior.', $method)
  207. );
  208. }
  209. /**
  210. * Invoke a finder on a behavior.
  211. *
  212. * @param string $type The finder type to invoke.
  213. * @param array $args The arguments you want to invoke the method with.
  214. * @return mixed The return value depends on the underlying behavior method.
  215. * @throws \BadMethodCallException When the method is unknown.
  216. */
  217. public function callFinder($type, array $args = [])
  218. {
  219. $type = strtolower($type);
  220. if ($this->hasFinder($type) && $this->has($this->_finderMap[$type][0])) {
  221. list($behavior, $callMethod) = $this->_finderMap[$type];
  222. return call_user_func_array([$this->_loaded[$behavior], $callMethod], $args);
  223. }
  224. throw new BadMethodCallException(
  225. sprintf('Cannot call finder "%s" it does not belong to any attached behavior.', $type)
  226. );
  227. }
  228. }