1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Anax\Configure; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Load configuration for a specified item, look in several places for the |
7
|
|
|
* configuration files or directories. Return the configuration as the value |
8
|
|
|
* received from the configuration file. |
9
|
|
|
*/ |
10
|
|
|
class Configuration |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* @var array $config to save the latest loaded config to ease |
14
|
|
|
* access. |
15
|
|
|
*/ |
16
|
|
|
protected $config = []; |
17
|
|
|
|
18
|
|
|
|
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var array $dirs where to look for configuration items. |
22
|
|
|
*/ |
23
|
|
|
protected $dirs = []; |
24
|
|
|
|
25
|
|
|
|
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var array $mapping mapping items to specific configuration file, mainly |
29
|
|
|
* useful for testing various configuration files. |
30
|
|
|
*/ |
31
|
|
|
protected $mapping = []; |
32
|
|
|
|
33
|
|
|
|
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Set a specific configuration file to load for a particluar item. |
37
|
|
|
* |
38
|
|
|
* @param string $item the item to map. |
39
|
|
|
* @param string $file file to load configuration from. |
40
|
|
|
* |
41
|
|
|
* @return self to allow chaining. |
42
|
|
|
*/ |
43
|
|
|
public function setMapping(string $item, string $file) : object |
44
|
|
|
{ |
45
|
|
|
$this->mapping[$item] = $file; |
46
|
|
|
return $this; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
|
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Set the directories where to look for configuration |
53
|
|
|
* items (files, directories) to load. |
54
|
|
|
* |
55
|
|
|
* @throws Exception when the path to any of the directories are incorrect. |
56
|
|
|
* |
57
|
|
|
* @param array $dirs with the path to the config directories to search in. |
58
|
|
|
* |
59
|
|
|
* @return self to allow chaining. |
60
|
|
|
*/ |
61
|
|
|
public function setBaseDirectories(array $dirs): object |
62
|
|
|
{ |
63
|
|
|
foreach ($dirs as $dir) { |
64
|
|
|
if (!(is_readable($dir) && is_dir($dir))) { |
65
|
|
|
throw new Exception("The configuration dir '$dir' is not a valid path."); |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
$this->dirs = $dirs; |
70
|
|
|
return $this; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
|
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Read configuration from file or directory, if a file, look though all |
77
|
|
|
* base dirs and use the first configuration that is found. A configuration |
78
|
|
|
* item can be combined from a file and a directory, when available in the |
79
|
|
|
* same base directory. |
80
|
|
|
* |
81
|
|
|
* The resulting configuration is always an array, its structure contains |
82
|
|
|
* values from each individual configuration file, like this. |
83
|
|
|
* |
84
|
|
|
* $config = [ |
85
|
|
|
* "file" => filename for file.php, |
86
|
|
|
* "config" => result returned from file.php, |
87
|
|
|
* "items" => [ |
88
|
|
|
* [ |
89
|
|
|
* "file" => filename for dir/file1.php, |
90
|
|
|
* "config" => result returned from dir/file1.php, |
91
|
|
|
* ], |
92
|
|
|
* [ |
93
|
|
|
* "file" => filename for dir/file2.php, |
94
|
|
|
* "config" => result returned from dir/file2.php, |
95
|
|
|
* ], |
96
|
|
|
* ]. |
97
|
|
|
* ] |
98
|
|
|
* |
99
|
|
|
* The configuration files in the directory are loaded per alphabetical |
100
|
|
|
* order. |
101
|
|
|
* |
102
|
|
|
* @param string $item is a name representing the module and is used to |
103
|
|
|
* combine the path to search for. |
104
|
|
|
* |
105
|
|
|
* @throws Exception when configuration item can not be found. |
106
|
|
|
* @throws Exception when $dirs are empty. |
107
|
|
|
* |
108
|
|
|
* @return array with returned value from the loaded configuration. |
109
|
|
|
*/ |
110
|
|
|
public function load(string $item) : array |
111
|
|
|
{ |
112
|
|
|
$found = false; |
113
|
|
|
$config = []; |
114
|
|
|
$this->config = $config; |
115
|
|
|
|
116
|
|
|
$mapping = $this->mapping[$item] ?? null; |
117
|
|
|
if ($mapping) { |
118
|
|
|
$config["file"] = $mapping; |
119
|
|
|
$config["config"] = require $mapping; |
120
|
|
|
$this->config = $config; |
121
|
|
|
return $config; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
// The configuration is found by absolute path |
125
|
|
View Code Duplication |
if (is_readable($item) && is_file($item)) { |
|
|
|
|
126
|
|
|
$found = true; |
127
|
|
|
$config["file"] = $item; |
128
|
|
|
$config["config"] = require $item; |
129
|
|
|
$this->config = $config; |
130
|
|
|
return $config; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
foreach ($this->dirs as $dir) { |
134
|
|
|
$path = "$dir/$item"; |
135
|
|
|
$file = "$path.php"; |
136
|
|
|
|
137
|
|
|
// The configuration is found in a file |
138
|
|
View Code Duplication |
if (is_readable($file) && is_file($file)) { |
|
|
|
|
139
|
|
|
$found = true; |
140
|
|
|
$config["file"] = $file; |
141
|
|
|
$config["config"] = require $file; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
// The configuration is found in a directory |
145
|
|
|
if (is_readable($path) && is_dir($path)) { |
146
|
|
|
$found = true; |
147
|
|
|
$config["items"] = $this->loadFromDir($path); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
if ($found) { |
151
|
|
|
break; |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
if (!$found) { |
156
|
|
|
throw new Exception("Configure item '$item' can not be found."); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
$this->config = $config; |
160
|
|
|
return $config; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
|
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Read configuration a directory, loop through all files and add |
167
|
|
|
* them into the $config array as: |
168
|
|
|
* [ |
169
|
|
|
* [ |
170
|
|
|
* "file" => filename for dir/file1.php, |
171
|
|
|
* "config" => result returned from dir/file1.php, |
172
|
|
|
* ], |
173
|
|
|
* [ |
174
|
|
|
* "file" => filename for dir/file2.php, |
175
|
|
|
* "config" => result returned from dir/file2.php, |
176
|
|
|
* ], |
177
|
|
|
* ]. |
178
|
|
|
* |
179
|
|
|
* @param string $path is the path to the directory containing config files. |
180
|
|
|
* |
181
|
|
|
* @return array with configuration for each file. |
182
|
|
|
*/ |
183
|
|
|
public function loadFromDir(string $path): array |
184
|
|
|
{ |
185
|
|
|
$config = []; |
186
|
|
|
foreach (glob("$path/*.php") as $file) { |
187
|
|
|
$config[] = [ |
188
|
|
|
"file" => $file, |
189
|
|
|
"config" => require $file, |
190
|
|
|
]; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
return $config; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
|
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Helper function for reading values from the configuration and apply |
200
|
|
|
* default values where configuration item is missing. This |
201
|
|
|
* helper only works when there are single configuration files, |
202
|
|
|
* it does not work when multiple configuration files are loaded |
203
|
|
|
* from a directory. |
204
|
|
|
* |
205
|
|
|
* @param string $key matching a key in the config array. |
206
|
|
|
* @param string $default value returned when config item is not found. |
207
|
|
|
* |
208
|
|
|
* @return mixed or null if key does not exists. |
209
|
|
|
*/ |
210
|
|
|
public function getConfig($key, $default = null) |
211
|
|
|
{ |
212
|
|
|
return $this->config["config"][$key] ?? $default; |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.