1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\DI\Config\Adapters;
9:
10: use Nette;
11: use Nette\DI\Config\Helpers;
12: use Nette\DI\Statement;
13: use Nette\Neon;
14:
15:
16: 17: 18:
19: class NeonAdapter implements Nette\DI\Config\IAdapter
20: {
21: use Nette\SmartObject;
22:
23:
24: const INHERITING_SEPARATOR = '<',
25: PREVENT_MERGING = '!';
26:
27:
28: 29: 30: 31: 32:
33: public function load($file)
34: {
35: return $this->process((array) Neon\Neon::decode(file_get_contents($file)));
36: }
37:
38:
39: 40: 41: 42:
43: public function process(array $arr)
44: {
45: $res = [];
46: foreach ($arr as $key => $val) {
47: if (is_string($key) && substr($key, -1) === self::PREVENT_MERGING) {
48: if (!is_array($val) && $val !== null) {
49: throw new Nette\InvalidStateException("Replacing operator is available only for arrays, item '$key' is not array.");
50: }
51: $key = substr($key, 0, -1);
52: $val[Helpers::EXTENDS_KEY] = Helpers::OVERWRITE;
53:
54: } elseif (is_string($key) && preg_match('#^(\S+)\s+' . self::INHERITING_SEPARATOR . '\s+(\S+)\z#', $key, $matches)) {
55: if (!is_array($val) && $val !== null) {
56: throw new Nette\InvalidStateException("Inheritance operator is available only for arrays, item '$key' is not array.");
57: }
58: list(, $key, $val[Helpers::EXTENDS_KEY]) = $matches;
59: if (isset($res[$key])) {
60: throw new Nette\InvalidStateException("Duplicated key '$key'.");
61: }
62: }
63:
64: if (is_array($val)) {
65: $val = $this->process($val);
66:
67: } elseif ($val instanceof Neon\Entity) {
68: if ($val->value === Neon\Neon::CHAIN) {
69: $tmp = null;
70: foreach ($this->process($val->attributes) as $st) {
71: $tmp = new Statement(
72: $tmp === null ? $st->getEntity() : [$tmp, ltrim($st->getEntity(), ':')],
73: $st->arguments
74: );
75: }
76: $val = $tmp;
77: } else {
78: $tmp = $this->process([$val->value]);
79: $val = new Statement($tmp[0], $this->process($val->attributes));
80: }
81: }
82: $res[$key] = $val;
83: }
84: return $res;
85: }
86:
87:
88: 89: 90: 91:
92: public function dump(array $data)
93: {
94: $tmp = [];
95: foreach ($data as $name => $secData) {
96: if ($parent = Helpers::takeParent($secData)) {
97: $name .= ' ' . self::INHERITING_SEPARATOR . ' ' . $parent;
98: }
99: $tmp[$name] = $secData;
100: }
101: array_walk_recursive(
102: $tmp,
103: function (&$val) {
104: if ($val instanceof Statement) {
105: $val = self::statementToEntity($val);
106: }
107: }
108: );
109:
110: return "# generated by Nette\n\n" . Neon\Neon::encode($tmp, Neon\Neon::BLOCK);
111: }
112:
113:
114: 115: 116:
117: private static function statementToEntity(Statement $val)
118: {
119: array_walk_recursive(
120: $val->arguments,
121: function (&$val) {
122: if ($val instanceof Statement) {
123: $val = self::statementToEntity($val);
124: }
125: }
126: );
127: if (is_array($val->getEntity()) && $val->getEntity()[0] instanceof Statement) {
128: return new Neon\Entity(
129: Neon\Neon::CHAIN,
130: [
131: self::statementToEntity($val->getEntity()[0]),
132: new Neon\Entity('::' . $val->getEntity()[1], $val->arguments),
133: ]
134: );
135: } else {
136: return new Neon\Entity($val->getEntity(), $val->arguments);
137: }
138: }
139: }
140: