/libraries/koowa/factory/factory.php

https://github.com/raeldc/com_learn · PHP · 332 lines · 149 code · 45 blank · 138 comment · 19 complexity · 9af689ade1d568782c0e45438b9cae65 MD5 · raw file

  1. <?php
  2. /**
  3. * @version $Id: factory.php 3826 2011-09-01 02:19:59Z johanjanssens $
  4. * @category Koowa
  5. * @package Koowa_Factory
  6. * @copyright Copyright (C) 2007 - 2010 Johan Janssens. All rights reserved.
  7. * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
  8. * @link http://www.nooku.org
  9. */
  10. //Instantiate the factory singleton
  11. KFactory::instantiate();
  12. /**
  13. * KFactory class
  14. *
  15. * @author Johan Janssens <johan@nooku.org>
  16. * @category Koowa
  17. * @package Koowa_Factory
  18. * @static
  19. * @uses KIdentifier
  20. * @uses KCommandContext
  21. */
  22. class KFactory
  23. {
  24. /**
  25. * The object container
  26. *
  27. * @var array
  28. */
  29. protected static $_registry = null;
  30. /**
  31. * Adapter list
  32. *
  33. * @var array
  34. */
  35. protected static $_adapters = null;
  36. /**
  37. * The identifier alias map
  38. *
  39. * @var array
  40. */
  41. protected static $_identifier_map = array();
  42. /**
  43. * The mixin map
  44. *
  45. * @var array
  46. */
  47. protected static $_mixin_map = array();
  48. /**
  49. * Constructor
  50. *
  51. * Prevent creating instances of this class by making the contructor private
  52. */
  53. final private function __construct(KConfig $config)
  54. {
  55. self::$_registry = new ArrayObject();
  56. }
  57. /**
  58. * Clone
  59. *
  60. * Prevent creating clones of this class
  61. */
  62. final private function __clone() { }
  63. /**
  64. * Force creation of a singleton
  65. *
  66. * @return void
  67. */
  68. public static function instantiate($config = array())
  69. {
  70. static $instance;
  71. if ($instance === NULL)
  72. {
  73. if(!$config instanceof KConfig) {
  74. $config = new KConfig($config);
  75. }
  76. $instance = new self($config);
  77. }
  78. return $instance;
  79. }
  80. /**
  81. * Returns an identifier string.
  82. *
  83. * Accepts various types of parameters and returns a valid identifier. Parameters can either be an
  84. * object that implements KObjectIdentifiable, or a KIdentifierInterface, or valid identifier
  85. * string. Function will also check for identifier mappings and return the mapped identifier.
  86. *
  87. * @param mixed An object that implements KObjectIdentifiable, an object that
  88. * implements KIdentifierInterface or valid identifier string
  89. * @return KIdentifier
  90. */
  91. public static function identify($identifier)
  92. {
  93. if(!is_string($identifier))
  94. {
  95. if($identifier instanceof KObjectIdentifiable) {
  96. $identifier = $identifier->getIdentifier();
  97. }
  98. }
  99. $alias = (string) $identifier;
  100. if(array_key_exists($alias, self::$_identifier_map)) {
  101. $identifier = self::$_identifier_map[$alias];
  102. }
  103. if(is_string($identifier)) {
  104. $identifier = new KIdentifier($identifier);
  105. }
  106. return $identifier;
  107. }
  108. /**
  109. * Get an instance of a class based on a class identifier only creating it
  110. * if it doesn't exist yet.
  111. *
  112. * @param string|object The class identifier or identifier object
  113. * @param array An optional associative array of configuration settings.
  114. * @throws KFactoryException
  115. * @return object Return object on success, throws exception on failure
  116. */
  117. public static function get($identifier, array $config = array())
  118. {
  119. $objIdentifier = self::identify($identifier);
  120. $strIdentifier = (string) $objIdentifier;
  121. if(!self::$_registry->offsetExists($strIdentifier))
  122. {
  123. //Instantiate the identifier
  124. $instance = self::_instantiate($objIdentifier, $config);
  125. //Perform the mixin
  126. self::_mixin($strIdentifier, $instance);
  127. }
  128. else $instance = self::$_registry->offsetGet($strIdentifier);
  129. return $instance;
  130. }
  131. /**
  132. * Insert the object instance using the identifier
  133. *
  134. * @param mixed The class identifier
  135. * @param object The object instance to store
  136. */
  137. public static function set($identifier, $object)
  138. {
  139. $objIdentifier = self::identify($identifier);
  140. $strIdentifier = (string) $objIdentifier;
  141. self::$_registry->offsetSet($strIdentifier, $object);
  142. }
  143. /**
  144. * Remove the object instance using the identifier
  145. *
  146. * @param mixed The class identifier
  147. * @return boolean Returns TRUE on success or FALSE on failure.
  148. */
  149. public static function del($identifier)
  150. {
  151. $objIdentifier = self::identify($identifier);
  152. $strIdentifier = (string) $objIdentifier;
  153. if(self::$_registry->offsetExists($strIdentifier)) {
  154. self::$_registry->offsetUnset($strIdentifier);
  155. return true;
  156. }
  157. return false;
  158. }
  159. /**
  160. * Check if the object instance exists based on the identifier
  161. *
  162. * @param mixed The class identifier
  163. * @return boolean Returns TRUE on success or FALSE on failure.
  164. */
  165. public static function has($identifier)
  166. {
  167. try
  168. {
  169. $objIdentifier = self::identify($identifier);
  170. $strIdentifier = (string) $objIdentifier;
  171. $result = (bool) self::$_registry->offsetExists($strIdentifier);
  172. } catch (KIdentifierException $e) {
  173. $result = false;
  174. }
  175. return $result;
  176. }
  177. /**
  178. * Creates an alias for an identifier
  179. *
  180. * @param mixed The alias
  181. * @param mixed The class indentifier or identifier object
  182. */
  183. public static function map($alias, $identifier)
  184. {
  185. $identifier = self::identify($identifier);
  186. self::$_identifier_map[$alias] = $identifier;
  187. }
  188. /**
  189. * Set a mixin or an array of mixins for an identifier
  190. *
  191. * The mixins are mixed when the indentified object is first instantiated see {@linkk get} and
  192. * {$link tmp} Mixins are also added to existing singleton objects that already exist in the
  193. * object store.
  194. *
  195. * @param mixed An identifier string, KIdentfier object or an array of identifiers
  196. * @param string|array A mixin identifier or a array of mixin identifiers
  197. * @see KObject::mixin
  198. */
  199. public static function mix($identifiers, $mixins)
  200. {
  201. settype($identifiers, 'array');
  202. settype($mixins, 'array');
  203. foreach($identifiers as $identifier)
  204. {
  205. $objIdentifier = self::identify($identifier);
  206. $strIdentifier = (string) $objIdentifier;
  207. if (!isset(self::$_mixin_map[$strIdentifier]) ) {
  208. self::$_mixin_map[$strIdentifier] = array();
  209. }
  210. self::$_mixin_map[$strIdentifier] = array_unique(array_merge(self::$_mixin_map[$strIdentifier], $mixins));
  211. if (self::$_registry->offsetExists($strIdentifier))
  212. {
  213. $instance = self::$_registry->offsetGet($strIdentifier);
  214. //Perform the mixin
  215. self::_mixin($strIdentifier, $instance);
  216. }
  217. }
  218. }
  219. /**
  220. * Add a factory adapter
  221. *
  222. * @param object A KFactoryAdapter
  223. * @return void
  224. */
  225. public static function addAdapter(KFactoryAdapterInterface $adapter)
  226. {
  227. self::$_adapters[$adapter->getType()] = $adapter;
  228. }
  229. /**
  230. * Perform the actual mixin of all registered mixins with an object
  231. *
  232. * @param string The identifier string
  233. * @param object A KObject instance to used as the mixer
  234. * @return void
  235. */
  236. protected static function _mixin($identifier, $instance)
  237. {
  238. if(isset(self::$_mixin_map[$identifier]) && $instance instanceof KObject)
  239. {
  240. $mixins = self::$_mixin_map[$identifier];
  241. foreach($mixins as $mixin)
  242. {
  243. $mixin = KFactory::get($mixin, array('mixer'=> $instance));
  244. $instance->mixin($mixin);
  245. }
  246. }
  247. }
  248. /**
  249. * Get an instance of a class based on a class identifier
  250. *
  251. * @param string The identifier string
  252. * @param array An optional associative array of configuration settings.
  253. * @throws KFactoryException
  254. * @return object Return object on success, throws exception on failure
  255. */
  256. protected static function _instantiate($identifier, array $config = array())
  257. {
  258. $config = new KConfig($config);
  259. if(isset(self::$_adapters[$identifier->type]))
  260. {
  261. $result = self::$_adapters[$identifier->type]->instantiate($identifier, $config);
  262. //If we get a string returned we assume it's a classname
  263. if(is_string($result))
  264. {
  265. //Set the classname
  266. $identifier->classname = $result;
  267. //Set the filepath
  268. $identifier->filepath = KLoader::path($identifier);
  269. //If the object is indentifiable push the identifier in through the constructor
  270. if(array_key_exists('KObjectIdentifiable', class_implements($identifier->classname))) {
  271. $config->identifier = $identifier;
  272. }
  273. // If the class has an instantiate method call it
  274. if(is_callable(array($identifier->classname, 'instantiate'), false)) {
  275. $result = call_user_func(array($identifier->classname, 'instantiate'), $config);
  276. }
  277. else {
  278. $result = new $identifier->classname($config);
  279. }
  280. }
  281. }
  282. if(!is_object($result)) {
  283. throw new KFactoryException('Cannot create object from identifier : '.$identifier);
  284. }
  285. return $result;
  286. }
  287. }