PageRenderTime 67ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/october/rain/src/Config/Repository.php

https://gitlab.com/gideonmarked/PLCPortal
PHP | 466 lines | 178 code | 62 blank | 226 comment | 10 complexity | 36dafb6d54613538f7a166c4e446eb10 MD5 | raw file
  1. <?php namespace October\Rain\Config;
  2. use Closure;
  3. use ArrayAccess;
  4. use Illuminate\Contracts\Config\Repository as ConfigContract;
  5. /**
  6. * October config repository class.
  7. *
  8. * @package config
  9. * @author Alexey Bobkov, Samuel Georges
  10. */
  11. class Repository implements ArrayAccess, ConfigContract
  12. {
  13. use \October\Rain\Support\Traits\KeyParser;
  14. /**
  15. * The loader implementation.
  16. *
  17. * @var \October\Rain\Config\LoaderInterface
  18. */
  19. protected $loader;
  20. /**
  21. * The current environment.
  22. *
  23. * @var string
  24. */
  25. protected $environment;
  26. /**
  27. * All of the configuration items.
  28. *
  29. * @var array
  30. */
  31. protected $items = [];
  32. /**
  33. * All of the registered packages.
  34. *
  35. * @var array
  36. */
  37. protected $packages = [];
  38. /**
  39. * The after load callbacks for namespaces.
  40. *
  41. * @var array
  42. */
  43. protected $afterLoad = [];
  44. /**
  45. * Create a new configuration repository.
  46. *
  47. * @param \October\Rain\Config\LoaderInterface $loader
  48. * @param string $environment
  49. * @return void
  50. */
  51. public function __construct(LoaderInterface $loader, $environment)
  52. {
  53. $this->loader = $loader;
  54. $this->environment = $environment;
  55. }
  56. /**
  57. * Determine if the given configuration value exists.
  58. *
  59. * @param string $key
  60. * @return bool
  61. */
  62. public function has($key)
  63. {
  64. $default = microtime(true);
  65. return $this->get($key, $default) !== $default;
  66. }
  67. /**
  68. * Determine if a configuration group exists.
  69. *
  70. * @param string $key
  71. * @return bool
  72. */
  73. public function hasGroup($key)
  74. {
  75. list($namespace, $group, $item) = $this->parseConfigKey($key);
  76. return $this->loader->exists($group, $namespace);
  77. }
  78. /**
  79. * Get the specified configuration value.
  80. *
  81. * @param string $key
  82. * @param mixed $default
  83. * @return mixed
  84. */
  85. public function get($key, $default = null)
  86. {
  87. list($namespace, $group, $item) = $this->parseConfigKey($key);
  88. // Configuration items are actually keyed by "collection", which is simply a
  89. // combination of each namespace and groups, which allows a unique way to
  90. // identify the arrays of configuration items for the particular files.
  91. $collection = $this->getCollection($group, $namespace);
  92. $this->load($group, $namespace, $collection);
  93. return array_get($this->items[$collection], $item, $default);
  94. }
  95. /**
  96. * Set a given configuration value.
  97. *
  98. * @param array|string $key
  99. * @param mixed $value
  100. * @return void
  101. */
  102. public function set($key, $value = null)
  103. {
  104. if (is_array($key)) {
  105. foreach ($key as $innerKey => $innerValue) {
  106. $this->set($innerKey, $innerValue);
  107. }
  108. }
  109. else {
  110. list($namespace, $group, $item) = $this->parseConfigKey($key);
  111. $collection = $this->getCollection($group, $namespace);
  112. // We'll need to go ahead and lazy load each configuration groups even when
  113. // we're just setting a configuration item so that the set item does not
  114. // get overwritten if a different item in the group is requested later.
  115. $this->load($group, $namespace, $collection);
  116. if (is_null($item)) {
  117. $this->items[$collection] = $value;
  118. }
  119. else {
  120. array_set($this->items[$collection], $item, $value);
  121. }
  122. }
  123. }
  124. /**
  125. * Prepend a value onto an array configuration value.
  126. *
  127. * @param string $key
  128. * @param mixed $value
  129. * @return void
  130. */
  131. public function prepend($key, $value)
  132. {
  133. $array = $this->get($key);
  134. array_unshift($array, $value);
  135. $this->set($key, $array);
  136. }
  137. /**
  138. * Push a value onto an array configuration value.
  139. *
  140. * @param string $key
  141. * @param mixed $value
  142. * @return void
  143. */
  144. public function push($key, $value)
  145. {
  146. $array = $this->get($key);
  147. $array[] = $value;
  148. $this->set($key, $array);
  149. }
  150. /**
  151. * Get all of the configuration items for the application.
  152. *
  153. * @return array
  154. */
  155. public function all()
  156. {
  157. return $this->items;
  158. }
  159. /**
  160. * Load the configuration group for the key.
  161. *
  162. * @param string $group
  163. * @param string $namespace
  164. * @param string $collection
  165. * @return void
  166. */
  167. protected function load($group, $namespace, $collection)
  168. {
  169. $env = $this->environment;
  170. // If we've already loaded this collection, we will just bail out since we do
  171. // not want to load it again. Once items are loaded a first time they will
  172. // stay kept in memory within this class and not loaded from disk again.
  173. if (isset($this->items[$collection])) {
  174. return;
  175. }
  176. $items = $this->loader->load($env, $group, $namespace);
  177. // If we've already loaded this collection, we will just bail out since we do
  178. // not want to load it again. Once items are loaded a first time they will
  179. // stay kept in memory within this class and not loaded from disk again.
  180. if (isset($this->afterLoad[$namespace])) {
  181. $items = $this->callAfterLoad($namespace, $group, $items);
  182. }
  183. $this->items[$collection] = $items;
  184. }
  185. /**
  186. * Call the after load callback for a namespace.
  187. *
  188. * @param string $namespace
  189. * @param string $group
  190. * @param array $items
  191. * @return array
  192. */
  193. protected function callAfterLoad($namespace, $group, $items)
  194. {
  195. $callback = $this->afterLoad[$namespace];
  196. return call_user_func($callback, $this, $group, $items);
  197. }
  198. /**
  199. * Parse a key into namespace, group, and item.
  200. *
  201. * @param string $key
  202. * @return array
  203. */
  204. public function parseConfigKey($key)
  205. {
  206. if (strpos($key, '::') === false) {
  207. return $this->parseKey($key);
  208. }
  209. if (isset($this->keyParserCache[$key])) {
  210. return $this->keyParserCache[$key];
  211. }
  212. $segments = explode('.', $key);
  213. $parsed = $this->parseNamespacedSegments($key);
  214. return $this->keyParserCache[$key] = $parsed;
  215. }
  216. /**
  217. * Parse an array of namespaced segments.
  218. *
  219. * @param string $key
  220. * @return array
  221. */
  222. protected function parseNamespacedSegments($key)
  223. {
  224. list($namespace, $item) = explode('::', $key);
  225. // If the namespace is registered as a package, we will just assume the group
  226. // is equal to the namespace since all packages cascade in this way having
  227. // a single file per package, otherwise we'll just parse them as normal.
  228. if (in_array($namespace, $this->packages)) {
  229. return $this->parsePackageSegments($key, $namespace, $item);
  230. }
  231. return $this->keyParserParseSegments($key);
  232. }
  233. /**
  234. * Parse the segments of a package namespace.
  235. *
  236. * @param string $key
  237. * @param string $namespace
  238. * @param string $item
  239. * @return array
  240. */
  241. protected function parsePackageSegments($key, $namespace, $item)
  242. {
  243. $itemSegments = explode('.', $item);
  244. // If the configuration file doesn't exist for the given package group we can
  245. // assume that we should implicitly use the config file matching the name
  246. // of the namespace. Generally packages should use one type or another.
  247. if (!$this->loader->exists($itemSegments[0], $namespace)) {
  248. return [$namespace, 'config', $item];
  249. }
  250. return $this->keyParserParseSegments($key);
  251. }
  252. /**
  253. * Register a package for cascading configuration.
  254. *
  255. * @param string $namespace
  256. * @param string $hint
  257. * @param string $namespace
  258. * @return void
  259. */
  260. public function package($namespace, $hint)
  261. {
  262. $this->packages[] = $namespace;
  263. // First we will simply register the namespace with the repository so that it
  264. // can be loaded. Once we have done that we'll register an after namespace
  265. // callback so that we can cascade an application package configuration.
  266. $this->addNamespace($namespace, $hint);
  267. $this->afterLoading($namespace, function($me, $group, $items) use ($namespace) {
  268. $env = $me->getEnvironment();
  269. $loader = $me->getLoader();
  270. return $loader->cascadePackage($env, $namespace, $group, $items);
  271. });
  272. }
  273. /**
  274. * Register an after load callback for a given namespace.
  275. *
  276. * @param string $namespace
  277. * @param \Closure $callback
  278. * @return void
  279. */
  280. public function afterLoading($namespace, Closure $callback)
  281. {
  282. $this->afterLoad[$namespace] = $callback;
  283. }
  284. /**
  285. * Get the collection identifier.
  286. *
  287. * @param string $group
  288. * @param string $namespace
  289. * @return string
  290. */
  291. protected function getCollection($group, $namespace = null)
  292. {
  293. $namespace = $namespace ?: '*';
  294. return $namespace.'::'.$group;
  295. }
  296. /**
  297. * Add a new namespace to the loader.
  298. *
  299. * @param string $namespace
  300. * @param string $hint
  301. * @return void
  302. */
  303. public function addNamespace($namespace, $hint)
  304. {
  305. $this->loader->addNamespace($namespace, $hint);
  306. }
  307. /**
  308. * Returns all registered namespaces with the config
  309. * loader.
  310. *
  311. * @return array
  312. */
  313. public function getNamespaces()
  314. {
  315. return $this->loader->getNamespaces();
  316. }
  317. /**
  318. * Get the loader implementation.
  319. *
  320. * @return \October\Rain\Config\LoaderInterface
  321. */
  322. public function getLoader()
  323. {
  324. return $this->loader;
  325. }
  326. /**
  327. * Set the loader implementation.
  328. *
  329. * @param \October\Rain\Config\LoaderInterface $loader
  330. * @return void
  331. */
  332. public function setLoader(LoaderInterface $loader)
  333. {
  334. $this->loader = $loader;
  335. }
  336. /**
  337. * Get the current configuration environment.
  338. *
  339. * @return string
  340. */
  341. public function getEnvironment()
  342. {
  343. return $this->environment;
  344. }
  345. /**
  346. * Get the after load callback array.
  347. *
  348. * @return array
  349. */
  350. public function getAfterLoadCallbacks()
  351. {
  352. return $this->afterLoad;
  353. }
  354. /**
  355. * Get all of the configuration items.
  356. *
  357. * @return array
  358. */
  359. public function getItems()
  360. {
  361. return $this->items;
  362. }
  363. /**
  364. * Determine if the given configuration option exists.
  365. *
  366. * @param string $key
  367. * @return bool
  368. */
  369. public function offsetExists($key)
  370. {
  371. return $this->has($key);
  372. }
  373. /**
  374. * Get a configuration option.
  375. *
  376. * @param string $key
  377. * @return mixed
  378. */
  379. public function offsetGet($key)
  380. {
  381. return $this->get($key);
  382. }
  383. /**
  384. * Set a configuration option.
  385. *
  386. * @param string $key
  387. * @param mixed $value
  388. * @return void
  389. */
  390. public function offsetSet($key, $value)
  391. {
  392. $this->set($key, $value);
  393. }
  394. /**
  395. * Unset a configuration option.
  396. *
  397. * @param string $key
  398. * @return void
  399. */
  400. public function offsetUnset($key)
  401. {
  402. $this->set($key, null);
  403. }
  404. }