/app/code/local/Balance/Lib/Model/Di/InstanceManager.php

https://bitbucket.org/dereksangshi2000/balance_lib · PHP · 350 lines · 241 code · 27 blank · 82 comment · 24 complexity · fccccf926f41cc01001640b5f31af808 MD5 · raw file

  1. <?php
  2. /*
  3. * To change this template, choose Tools | Templates
  4. * and open the template in the editor.
  5. */
  6. class Balance_Lib_Model_Di_InstanceManager
  7. {
  8. protected $_fallbackLevelLimit = 1;
  9. protected $_definitionList = null;
  10. protected $_class = null;
  11. protected $_params = array();
  12. protected $_callbacks = array();
  13. public function __construct($class = null, $params = null, $callbacks = null, $difinitionList = null)
  14. {
  15. if (isset($class))
  16. {
  17. $this->setClass($class);
  18. }
  19. if (isset($params))
  20. {
  21. $this->setParams($params);
  22. }
  23. if (isset($difinitionList))
  24. {
  25. $this->setDefinitionList($difinitionList);
  26. }
  27. if (isset($callbacks))
  28. {
  29. $this->setCallbacks($callbacks);
  30. }
  31. }
  32. public function setCallbacks($callbacks)
  33. {
  34. $this->_callbacks = $callbacks;
  35. }
  36. public function getCallbacks()
  37. {
  38. if (empty($this->_callbacks))
  39. {
  40. $this->_loadCallbacksInDefinitionList();
  41. }
  42. return $this->_callbacks;
  43. }
  44. protected function _loadCallbacksInDefinitionList()
  45. {
  46. $this->_callbacks = $this->getDefinition($this->getClass(), 'callbacks');
  47. }
  48. public function hasDefinition($class)
  49. {
  50. return (array_key_exists($class, $this->_definitionList) && !empty($this->_definitionList[$class]));
  51. }
  52. /**
  53. * Get definition of the class.
  54. *
  55. * @param string $class Name (or alias) of the class.
  56. * @param string $property Property of the class ('params' or 'callbacks').
  57. * @return mixed
  58. */
  59. public function getDefinition($class, $property = null)
  60. {
  61. if (!isset($property))
  62. {
  63. return $this->_definitionList[$class];
  64. }
  65. else
  66. {
  67. switch ($property)
  68. {
  69. case 'params':
  70. {
  71. return $this->_definitionList[$class]['params'];
  72. }
  73. case 'callbacks':
  74. {
  75. return $this->_definitionList[$class]['callbacks'];
  76. }
  77. default:
  78. {
  79. return $this->_definitionList[$class];
  80. }
  81. }
  82. }
  83. }
  84. /**
  85. * Get dependency instance.
  86. *
  87. * @param string $dependencyClass Class name.
  88. * @param array $params OPTIONAL Params for construct.
  89. * @param array $callbacks OPTIONAL Callbacks.
  90. * @param array $definitionList Definition list provided.
  91. * @return type
  92. */
  93. protected function _getDependencyInstance($dependencyClass, $params = array(), $callbacks = array(), $definitionList = array())
  94. {
  95. $Instance = new Balance_Lib_Model_Di_InstanceManager($dependencyClass, $params, $callbacks, $definitionList);
  96. return $Instance->createInstance();
  97. }
  98. /**
  99. * Fix the dependencies.
  100. * 1) Fix the dependencies of 'params' in definition list.
  101. * 2) Fix the dependencies of 'callbacks' in definition list.
  102. *
  103. * @param array $elements The array to fix (It could be 'params' or 'callbacks').
  104. * @return array Fixed array (which might contain dependency instances as defined).
  105. */
  106. protected function _fixDependencis($elements)
  107. {
  108. if (is_array($elements))
  109. {
  110. foreach ($elements as $key => $val)
  111. {
  112. // Key is marked as dependency.
  113. $dependencyClass = $this->_getDependencyClass($key);
  114. if (!empty($dependencyClass))
  115. {
  116. if ($this->hasDefinition($dependencyClass))
  117. {
  118. $definition = $this->getDefinition($dependencyClass);
  119. $params = isset($val['params']) ? $val['params'] : (isset($definition['params']) ? $definition['params'] : array());
  120. $callbacks = isset($val['callbacks']) ? $val['callbacks'] : (isset($definition['callbacks']) ? $definition['callbacks'] : array());
  121. // $Instance = new Balance_Lib_Model_Di_InstanceManager($dependencyClass, $params, $callbacks, $this->getDefinitionList());
  122. // $elements[$key] = $Instance->createInstance();
  123. $elements[$key] = $this->_getDependencyInstance($dependencyClass, $params, $callbacks, $this->getDefinitionList());
  124. }
  125. else
  126. {
  127. /**
  128. * @todo Throw exception ('Dependency defition not found') .
  129. */
  130. throw new Exception(sprintf('Dependency class %s defition not found', $dependencyClass));
  131. }
  132. }
  133. // Value is marked as dependency.
  134. $dependencyClass = $this->_getDependencyClass($val);
  135. if (!empty($dependencyClass))
  136. {
  137. if ($this->hasDefinition($dependencyClass))
  138. {
  139. $definition = $this->getDefinition($dependencyClass);
  140. $params = isset($definition['params']) ? $definition['params'] : array();
  141. $callbacks = isset($definition['callbacks']) ? $definition['callbacks'] : array();
  142. // $Instance = new Balance_Lib_Model_Di_InstanceManager($dependencyClass, $params, $callbacks, $this->getDefinitionList());
  143. // $elements[$key] = $Instance->createInstance();
  144. $elements[$key] = $this->_getDependencyInstance($dependencyClass, $params, $callbacks, $this->getDefinitionList());
  145. }
  146. else
  147. {
  148. /**
  149. * @todo Throw exception ('Dependency defition not found') .
  150. */
  151. throw new Exception(sprintf('Dependency class %s defition not found', $dependencyClass));
  152. }
  153. }
  154. }
  155. return $elements;
  156. }
  157. }
  158. /**
  159. * Get dependency class.
  160. * If the given value is marked as a dependency class, then the format in the defition list should look like this: '_d::NAME_OR_ALIAS_OF_THE_CLASS'
  161. *
  162. * @param string $ele The element to evaluate.
  163. * @return mixed Return the class name (or alias) if it's a dependency class, or false otherwise.
  164. */
  165. protected function _getDependencyClass($ele)
  166. {
  167. if (preg_match("/^_d::(.+)/", $ele, $matches))
  168. {
  169. return $matches[1];
  170. }
  171. return false;
  172. }
  173. public function setDefinitionList($difinitionList)
  174. {
  175. $this->_definitionList = $difinitionList;
  176. }
  177. public function getDefinitionList()
  178. {
  179. return $this->_definitionList;
  180. }
  181. public function setClass($class)
  182. {
  183. $this->_class = $class;
  184. }
  185. public function getClass()
  186. {
  187. return $this->_class;
  188. }
  189. public function setParams($params)
  190. {
  191. $this->_params = $params;
  192. }
  193. public function getParams()
  194. {
  195. return $this->_params;
  196. }
  197. public function createInstance()
  198. {
  199. $instance = $this->_createInstanceByClass($this->getClass(), $this->getParams());
  200. $this->_processCallbacks($instance);
  201. if (!is_object($instance))
  202. {
  203. /**
  204. * @todo Throw exception (No instance created).
  205. */
  206. throw new Exception('No instance created for class: '.$this->getClass());
  207. }
  208. return $instance;
  209. }
  210. /**
  211. * Process callback functions.
  212. *
  213. * @param object $instance The instance for the callback functions.
  214. * @return mixed
  215. */
  216. protected function _processCallbacks($instance)
  217. {
  218. $callbacks = $this->getCallbacks();
  219. if (empty($callbacks))
  220. {
  221. return;
  222. }
  223. if (!is_array($callbacks))
  224. {
  225. $callbacks = array($callbacks);
  226. }
  227. // Run callback functions.
  228. foreach ($callbacks as $callback)
  229. {
  230. if (!isset($callback['method']))
  231. {
  232. /**
  233. * @todo Throw exception ('No method definied for callback')
  234. */
  235. continue;
  236. }
  237. if (method_exists($instance, $callback['method']))
  238. {
  239. $callback['params'] = isset($callback['params']) ? $callback['params'] : array();
  240. $params = $this->_fixDependencis($callback['params']);
  241. call_user_func_array(array($instance, $callback['method']), $params);
  242. }
  243. }
  244. }
  245. /**
  246. * Create instacne based on class.
  247. * If the given class not found, try the fallbacks until the fallback limit is reached.
  248. *
  249. * @param string $class Name (or alias) of the class.
  250. * @param array $params OPTIONAL Parameters for __construct()
  251. * @param integer $fallbackLevel Fallback levels.
  252. * @return null|\class
  253. */
  254. protected function _createInstanceByClass($class, $params = array(), $fallbackLevel = 0)
  255. {
  256. if (!class_exists($class, true))
  257. {
  258. if ($fallbackLevel > $this->_fallbackLevelLimit)
  259. {
  260. return null;
  261. }
  262. $fallbackLevel++;
  263. return $this->_createInstanceByClass($this->_getFallbackClass($class, $fallbackLevel), $params, $fallbackLevel);
  264. }
  265. $params = $this->_fixDependencis($params);
  266. $params = array_values($params);
  267. /**
  268. * Most of time, the construct needs 3 params at most.
  269. */
  270. switch (count($params))
  271. {
  272. case 0:
  273. {
  274. return new $class();
  275. }
  276. case 1:
  277. {
  278. return new $class($params[0]);
  279. }
  280. case 2:
  281. {
  282. return new $class($params[0], $params[1]);
  283. }
  284. case 3:
  285. {
  286. return new $class($params[0], $params[1], $params[2]);
  287. }
  288. default:
  289. {
  290. $ref = new ReflectionClass($class);
  291. return $ref->newInstanceArgs($params);
  292. }
  293. }
  294. }
  295. /**
  296. * Get the fallback class name.
  297. *
  298. * @param string $class Alias of the class.
  299. * @param integer $fallbackLevel Fallback level.
  300. * @return string Name of the class.
  301. */
  302. protected function _getFallbackClass($class, $fallbackLevel = 1)
  303. {
  304. /**
  305. * @todo More fall backs could be put here.
  306. */
  307. switch ($fallbackLevel)
  308. {
  309. case 1:
  310. {
  311. $prefix = 'Balance_Lib_Model_';
  312. break;
  313. }
  314. default:
  315. {
  316. $prefix = 'Balance_Lib_Model_';
  317. break;
  318. }
  319. }
  320. return $prefix.str_replace(' ', '_', ucwords(str_replace('_', ' ', $class)));
  321. }
  322. }
  323. ?>