PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Nette/Config/Config.php

http://github.com/nette/nette
PHP | 224 lines | 115 code | 50 blank | 59 comment | 26 complexity | 1966acb1f3ebcbd85de98b5c7d3d7fc1 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (http://nette.org)
  4. *
  5. * Copyright (c) 2004, 2011 David Grudl (http://davidgrudl.com)
  6. *
  7. * For the full copyright and license information, please view
  8. * the file license.txt that was distributed with this source code.
  9. */
  10. namespace Nette\Config;
  11. use Nette;
  12. /**
  13. * Configuration manipulator.
  14. *
  15. * @author David Grudl
  16. *
  17. * @property-read array $dependencies
  18. */
  19. class Config extends Nette\Object
  20. {
  21. /** @internal */
  22. const INCLUDES_KEY = 'includes',
  23. EXTENDS_KEY = '_extends',
  24. OVERWRITE = TRUE;
  25. private $adapters = array(
  26. 'php' => 'Nette\Config\Adapters\PhpAdapter',
  27. 'ini' => 'Nette\Config\Adapters\IniAdapter',
  28. 'neon' => 'Nette\Config\Adapters\NeonAdapter',
  29. );
  30. private $dependencies = array();
  31. /**
  32. * Static shortcut for load()
  33. * @return array
  34. */
  35. public static function fromFile($file, $section = NULL)
  36. {
  37. $loader = new static;
  38. return $loader->load($file, $section);
  39. }
  40. /**
  41. * Reads configuration from file.
  42. * @param string file name
  43. * @param string optional section to load
  44. * @return array
  45. */
  46. public function load($file, $section = NULL)
  47. {
  48. if (!is_file($file) || !is_readable($file)) {
  49. throw new Nette\FileNotFoundException("File '$file' is missing or is not readable.");
  50. }
  51. $this->dependencies[] = $file = realpath($file);
  52. $data = $this->getAdapter($file)->load($file);
  53. if ($section) {
  54. $data = $this->getSection($data, $section);
  55. }
  56. // include child files
  57. $merged = array();
  58. if (isset($data[self::INCLUDES_KEY])) {
  59. if (!is_array($data[self::INCLUDES_KEY])) {
  60. throw new Nette\InvalidStateException("Invalid section 'includes' in file '$file'.");
  61. }
  62. foreach ($data[self::INCLUDES_KEY] as $include) {
  63. $merged = static::merge($this->load(dirname($file) . '/' . $include), $merged);
  64. }
  65. }
  66. unset($data[self::INCLUDES_KEY]);
  67. return static::merge($data, $merged);
  68. }
  69. /**
  70. * Save configuration to file.
  71. * @param array
  72. * @param string file
  73. * @return void
  74. */
  75. public function save($data, $file)
  76. {
  77. if (file_put_contents($file, $this->getAdapter($file)->dump($data)) === FALSE) {
  78. throw new Nette\IOException("Cannot write file '$file'.");
  79. }
  80. }
  81. /**
  82. * Returns configuration files.
  83. * @return array
  84. */
  85. public function getDependencies()
  86. {
  87. return array_unique($this->dependencies);
  88. }
  89. /**
  90. * Registers adapter for given file extension.
  91. * @param string file extension
  92. * @param string|Nette\Config\IAdapter
  93. * @return void
  94. */
  95. public function addAdapter($extension, $adapter)
  96. {
  97. $this->adapters[strtolower($extension)] = $adapter;
  98. }
  99. /** @return IAdapter */
  100. private function getAdapter($file)
  101. {
  102. $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
  103. if (!isset($this->adapters[$extension])) {
  104. throw new Nette\InvalidArgumentException("Unknown file extension '$file'.");
  105. }
  106. return is_object($this->adapters[$extension]) ? $this->adapters[$extension] : new $this->adapters[$extension];
  107. }
  108. /********************* tools ****************d*g**/
  109. /**
  110. * Merges configurations. Left has higher priority than right one.
  111. * @return array
  112. */
  113. public static function merge($left, $right)
  114. {
  115. if (is_array($left) && is_array($right)) {
  116. foreach ($left as $key => $val) {
  117. if (is_int($key)) {
  118. $right[] = $val;
  119. } else {
  120. if (is_array($val) && isset($val[self::EXTENDS_KEY])) {
  121. if ($val[self::EXTENDS_KEY] === self::OVERWRITE) {
  122. unset($val[self::EXTENDS_KEY]);
  123. }
  124. } elseif (isset($right[$key])) {
  125. $val = static::merge($val, $right[$key]);
  126. }
  127. $right[$key] = $val;
  128. }
  129. }
  130. return $right;
  131. } elseif ($left === NULL && is_array($right)) {
  132. return $right;
  133. } else {
  134. return $left;
  135. }
  136. }
  137. /**
  138. * Finds out and removes information about the parent.
  139. * @return mixed
  140. */
  141. public static function takeParent(& $data)
  142. {
  143. if (is_array($data) && isset($data[self::EXTENDS_KEY])) {
  144. $parent = $data[self::EXTENDS_KEY];
  145. unset($data[self::EXTENDS_KEY]);
  146. return $parent;
  147. }
  148. }
  149. /**
  150. * @return bool
  151. */
  152. public static function isOverwriting(& $data)
  153. {
  154. return is_array($data) && isset($data[self::EXTENDS_KEY]) && $data[self::EXTENDS_KEY] === self::OVERWRITE;
  155. }
  156. /**
  157. * @return bool
  158. */
  159. public static function isInheriting(& $data)
  160. {
  161. return is_array($data) && isset($data[self::EXTENDS_KEY]) && $data[self::EXTENDS_KEY] !== self::OVERWRITE;
  162. }
  163. private function getSection(array $data, $key)
  164. {
  165. if (!array_key_exists($key, $data) || !is_array($data[$key]) && $data[$key] !== NULL) {
  166. throw new Nette\InvalidStateException("Section '$key' is missing or is not an array.");
  167. }
  168. $item = $data[$key];
  169. if ($parent = static::takeParent($item)) {
  170. $item = static::merge($item, $this->getSection($data, $parent));
  171. }
  172. return $item;
  173. }
  174. }