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