1: <?php
2:
3: namespace Charcoal\Config;
4:
5: use Traversable;
6: use Throwable;
7: use Exception;
8: use LogicException;
9: use InvalidArgumentException;
10: use UnexpectedValueException;
11:
12:
13: use Symfony\Component\Yaml\Parser as YamlParser;
14:
15: 16: 17: 18: 19: 20: 21: 22: 23:
24: trait FileAwareTrait
25: {
26: 27: 28: 29: 30: 31: 32:
33: public function loadFile($path)
34: {
35: if (!is_string($path)) {
36: throw new InvalidArgumentException(
37: 'File must be a string'
38: );
39: }
40:
41: if (!file_exists($path)) {
42: throw new InvalidArgumentException(
43: sprintf('File "%s" does not exist', $path)
44: );
45: }
46:
47: $ext = pathinfo($path, PATHINFO_EXTENSION);
48: switch ($ext) {
49: case 'php':
50: return $this->loadPhpFile($path);
51:
52: case 'json':
53: return $this->loadJsonFile($path);
54:
55: case 'ini':
56: return $this->loadIniFile($path);
57:
58: case 'yml':
59: case 'yaml':
60: return $this->loadYamlFile($path);
61: }
62:
63: $validConfigExts = [ 'ini', 'json', 'php', 'yml' ];
64: throw new InvalidArgumentException(sprintf(
65: 'Unsupported file format for "%s"; must be one of "%s"',
66: $path,
67: implode('", "', $validConfigExts)
68: ));
69: }
70:
71: 72: 73: 74: 75: 76: 77:
78: private function loadIniFile($path)
79: {
80: $data = parse_ini_file($path, true);
81: if ($data === false) {
82: throw new UnexpectedValueException(
83: sprintf('INI file "%s" is empty or invalid', $path)
84: );
85: }
86:
87: return $data;
88: }
89:
90: 91: 92: 93: 94: 95: 96: 97:
98: private function loadJsonFile($path)
99: {
100: $data = null;
101: $json = file_get_contents($path);
102: if ($json) {
103: $data = json_decode($json, true);
104: if (json_last_error() !== JSON_ERROR_NONE) {
105: $error = json_last_error_msg() ?: 'Unknown error';
106: throw new UnexpectedValueException(
107: sprintf('JSON file "%s" could not be parsed: %s', $path, $error)
108: );
109: }
110: }
111:
112: if (!is_array($data)) {
113: return [];
114: }
115:
116: return $data;
117: }
118:
119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131:
132: private function loadPhpFile($path)
133: {
134: try {
135: $data = include $path;
136: } catch (Exception $e) {
137: $message = sprintf('PHP file "%s" could not be parsed: %s', $path, $e->getMessage());
138: throw new UnexpectedValueException($message, 0, $e);
139: } catch (Throwable $e) {
140: $message = sprintf('PHP file "%s" could not be parsed: %s', $path, $e->getMessage());
141: throw new UnexpectedValueException($message, 0, $e);
142: }
143:
144: if (is_array($data) || ($data instanceof Traversable)) {
145: return $data;
146: }
147:
148: return [];
149: }
150:
151: 152: 153: 154: 155: 156: 157: 158: 159:
160: private function loadYamlFile($path)
161: {
162: if (!class_exists('Symfony\Component\Yaml\Parser')) {
163: throw new LogicException('YAML format requires the Symfony YAML component');
164: }
165:
166: try {
167: $yaml = new YamlParser();
168: $data = $yaml->parseFile($path);
169: } catch (Exception $e) {
170: $message = sprintf('YAML file "%s" could not be parsed: %s', $path, $e->getMessage());
171: throw new UnexpectedValueException($message, 0, $e);
172: }
173:
174: if (!is_array($data)) {
175: return [];
176: }
177:
178: return $data;
179: }
180: }
181: