vendor/pimcore/pimcore/lib/Config/Config.php line 306

Open in your IDE?
  1. <?php
  2. /**
  3. * Pimcore
  4. *
  5. * This source file is available under two different licenses:
  6. * - GNU General Public License version 3 (GPLv3)
  7. * - Pimcore Commercial License (PCL)
  8. * Full copyright and license information is available in
  9. * LICENSE.md which is distributed with this source code.
  10. *
  11. * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12. * @license http://www.pimcore.org/license GPLv3 and PCL
  13. */
  14. /**
  15. * ----------------------------------------------------------------------------------
  16. * based on Zend\Config https://github.com/zendframework/zend-config
  17. * ----------------------------------------------------------------------------------
  18. */
  19. /**
  20. * @see https://github.com/zendframework/zend-config for the canonical source repository
  21. *
  22. * @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
  23. * @license https://github.com/zendframework/zend-config/blob/master/LICENSE.md New BSD License
  24. */
  25. namespace Pimcore\Config;
  26. use ArrayAccess;
  27. use Countable;
  28. use Exception;
  29. use Iterator;
  30. /**
  31. * Provides a property based interface to an array.
  32. * The data are read-only unless $allowModifications is set to true
  33. * on construction.
  34. *
  35. * Implements Countable, Iterator and ArrayAccess
  36. * to facilitate easy access to the data.
  37. */
  38. final class Config implements Countable, Iterator, ArrayAccess
  39. {
  40. /**
  41. * Whether modifications to configuration data are allowed.
  42. *
  43. * @var bool
  44. */
  45. protected $allowModifications;
  46. /**
  47. * Data within the configuration.
  48. *
  49. * @var array
  50. */
  51. protected $data = [];
  52. /**
  53. * Used when unsetting values during iteration to ensure we do not skip
  54. * the next element.
  55. *
  56. * @var bool
  57. */
  58. protected $skipNextIteration;
  59. /**
  60. * Constructor.
  61. *
  62. * Data is read-only unless $allowModifications is set to true
  63. * on construction.
  64. *
  65. * @param array $array
  66. * @param bool $allowModifications
  67. */
  68. public function __construct(array $array, $allowModifications = false)
  69. {
  70. $this->allowModifications = (bool) $allowModifications;
  71. foreach ($array as $key => $value) {
  72. if (is_array($value)) {
  73. $this->data[$key] = new static($value, $this->allowModifications);
  74. } else {
  75. $this->data[$key] = $value;
  76. }
  77. }
  78. }
  79. /**
  80. * Retrieve a value and return $default if there is no element set.
  81. *
  82. * @param string $name
  83. * @param mixed $default
  84. *
  85. * @return mixed
  86. */
  87. public function get($name, $default = null)
  88. {
  89. if (array_key_exists($name, $this->data)) {
  90. return $this->data[$name];
  91. }
  92. return $default;
  93. }
  94. /**
  95. * Magic function so that $obj->value will work.
  96. *
  97. * @param string $name
  98. *
  99. * @return mixed
  100. */
  101. public function __get($name)
  102. {
  103. return $this->get($name);
  104. }
  105. /**
  106. * Set a value in the config.
  107. *
  108. * Only allow setting of a property if $allowModifications was set to true
  109. * on construction. Otherwise, throw an exception.
  110. *
  111. * @param string|null $name
  112. * @param mixed $value
  113. *
  114. * @return void
  115. *
  116. * @throws Exception
  117. */
  118. public function __set($name, $value)
  119. {
  120. if ($this->allowModifications) {
  121. if (is_array($value)) {
  122. $value = new static($value, true);
  123. }
  124. if (null === $name) {
  125. $this->data[] = $value;
  126. } else {
  127. $this->data[$name] = $value;
  128. }
  129. } else {
  130. throw new Exception('Config is read only');
  131. }
  132. }
  133. /**
  134. * Deep clone of this instance to ensure that nested Zend\Configs are also
  135. * cloned.
  136. *
  137. * @return void
  138. */
  139. public function __clone()
  140. {
  141. $array = [];
  142. foreach ($this->data as $key => $value) {
  143. if ($value instanceof self) {
  144. $array[$key] = clone $value;
  145. } else {
  146. $array[$key] = $value;
  147. }
  148. }
  149. $this->data = $array;
  150. }
  151. /**
  152. * Return an associative array of the stored data.
  153. *
  154. * @return array
  155. */
  156. public function toArray()
  157. {
  158. $array = [];
  159. $data = $this->data;
  160. foreach ($data as $key => $value) {
  161. if ($value instanceof self) {
  162. $array[$key] = $value->toArray();
  163. } else {
  164. $array[$key] = $value;
  165. }
  166. }
  167. return $array;
  168. }
  169. /**
  170. * isset() overloading
  171. *
  172. * @param string $name
  173. *
  174. * @return bool
  175. */
  176. public function __isset($name)
  177. {
  178. return isset($this->data[$name]);
  179. }
  180. /**
  181. * unset() overloading
  182. *
  183. * @param string $name
  184. *
  185. * @return void
  186. *
  187. * @throws Exception
  188. */
  189. public function __unset($name)
  190. {
  191. if (! $this->allowModifications) {
  192. throw new Exception('Config is read only');
  193. } elseif (isset($this->data[$name])) {
  194. unset($this->data[$name]);
  195. $this->skipNextIteration = true;
  196. }
  197. }
  198. /**
  199. * {@inheritdoc}
  200. */
  201. public function count()
  202. {
  203. return count($this->data);
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function current()
  209. {
  210. $this->skipNextIteration = false;
  211. return current($this->data);
  212. }
  213. /**
  214. * {@inheritdoc}
  215. */
  216. public function key()
  217. {
  218. return key($this->data);
  219. }
  220. /**
  221. * {@inheritdoc}
  222. */
  223. public function next()
  224. {
  225. if ($this->skipNextIteration) {
  226. $this->skipNextIteration = false;
  227. return;
  228. }
  229. next($this->data);
  230. }
  231. /**
  232. * {@inheritdoc}
  233. */
  234. public function rewind()
  235. {
  236. $this->skipNextIteration = false;
  237. reset($this->data);
  238. }
  239. /**
  240. * {@inheritdoc}
  241. */
  242. public function valid()
  243. {
  244. return $this->key() !== null;
  245. }
  246. /**
  247. * {@inheritdoc}
  248. */
  249. public function offsetExists($offset)
  250. {
  251. return $this->__isset($offset);
  252. }
  253. /**
  254. * {@inheritdoc}
  255. */
  256. public function offsetGet($offset)
  257. {
  258. return $this->__get($offset);
  259. }
  260. /**
  261. * {@inheritdoc}
  262. */
  263. public function offsetSet($offset, $value)
  264. {
  265. $this->__set($offset, $value);
  266. }
  267. /**
  268. * {@inheritdoc}
  269. */
  270. public function offsetUnset($offset)
  271. {
  272. $this->__unset($offset);
  273. }
  274. /**
  275. * @internal
  276. *
  277. * Merge another Config with this one.
  278. *
  279. * For duplicate keys, the following will be performed:
  280. * - Nested Configs will be recursively merged.
  281. * - Items in $merge with INTEGER keys will be appended.
  282. * - Items in $merge with STRING keys will overwrite current values.
  283. *
  284. * @param Config $merge
  285. *
  286. * @return self
  287. */
  288. public function merge(Config $merge)
  289. {
  290. foreach ($merge as $key => $value) {
  291. if (array_key_exists($key, $this->data)) {
  292. if (is_int($key)) {
  293. $this->data[] = $value;
  294. } elseif ($value instanceof self && $this->data[$key] instanceof self) {
  295. $this->data[$key]->merge($value);
  296. } else {
  297. if ($value instanceof self) {
  298. $this->data[$key] = new static($value->toArray(), $this->allowModifications);
  299. } else {
  300. $this->data[$key] = $value;
  301. }
  302. }
  303. } else {
  304. if ($value instanceof self) {
  305. $this->data[$key] = new static($value->toArray(), $this->allowModifications);
  306. } else {
  307. $this->data[$key] = $value;
  308. }
  309. }
  310. }
  311. return $this;
  312. }
  313. /**
  314. * @internal
  315. *
  316. * Prevent any more modifications being made to this instance.
  317. *
  318. * Useful after merge() has been used to merge multiple Config objects
  319. * into one object which should then not be modified again.
  320. *
  321. * @return void
  322. */
  323. public function setReadOnly()
  324. {
  325. $this->allowModifications = false;
  326. /** @var Config $value */
  327. foreach ($this->data as $value) {
  328. if ($value instanceof self) {
  329. $value->setReadOnly();
  330. }
  331. }
  332. }
  333. /**
  334. * @internal
  335. *
  336. * Returns whether this Config object is read only or not.
  337. *
  338. * @return bool
  339. */
  340. public function isReadOnly()
  341. {
  342. return ! $this->allowModifications;
  343. }
  344. /**
  345. * {@inheritdoc}
  346. */
  347. public function __toString()
  348. {
  349. if (empty($this->data)) {
  350. return '';
  351. }
  352. return is_string($this->data) ? (string)$this->data : json_encode($this->data, JSON_PRETTY_PRINT);
  353. }
  354. }