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