1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\DI\Config;
9:
10: use Nette;
11: use Nette\Utils\Validators;
12:
13:
14: 15: 16:
17: class Loader
18: {
19: use Nette\SmartObject;
20:
21:
22: const INCLUDES_KEY = 'includes';
23:
24: private $adapters = [
25: 'php' => Adapters\PhpAdapter::class,
26: 'ini' => Adapters\IniAdapter::class,
27: 'neon' => Adapters\NeonAdapter::class,
28: ];
29:
30: private $dependencies = [];
31:
32:
33: 34: 35: 36: 37: 38:
39: public function load($file, $section = null)
40: {
41: if (!is_file($file) || !is_readable($file)) {
42: throw new Nette\FileNotFoundException("File '$file' is missing or is not readable.");
43: }
44: $this->dependencies[] = $file;
45: $data = $this->getAdapter($file)->load($file);
46:
47: if ($section) {
48: if (isset($data[self::INCLUDES_KEY])) {
49: throw new Nette\InvalidStateException("Section 'includes' must be placed under some top section in file '$file'.");
50: }
51: $data = $this->getSection($data, $section, $file);
52: }
53:
54:
55: $merged = [];
56: if (isset($data[self::INCLUDES_KEY])) {
57: Validators::assert($data[self::INCLUDES_KEY], 'list', "section 'includes' in file '$file'");
58: foreach ($data[self::INCLUDES_KEY] as $include) {
59: if (!preg_match('#([a-z]+:)?[/\\\\]#Ai', $include)) {
60: $include = dirname($file) . '/' . $include;
61: }
62: $merged = Helpers::merge($this->load($include), $merged);
63: }
64: }
65: unset($data[self::INCLUDES_KEY]);
66:
67: return Helpers::merge($data, $merged);
68: }
69:
70:
71: 72: 73: 74: 75: 76:
77: public function save($data, $file)
78: {
79: if (file_put_contents($file, $this->getAdapter($file)->dump($data)) === false) {
80: throw new Nette\IOException("Cannot write file '$file'.");
81: }
82: }
83:
84:
85: 86: 87: 88:
89: public function getDependencies()
90: {
91: return array_unique($this->dependencies);
92: }
93:
94:
95: 96: 97: 98: 99: 100:
101: public function addAdapter($extension, $adapter)
102: {
103: $this->adapters[strtolower($extension)] = $adapter;
104: return $this;
105: }
106:
107:
108:
109: private function getAdapter($file)
110: {
111: $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
112: if (!isset($this->adapters[$extension])) {
113: throw new Nette\InvalidArgumentException("Unknown file extension '$file'.");
114: }
115: return is_object($this->adapters[$extension]) ? $this->adapters[$extension] : new $this->adapters[$extension];
116: }
117:
118:
119: private function getSection(array $data, $key, $file)
120: {
121: Validators::assertField($data, $key, 'array|null', "section '%' in file '$file'");
122: $item = $data[$key];
123: if ($parent = Helpers::takeParent($item)) {
124: $item = Helpers::merge($item, $this->getSection($data, $parent, $file));
125: }
126: return $item;
127: }
128: }
129: