StaticConfigTrait.php 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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 BadMethodCallException;
  17. use InvalidArgumentException;
  18. use LogicException;
  19. /**
  20. * A trait that provides a set of static methods to manage configuration
  21. * for classes that provide an adapter facade or need to have sets of
  22. * configuration data registered and manipulated.
  23. *
  24. * Implementing objects are expected to declare a static `$_dsnClassMap` property.
  25. */
  26. trait StaticConfigTrait
  27. {
  28. /**
  29. * Configuration sets.
  30. *
  31. * @var array
  32. */
  33. protected static $_config = [];
  34. /**
  35. * This method can be used to define configuration adapters for an application.
  36. *
  37. * To change an adapter's configuration at runtime, first drop the adapter and then
  38. * reconfigure it.
  39. *
  40. * Adapters will not be constructed until the first operation is done.
  41. *
  42. * ### Usage
  43. *
  44. * Assuming that the class' name is `Cache` the following scenarios
  45. * are supported:
  46. *
  47. * Setting a cache engine up.
  48. *
  49. * ```
  50. * Cache::setConfig('default', $settings);
  51. * ```
  52. *
  53. * Injecting a constructed adapter in:
  54. *
  55. * ```
  56. * Cache::setConfig('default', $instance);
  57. * ```
  58. *
  59. * Configure multiple adapters at once:
  60. *
  61. * ```
  62. * Cache::setConfig($arrayOfConfig);
  63. * ```
  64. *
  65. * @param string|array $key The name of the configuration, or an array of multiple configs.
  66. * @param array $config An array of name => configuration data for adapter.
  67. * @throws \BadMethodCallException When trying to modify an existing config.
  68. * @throws \LogicException When trying to store an invalid structured config array.
  69. * @return void
  70. */
  71. public static function setConfig($key, $config = null)
  72. {
  73. if ($config === null) {
  74. if (!is_array($key)) {
  75. throw new LogicException('If config is null, key must be an array.');
  76. }
  77. foreach ($key as $name => $settings) {
  78. static::setConfig($name, $settings);
  79. }
  80. return;
  81. }
  82. if (isset(static::$_config[$key])) {
  83. throw new BadMethodCallException(sprintf('Cannot reconfigure existing key "%s"', $key));
  84. }
  85. if (is_object($config)) {
  86. $config = ['className' => $config];
  87. }
  88. if (isset($config['url'])) {
  89. $parsed = static::parseDsn($config['url']);
  90. unset($config['url']);
  91. $config = $parsed + $config;
  92. }
  93. if (isset($config['engine']) && empty($config['className'])) {
  94. $config['className'] = $config['engine'];
  95. unset($config['engine']);
  96. }
  97. static::$_config[$key] = $config;
  98. }
  99. /**
  100. * Reads existing configuration.
  101. *
  102. * @param string $key The name of the configuration.
  103. * @return array|null Array of configuration data.
  104. */
  105. public static function getConfig($key)
  106. {
  107. return isset(static::$_config[$key]) ? static::$_config[$key] : null;
  108. }
  109. /**
  110. * This method can be used to define configuration adapters for an application
  111. * or read existing configuration.
  112. *
  113. * To change an adapter's configuration at runtime, first drop the adapter and then
  114. * reconfigure it.
  115. *
  116. * Adapters will not be constructed until the first operation is done.
  117. *
  118. * ### Usage
  119. *
  120. * Assuming that the class' name is `Cache` the following scenarios
  121. * are supported:
  122. *
  123. * Reading config data back:
  124. *
  125. * ```
  126. * Cache::config('default');
  127. * ```
  128. *
  129. * Setting a cache engine up.
  130. *
  131. * ```
  132. * Cache::config('default', $settings);
  133. * ```
  134. *
  135. * Injecting a constructed adapter in:
  136. *
  137. * ```
  138. * Cache::config('default', $instance);
  139. * ```
  140. *
  141. * Configure multiple adapters at once:
  142. *
  143. * ```
  144. * Cache::config($arrayOfConfig);
  145. * ```
  146. *
  147. * @deprecated 3.4.0 Use setConfig()/getConfig() instead.
  148. * @param string|array $key The name of the configuration, or an array of multiple configs.
  149. * @param array|null $config An array of name => configuration data for adapter.
  150. * @return array|null Null when adding configuration or an array of configuration data when reading.
  151. * @throws \BadMethodCallException When trying to modify an existing config.
  152. */
  153. public static function config($key, $config = null)
  154. {
  155. if ($config !== null || !is_string($key)) {
  156. static::setConfig($key, $config);
  157. return null;
  158. }
  159. return static::getConfig($key);
  160. }
  161. /**
  162. * Drops a constructed adapter.
  163. *
  164. * If you wish to modify an existing configuration, you should drop it,
  165. * change configuration and then re-add it.
  166. *
  167. * If the implementing objects supports a `$_registry` object the named configuration
  168. * will also be unloaded from the registry.
  169. *
  170. * @param string $config An existing configuration you wish to remove.
  171. * @return bool Success of the removal, returns false when the config does not exist.
  172. */
  173. public static function drop($config)
  174. {
  175. if (!isset(static::$_config[$config])) {
  176. return false;
  177. }
  178. if (isset(static::$_registry)) {
  179. static::$_registry->unload($config);
  180. }
  181. unset(static::$_config[$config]);
  182. return true;
  183. }
  184. /**
  185. * Returns an array containing the named configurations
  186. *
  187. * @return array Array of configurations.
  188. */
  189. public static function configured()
  190. {
  191. return array_keys(static::$_config);
  192. }
  193. /**
  194. * Parses a DSN into a valid connection configuration
  195. *
  196. * This method allows setting a DSN using formatting similar to that used by PEAR::DB.
  197. * The following is an example of its usage:
  198. *
  199. * ```
  200. * $dsn = 'mysql://user:pass@localhost/database?';
  201. * $config = ConnectionManager::parseDsn($dsn);
  202. *
  203. * $dsn = 'Cake\Log\Engine\FileLog://?types=notice,info,debug&file=debug&path=LOGS';
  204. * $config = Log::parseDsn($dsn);
  205. *
  206. * $dsn = 'smtp://user:secret@localhost:25?timeout=30&client=null&tls=null';
  207. * $config = Email::parseDsn($dsn);
  208. *
  209. * $dsn = 'file:///?className=\My\Cache\Engine\FileEngine';
  210. * $config = Cache::parseDsn($dsn);
  211. *
  212. * $dsn = 'File://?prefix=myapp_cake_core_&serialize=true&duration=+2 minutes&path=/tmp/persistent/';
  213. * $config = Cache::parseDsn($dsn);
  214. * ```
  215. *
  216. * For all classes, the value of `scheme` is set as the value of both the `className`
  217. * unless they have been otherwise specified.
  218. *
  219. * Note that querystring arguments are also parsed and set as values in the returned configuration.
  220. *
  221. * @param string $dsn The DSN string to convert to a configuration array
  222. * @return array The configuration array to be stored after parsing the DSN
  223. * @throws \InvalidArgumentException If not passed a string
  224. */
  225. public static function parseDsn($dsn)
  226. {
  227. if (empty($dsn)) {
  228. return [];
  229. }
  230. if (!is_string($dsn)) {
  231. throw new InvalidArgumentException('Only strings can be passed to parseDsn');
  232. }
  233. $scheme = '';
  234. if (preg_match("/^([\w\\\]+)/", $dsn, $matches)) {
  235. $scheme = $matches[1];
  236. $dsn = preg_replace("/^([\w\\\]+)/", 'file', $dsn);
  237. }
  238. $parsed = parse_url($dsn);
  239. if ($parsed === false) {
  240. return $dsn;
  241. }
  242. $parsed['scheme'] = $scheme;
  243. $query = '';
  244. if (isset($parsed['query'])) {
  245. $query = $parsed['query'];
  246. unset($parsed['query']);
  247. }
  248. parse_str($query, $queryArgs);
  249. foreach ($queryArgs as $key => $value) {
  250. if ($value === 'true') {
  251. $queryArgs[$key] = true;
  252. } elseif ($value === 'false') {
  253. $queryArgs[$key] = false;
  254. } elseif ($value === 'null') {
  255. $queryArgs[$key] = null;
  256. }
  257. }
  258. if (isset($parsed['user'])) {
  259. $parsed['username'] = $parsed['user'];
  260. }
  261. if (isset($parsed['pass'])) {
  262. $parsed['password'] = $parsed['pass'];
  263. }
  264. unset($parsed['pass'], $parsed['user']);
  265. $parsed = $queryArgs + $parsed;
  266. if (empty($parsed['className'])) {
  267. $classMap = static::dsnClassMap();
  268. $parsed['className'] = $parsed['scheme'];
  269. if (isset($classMap[$parsed['scheme']])) {
  270. $parsed['className'] = $classMap[$parsed['scheme']];
  271. }
  272. }
  273. return $parsed;
  274. }
  275. /**
  276. * Updates the DSN class map for this class.
  277. *
  278. * @param array $map Additions/edits to the class map to apply.
  279. * @return void
  280. */
  281. public static function setDsnClassMap(array $map)
  282. {
  283. static::$_dsnClassMap = $map + static::$_dsnClassMap;
  284. }
  285. /**
  286. * Returns the DSN class map for this class.
  287. *
  288. * @return array
  289. */
  290. public static function getDsnClassMap()
  291. {
  292. return static::$_dsnClassMap;
  293. }
  294. /**
  295. * Returns or updates the DSN class map for this class.
  296. *
  297. * @deprecated 3.4.0 Use setDsnClassMap()/getDsnClassMap() instead.
  298. * @param array|null $map Additions/edits to the class map to apply.
  299. * @return array
  300. */
  301. public static function dsnClassMap(array $map = null)
  302. {
  303. if ($map !== null) {
  304. static::setDsnClassMap($map);
  305. }
  306. return static::getDsnClassMap();
  307. }
  308. }