1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Config\Adapters;
9:
10: use Nette,
11: Nette\Config\Helpers;
12:
13:
14: 15: 16: 17: 18:
19: class IniAdapter extends Nette\Object implements Nette\Config\IAdapter
20: {
21:
22: const INHERITING_SEPARATOR = '<',
23: KEY_SEPARATOR = '.',
24: ESCAPED_KEY_SEPARATOR = '..',
25: RAW_SECTION = '!';
26:
27:
28: 29: 30: 31: 32: 33:
34: public function load($file)
35: {
36: set_error_handler(function($severity, $message) {
37: restore_error_handler();
38: throw new Nette\InvalidStateException("parse_ini_file(): $message");
39: });
40: $ini = parse_ini_file($file, TRUE);
41: restore_error_handler();
42:
43: $data = array();
44: foreach ($ini as $secName => $secData) {
45: if (is_array($secData)) {
46: if (substr($secName, -1) === self::RAW_SECTION) {
47: $secName = substr($secName, 0, -1);
48: } else {
49: $tmp = array();
50: foreach ($secData as $key => $val) {
51: $cursor = & $tmp;
52: $key = str_replace(self::ESCAPED_KEY_SEPARATOR, "\xFF", $key);
53: foreach (explode(self::KEY_SEPARATOR, $key) as $part) {
54: $part = str_replace("\xFF", self::KEY_SEPARATOR, $part);
55: if (!isset($cursor[$part]) || is_array($cursor[$part])) {
56: $cursor = & $cursor[$part];
57: } else {
58: throw new Nette\InvalidStateException("Invalid key '$key' in section [$secName] in file '$file'.");
59: }
60: }
61: $cursor = $val;
62: }
63: $secData = $tmp;
64: }
65:
66: $parts = explode(self::INHERITING_SEPARATOR, $secName);
67: if (count($parts) > 1) {
68: $secName = trim($parts[0]);
69: $secData[Helpers::EXTENDS_KEY] = trim($parts[1]);
70: }
71: }
72:
73: $cursor = & $data;
74: foreach (explode(self::KEY_SEPARATOR, $secName) as $part) {
75: if (!isset($cursor[$part]) || is_array($cursor[$part])) {
76: $cursor = & $cursor[$part];
77: } else {
78: throw new Nette\InvalidStateException("Invalid section [$secName] in file '$file'.");
79: }
80: }
81:
82: if (is_array($secData) && is_array($cursor)) {
83: $secData = Helpers::merge($secData, $cursor);
84: }
85:
86: $cursor = $secData;
87: }
88:
89: return $data;
90: }
91:
92:
93: 94: 95: 96:
97: public function dump(array $data)
98: {
99: $output = array();
100: foreach ($data as $name => $secData) {
101: if (!is_array($secData)) {
102: $output = array();
103: self::build($data, $output, '');
104: break;
105: }
106: if ($parent = Helpers::takeParent($secData)) {
107: $output[] = "[$name " . self::INHERITING_SEPARATOR . " $parent]";
108: } else {
109: $output[] = "[$name]";
110: }
111: self::build($secData, $output, '');
112: $output[] = '';
113: }
114: return "; generated by Nette\n\n" . implode(PHP_EOL, $output);
115: }
116:
117:
118: 119: 120: 121:
122: private static function build($input, & $output, $prefix)
123: {
124: foreach ($input as $key => $val) {
125: $key = str_replace(self::KEY_SEPARATOR, self::ESCAPED_KEY_SEPARATOR, $key);
126: if (is_array($val)) {
127: self::build($val, $output, $prefix . $key . self::KEY_SEPARATOR);
128:
129: } elseif (is_bool($val)) {
130: $output[] = "$prefix$key = " . ($val ? 'true' : 'false');
131:
132: } elseif (is_numeric($val)) {
133: $output[] = "$prefix$key = $val";
134:
135: } elseif (is_string($val)) {
136: $output[] = "$prefix$key = \"$val\"";
137:
138: } else {
139: throw new Nette\InvalidArgumentException(sprintf("The '%s' item must be scalar or array, %s given.", $prefix . $key, gettype($val)));
140: }
141: }
142: }
143:
144: }
145: