PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/lithium/libraries/lithium/core/Adaptable.php

https://github.com/brtriver/sukonv
PHP | 311 lines | 144 code | 30 blank | 137 comment | 26 complexity | 9e0e27a0911195d9462c20c746ef4baa MD5 | raw file
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2010, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\core;
  9. use lithium\util\Collection;
  10. use lithium\core\Environment;
  11. use SplDoublyLinkedList;
  12. use lithium\core\ConfigException;
  13. /**
  14. * The `Adaptable` static class is the base class from which all adapter implementations extend.
  15. *
  16. * `Adaptable` provides the logic necessary for generic configuration of named adapter
  17. * configurations (such as the ones used in `Cache`) as well as a unified method of locating and
  18. * obtaining an instance to a specified adapter.
  19. *
  20. * All immediate subclasses to `Adaptable` must define the protected attributes `$_configurations`
  21. * and `$_adapters`. The former is where all local adapter named configurations will be
  22. * stored (as an array of named configuration settings), and the latter must contain the
  23. * `Libraries::locate()`-compatible path string (or array of strings) specifying how adapter classes
  24. * should be located.
  25. *
  26. * This static class should **never** be called explicitly.
  27. */
  28. class Adaptable extends \lithium\core\StaticObject {
  29. /**
  30. * To be re-defined in sub-classes.
  31. *
  32. * @var object `Collection` of configurations, indexed by name.
  33. */
  34. protected static $_configurations = array();
  35. /**
  36. * To be re-defined in sub-classes.
  37. *
  38. * Holds the Libraries::locate() compatible path string where the strategy in question
  39. * may be found.
  40. *
  41. * @var string Path string.
  42. */
  43. protected static $_strategies = null;
  44. /**
  45. * To be re-defined in sub-classes.
  46. *
  47. * Holds the `Libraries::locate()`-compatible path string where the adapter in question
  48. * may be found.
  49. *
  50. * @var string Path string.
  51. */
  52. protected static $_adapters = null;
  53. /**
  54. * Sets configurations for a particular adaptable implementation, or returns the current
  55. * configuration settings.
  56. *
  57. * @param array $config Configurations, indexed by name.
  58. * @return object|void `Collection` of configurations or void if setting configurations.
  59. */
  60. public static function config($config = null) {
  61. if ($config && is_array($config)) {
  62. static::$_configurations = $config;
  63. return;
  64. }
  65. if ($config) {
  66. return static::_config($config);
  67. }
  68. $result = array();
  69. static::$_configurations = array_filter(static::$_configurations);
  70. foreach (array_keys(static::$_configurations) as $key) {
  71. $result[$key] = static::_config($key);
  72. }
  73. return $result;
  74. }
  75. /**
  76. * Clears all configurations.
  77. *
  78. * @return void
  79. */
  80. public static function reset() {
  81. static::$_configurations = array();
  82. }
  83. /**
  84. * Returns adapter class name for given `$name` configuration, using
  85. * the `$_adapter` path defined in Adaptable subclasses.
  86. *
  87. * @param string $name Class name of adapter to load.
  88. * @return object Adapter object.
  89. */
  90. public static function adapter($name = null) {
  91. $config = static::_config($name);
  92. if ($config === null) {
  93. throw new ConfigException("Configuration '{$name}' has not been defined.");
  94. }
  95. if (isset($config['object'])) {
  96. return $config['object'];
  97. }
  98. $class = static::_class($config, static::$_adapters);
  99. $settings = static::$_configurations[$name];
  100. $settings[0]['object'] = new $class($config);
  101. static::$_configurations[$name] = $settings;
  102. return static::$_configurations[$name][0]['object'];
  103. }
  104. /**
  105. * Obtain an `SplStack` of the strategies for the given `$name` configuration, using
  106. * the `$_strategies` path defined in `Adaptable` subclasses.
  107. *
  108. * @param string $name Class name of adapter to load.
  109. * @return object `SplStack` of strategies, or `null` if none are defined.
  110. */
  111. public static function strategies($name) {
  112. $config = static::_config($name);
  113. if ($config === null) {
  114. throw new ConfigException("Configuration '{$name}' has not been defined.");
  115. }
  116. if (!isset($config['strategies'])) {
  117. return null;
  118. }
  119. $stack = new SplDoublyLinkedList();
  120. foreach ($config['strategies'] as $key => $strategy) {
  121. $arguments = array();
  122. if (is_array($strategy)) {
  123. $name = $key;
  124. $class = static::_strategy($name, static::$_strategies);
  125. $index = (isset($config['strategies'][$name])) ? $name : $class;
  126. $arguments = $config['strategies'][$index];
  127. } else {
  128. $name = $strategy;
  129. $class = static::_strategy($name, static::$_strategies);
  130. }
  131. $stack->push(new $class($arguments));
  132. }
  133. return $stack;
  134. }
  135. /**
  136. * Applies strategies configured in `$name` for `$method` on `$data`.
  137. *
  138. * @param string $method The strategy method to be applied.
  139. * @param string $name The named configuration
  140. * @param mixed $data The data to which the strategies will be applied.
  141. * @param array $options If `mode` is set to 'LIFO', the strategies are applied in reverse.
  142. * order of their definition.
  143. * @return mixed Result of application of strategies to data. If no strategies
  144. * have been configured, this method will simply return the original data.
  145. */
  146. public static function applyStrategies($method, $name, $data, array $options = array()){
  147. $options += array('mode' => null);
  148. if (!$strategies = static::strategies($name)) {
  149. return $data;
  150. }
  151. if (!count($strategies)) {
  152. return $data;
  153. }
  154. if (isset($options['mode']) && ($options['mode'] === 'LIFO')) {
  155. $strategies->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);
  156. unset($options['mode']);
  157. }
  158. foreach ($strategies as $strategy) {
  159. if (method_exists($strategy, $method)) {
  160. $data = $strategy->{$method}($data, $options);
  161. }
  162. }
  163. return $data;
  164. }
  165. /**
  166. * Determines if the adapter specified in the named configuration is enabled.
  167. *
  168. * `Enabled` can mean various things, e.g. having a PECL memcached extension compiled
  169. * & loaded, as well as having the memcache server up & available.
  170. *
  171. * @param string $name The named configuration whose adapter will be checked.
  172. * @return boolean|null True if adapter is enabled, false if not. This method will
  173. * return null if no configuration under the given $name exists.
  174. */
  175. public static function enabled($name) {
  176. if (!static::_config($name)) {
  177. return null;
  178. }
  179. $adapter = static::adapter($name);
  180. return $adapter::enabled();
  181. }
  182. /**
  183. * Looks up an adapter by class by name.
  184. *
  185. * @see lithium\core\libraries::locate()
  186. * @param string $config Configuration array of class to be found.
  187. * @param array $paths Optional array of search paths that will be checked.
  188. * @return string Returns a fully-namespaced class reference to the adapter class.
  189. */
  190. protected static function _class($config, $paths = array()) {
  191. if (!$name = $config['adapter']) {
  192. $self = get_called_class();
  193. throw new ConfigException("No adapter set for configuration in class {$self}.");
  194. }
  195. if (!$class = static::_locate($paths, $name)) {
  196. $self = get_called_class();
  197. throw new ConfigException("Could not find adapter '{$name}' in class {$self}.");
  198. }
  199. return $class;
  200. }
  201. /**
  202. * Looks up a strategy by class by name.
  203. *
  204. * @see lithium\core\libraries::locate()
  205. * @param string $name The strategy to locate.
  206. * @param array $paths Optional array of search paths that will be checked.
  207. * @return string Returns a fully-namespaced class reference to the adapter class.
  208. */
  209. protected static function _strategy($name, $paths = array()) {
  210. if (!$name) {
  211. $self = get_called_class();
  212. throw new ConfigException("No strategy set for configuration in class {$self}.");
  213. }
  214. if (!$class = static::_locate($paths, $name)) {
  215. $self = get_called_class();
  216. throw new ConfigException("Could not find strategy '{$name}' in class {$self}.");
  217. }
  218. return $class;
  219. }
  220. /**
  221. * Perform library location for an array of paths or a single string-based path.
  222. *
  223. * @param string|array $paths Paths that Libraries::locate() will utilize.
  224. * @param string $name The name of the class to be located.
  225. * @return null|string Fully-namespaced path to the class, or null if not found.
  226. */
  227. protected static function _locate($paths, $name) {
  228. foreach ((array) $paths as $path) {
  229. if ($class = Libraries::locate($path, $name)) {
  230. return $class;
  231. }
  232. }
  233. return null;
  234. }
  235. /**
  236. * Gets an array of settings for the given named configuration in the current
  237. * environment.
  238. *
  239. * The default types of settings for all adapters will contain keys for:
  240. * `adapter` - The class name of the adapter
  241. * `filters` - An array of filters to be applied to the adapter methods
  242. *
  243. * @see lithium\core\Environment
  244. * @param string $name Named configuration.
  245. * @return array Settings for the named configuration.
  246. */
  247. protected static function _config($name) {
  248. if (!isset(static::$_configurations[$name])) {
  249. return null;
  250. }
  251. $settings = static::$_configurations[$name];
  252. if (isset($settings[0])) {
  253. return $settings[0];
  254. }
  255. $env = Environment::get();
  256. $config = isset($settings[$env]) ? $settings[$env] : $settings;
  257. if (isset($settings[$env]) && isset($settings[true])) {
  258. $config += $settings[true];
  259. }
  260. static::$_configurations[$name] += array(static::_initConfig($name, $config));
  261. return static::$_configurations[$name][0];
  262. }
  263. /**
  264. * A stub method called by `_config()` which allows `Adaptable` subclasses to automatically
  265. * assign or auto-generate additional configuration data, once a configuration is first
  266. * accessed. This allows configuration data to be lazy-loaded from adapters or other data
  267. * sources.
  268. *
  269. * @param string $name The name of the configuration which is being accessed. This is the key
  270. * name containing the specific set of configuration passed into `config()`.
  271. * @param array $config Contains the configuration assigned to `$name`. If this configuration is
  272. * segregated by environment, then this will contian the configuration for the
  273. * current environment.
  274. * @return array Returns the final array of settings for the given named configuration.
  275. */
  276. protected static function _initConfig($name, $config) {
  277. $defaults = array('adapter' => null, 'filters' => array());
  278. return (array) $config + $defaults;
  279. }
  280. }
  281. ?>