1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Config;
13:
14: use Nette;
15:
16:
17:
18: 19: 20: 21: 22:
23: final class ConfigAdapterIni implements IConfigAdapter
24: {
25:
26:
27: public static $keySeparator = '.';
28:
29:
30: public static $sectionSeparator = ' < ';
31:
32:
33: public static $rawSection = '!';
34:
35:
36:
37: 38: 39:
40: final public function __construct()
41: {
42: throw new \LogicException("Cannot instantiate static class " . get_class($this));
43: }
44:
45:
46:
47: 48: 49: 50: 51: 52:
53: public static function load($file)
54: {
55: if (!is_file($file) || !is_readable($file)) {
56: throw new \FileNotFoundException("File '$file' is missing or is not readable.");
57: }
58:
59: Nette\Debug::tryError();
60: $ini = parse_ini_file($file, TRUE);
61: if (Nette\Debug::catchError($e)) {
62: throw new \InvalidStateException('parse_ini_file(): ' . $e->getMessage(), 0, $e);
63: }
64:
65: $separator = trim(self::$sectionSeparator);
66: $data = array();
67: foreach ($ini as $secName => $secData) {
68: 69: if (is_array($secData)) {
70: if (substr($secName, -1) === self::$rawSection) {
71: $secName = substr($secName, 0, -1);
72:
73: } elseif (self::$keySeparator) {
74: 75: $tmp = array();
76: foreach ($secData as $key => $val) {
77: $cursor = & $tmp;
78: foreach (explode(self::$keySeparator, $key) as $part) {
79: if (!isset($cursor[$part]) || is_array($cursor[$part])) {
80: $cursor = & $cursor[$part];
81: } else {
82: throw new \InvalidStateException("Invalid key '$key' in section [$secName] in '$file'.");
83: }
84: }
85: $cursor = $val;
86: }
87: $secData = $tmp;
88: }
89:
90: 91: $parts = $separator ? explode($separator, strtr($secName, ':', $separator)) : array($secName);
92: if (count($parts) > 1) {
93: $parent = trim($parts[1]);
94: $cursor = & $data;
95: foreach (self::$keySeparator ? explode(self::$keySeparator, $parent) : array($parent) as $part) {
96: if (isset($cursor[$part]) && is_array($cursor[$part])) {
97: $cursor = & $cursor[$part];
98: } else {
99: throw new \InvalidStateException("Missing parent section [$parent] in '$file'.");
100: }
101: }
102: $secData = Nette\ArrayTools::mergeTree($secData, $cursor);
103: }
104:
105: $secName = trim($parts[0]);
106: if ($secName === '') {
107: throw new \InvalidStateException("Invalid empty section name in '$file'.");
108: }
109: }
110:
111: if (self::$keySeparator) {
112: $cursor = & $data;
113: foreach (explode(self::$keySeparator, $secName) as $part) {
114: if (!isset($cursor[$part]) || is_array($cursor[$part])) {
115: $cursor = & $cursor[$part];
116: } else {
117: throw new \InvalidStateException("Invalid section [$secName] in '$file'.");
118: }
119: }
120: } else {
121: $cursor = & $data[$secName];
122: }
123:
124: if (is_array($secData) && is_array($cursor)) {
125: $secData = Nette\ArrayTools::mergeTree($secData, $cursor);
126: }
127:
128: $cursor = $secData;
129: }
130:
131: return $data;
132: }
133:
134:
135:
136: 137: 138: 139: 140: 141:
142: public static function save($config, $file)
143: {
144: $output = array();
145: $output[] = '; generated by Nette';146: $output[] = '';
147:
148: foreach ($config as $secName => $secData) {
149: if (!(is_array($secData) || $secData instanceof \Traversable)) {
150: throw new \InvalidStateException("Invalid section '$section'.");
151: }
152:
153: $output[] = "[$secName]";
154: self::build($secData, $output, '');
155: $output[] = '';
156: }
157:
158: if (!file_put_contents($file, implode(PHP_EOL, $output))) {
159: throw new \IOException("Cannot write file '$file'.");
160: }
161: }
162:
163:
164:
165: 166: 167: 168: 169: 170: 171:
172: private static function build($input, & $output, $prefix)
173: {
174: foreach ($input as $key => $val) {
175: if (is_array($val) || $val instanceof \Traversable) {
176: self::build($val, $output, $prefix . $key . self::$keySeparator);
177:
178: } elseif (is_bool($val)) {
179: $output[] = "$prefix$key = " . ($val ? 'true' : 'false');
180:
181: } elseif (is_numeric($val)) {
182: $output[] = "$prefix$key = $val";
183:
184: } elseif (is_string($val)) {
185: $output[] = "$prefix$key = \"$val\"";
186:
187: } else {
188: throw new \InvalidArgumentException("The '$prefix$key' item must be scalar or array, " . gettype($val) ." given.");
189: }
190: }
191: }
192:
193: }
194: