Completed
Push — 3.0 ( fea5eb...c29f0e )
by Vermeulen
02:17
created

Config::setConfigKeyForFile()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.2408
c 0
b 0
f 0
cc 5
nc 12
nop 3
1
<?php
2
3
namespace BFW;
4
5
use \Exception;
6
7
/**
8
 * Class to load all files from a directory in config dir.
9
 */
10
class Config
11
{
12
    /**
13
     * @const ERR_JSON_PARSE Exception code if the parse of a json file fail.
14
     */
15
    const ERR_JSON_PARSE = 1302001;
16
    
17
    /**
18
     * @const ERR_GETVALUE_FILE_NOT_INDICATED Exception code if the file to use
19
     * is not indicated into the method getValue().
20
     * (only if there are many config files)
21
     */
22
    const ERR_GETVALUE_FILE_NOT_INDICATED = 1302002;
23
    
24
    /**
25
     * @const ERR_GETVALUE_FILE_NOT_FOUND Exception code if the file to use is
26
     * not found.
27
     */
28
    const ERR_FILE_NOT_FOUND = 1302003;
29
    
30
    /**
31
     * @const ERR_GETVALUE_KEY_NOT_FOUND Exception code if the asked config key
32
     * not exist.
33
     */
34
    const ERR_KEY_NOT_FOUND = 1303004;
35
    
36
    /**
37
     * @const ERR_VALUE_FORMAT Exception code if the value for a filename is
38
     * not an array or an object.
39
     */
40
    const ERR_VALUE_FORMAT = 1303005;
41
    
42
    /**
43
     * @const ERR_KEY_NOT_ADDED Exception code if the key can not be added to
44
     * the config.
45
     */
46
    const ERR_KEY_NOT_ADDED = 1303006;
47
    
48
    /**
49
     * @var string $configDirName Directory's name in config dir
50
     */
51
    protected $configDirName = '';
52
53
    /**
54
     * @var string $configDir Complete path of the readed directory
55
     */
56
    protected $configDir = '';
57
58
    /**
59
     * @var string[] $configFiles List of files to read
60
     */
61
    protected $configFiles = [];
62
63
    /**
64
     * @var array $config List of config value found
65
     */
66
    protected $config = [];
67
68
    /**
69
     * Constructor
70
     * Define properties configDirName and configDir
71
     * 
72
     * @param string $configDirName Directory's name in config dir
73
     */
74
    public function __construct($configDirName)
75
    {
76
        $this->configDirName = $configDirName;
77
        $this->configDir     = CONFIG_DIR.$this->configDirName;
78
    }
79
    
80
    /**
81
     * Getter accessor to the property configDirName
82
     * 
83
     * @return string
84
     */
85
    public function getConfigDirName()
86
    {
87
        return $this->configDirName;
88
    }
89
90
    /**
91
     * Getter accessor to the property configDir
92
     * 
93
     * @return string
94
     */
95
    public function getConfigDir()
96
    {
97
        return $this->configDir;
98
    }
99
100
    /**
101
     * Getter accessor to the property configFiles
102
     * 
103
     * @return string[]
104
     */
105
    public function getConfigFiles()
106
    {
107
        return $this->configFiles;
108
    }
109
    
110
    /**
111
     * Getter accessor to $config property
112
     * 
113
     * @return array
114
     */
115
    public function getConfig()
116
    {
117
        return $this->config;
118
    }
119
    
120
    /**
121
     * Getter accessor to have all values contain into a config file
122
     * 
123
     * @param string $filename The filename config to read
124
     * 
125
     * @return mixed
126
     */
127
    public function getConfigByFilename($filename)
128
    {
129 View Code Duplication
        if (!isset($this->config[$filename])) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
130
            throw new Exception(
131
                'The file '.$filename.' has not been found',
132
                $this::ERR_FILE_NOT_FOUND
133
            );
134
        }
135
        
136
        return $this->config[$filename];
137
    }
138
    
139
    /**
140
     * Search and load all config files which has been found
141
     * 
142
     * @return void
143
     */
144
    public function loadFiles()
145
    {
146
        $this->searchAllConfigFiles($this->configDir);
147
        
148
        foreach ($this->configFiles as $fileKey => $filePath) {
149
            $this->loadConfigFile($fileKey, $filePath);
150
        }
151
    }
152
153
    /**
154
     * Search all config files in a directory
155
     * Search also in sub-directory (2nd parameter)
156
     * 
157
     * @param string $dirPath The directory path where is run the search
158
     * @param string $pathIntoFirstDir (default '') Used when this method
159
     *  reads a subdirectory. It's the path of the readed directory during
160
     *  the first call to this method.
161
     * 
162
     * @return void
163
     */
164
    protected function searchAllConfigFiles($dirPath, $pathIntoFirstDir = '')
165
    {
166
        if (!file_exists($dirPath)) {
167
            return;
168
        }
169
170
        //Remove some value in list of file
171
        $listFiles = array_diff(scandir($dirPath), ['.', '..']);
172
173
        foreach ($listFiles as $file) {
174
            $fileKey  = $pathIntoFirstDir.$file;
175
            $readPath = $dirPath.'/'.$file;
176
            
177
            if (is_link($readPath)) {
178
                $readPath = realpath($readPath);
179
            }
180
181
            if (is_file($readPath)) {
182
                $this->configFiles[$fileKey] = $readPath;
183
            } elseif (is_dir($readPath)) {
184
                $this->searchAllConfigFiles(
185
                    $readPath,
186
                    $pathIntoFirstDir.$file.'/'
187
                );
188
            }
189
        }
190
    }
191
192
    /**
193
     * Load a config file.
194
     * Find the file's extension and call the method to parse the file
195
     * 
196
     * @param string $fileKey The file's key. Most of the time, the path to
197
     *  the file from the $this->configDir value
198
     * @param string $filePath The path to the file
199
     * 
200
     * @return void
201
     */
202
    protected function loadConfigFile($fileKey, $filePath)
203
    {
204
        $fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
205
206
        if ($fileExtension === 'json') {
207
            $this->loadJsonConfigFile($fileKey, $filePath);
208
            return;
209
        }
210
211
        if ($fileExtension === 'php') {
212
            $this->loadPhpConfigFile($fileKey, $filePath);
213
            return;
214
        }
215
216
        //@TODO : YAML
217
    }
218
219
    /**
220
     * Load a json config file
221
     * 
222
     * @param string $fileKey The file's key. Most of the time, the path to
223
     *  the file from the $this->configDir value
224
     * @param string $filePath The path to the file
225
     * 
226
     * @return void
227
     * 
228
     * @throws Exception If there is an error from the json parser
229
     */
230
    protected function loadJsonConfigFile($fileKey, $filePath)
231
    {
232
        $json   = file_get_contents($filePath);
233
        $config = json_decode($json);
234
235
        if ($config === null) {
236
            throw new Exception(
237
                json_last_error_msg(),
238
                $this::ERR_JSON_PARSE
239
            );
240
        }
241
242
        $this->config[$fileKey] = $config;
243
    }
244
245
    /**
246
     * Load a php config file
247
     * 
248
     * @param string $fileKey The file's key. Most of the time, the path to
249
     *  the file from the $this->configDir value
250
     * @param string $filePath The path to the file
251
     * 
252
     * @return void
253
     */
254
    protected function loadPhpConfigFile($fileKey, $filePath)
255
    {
256
        $this->config[$fileKey] = require($filePath);
257
    }
258
259
    /**
260
     * Return a config value for a key
261
     * 
262
     * @param string $key The asked key for the value
263
     * @param string $file (default null) If many file is loaded, the file name
264
     *  where is the key. Is the file is into a sub-directory, the
265
     *  sub-directory should be present.
266
     * 
267
     * @return mixed
268
     * 
269
     * @throws Exception If file parameter is null and there are many files. Or
270
     *  if the file not exist. Or if the key not exist.
271
     */
272
    public function getValue($key, $file = null)
273
    {
274
        $nbConfigFile = count($this->config);
275
276
        if ($file === null && $nbConfigFile > 1) {
277
            throw new Exception(
278
                'There are many config files. Please indicate the file to'
279
                .' obtain the config '.$key,
280
                $this::ERR_GETVALUE_FILE_NOT_INDICATED
281
            );
282
        }
283
284
        if ($nbConfigFile === 1) {
285
            $file = key($this->config);
286
        }
287
288 View Code Duplication
        if (!isset($this->config[$file])) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
289
            throw new Exception(
290
                'The file '.$file.' has not been found for config '.$key,
291
                $this::ERR_FILE_NOT_FOUND
292
            );
293
        }
294
295
        $config = (array) $this->config[$file];
296
        if (!array_key_exists($key, $config)) {
297
            throw new Exception(
298
                'The config key '.$key.' has not been found',
299
                $this::ERR_KEY_NOT_FOUND
300
            );
301
        }
302
303
        return $config[$key];
304
    }
305
    
306
    /**
307
     * Setter to modify the all config value for a specific filename.
308
     * 
309
     * @param string $filename The filename config to modify
310
     * @param array|\stdClass $config The new config value
311
     * 
312
     * @return $this
313
     * 
314
     * @throws \Exception If the new value if not an array or an object.
315
     */
316
    public function setConfigForFilename($filename, $config)
317
    {
318
        if (!is_array($config) && !is_object($config)) {
319
            throw new Exception(
320
                'The config value shoud be an array or an object.',
321
                $this::ERR_VALUE_FORMAT
322
            );
323
        }
324
        
325
        if (!isset($this->configFiles[$filename])) {
326
            $this->configFiles[$filename] = $filename;
327
        }
328
        
329
        $this->config[$filename] = $config;
330
        
331
        return $this;
332
    }
333
    
334
    /**
335
     * Setter to modify a config key into the config of a filename
336
     * 
337
     * @param string $filename The filename config to modify
338
     * @param string $configKey The name of the key to modify
339
     * @param mixed $configValue The new value for the config key
340
     * 
341
     * @return $this
342
     * 
343
     * @throws \Exception If the key has not been found
344
     */
345
    public function setConfigKeyForFilename($filename, $configKey, $configValue)
346
    {
347
        if (!isset($this->config[$filename])) {
348
            $this->config[$filename] = new \stdClass;
349
        }
350
        
351
        if (!isset($this->configFiles[$filename])) {
352
            $this->configFiles[$filename] = $filename;
353
        }
354
        
355
        if (is_array($this->config[$filename])) {
356
            $this->config[$filename][$configKey] = $configValue;
357
        } elseif (is_object($this->config[$filename])) {
358
            $this->config[$filename]->{$configKey} = $configValue;
359
        } else {
360
            throw new Exception(
361
                'The config key '.$configKey.' can not be added.',
362
                $this::ERR_KEY_NOT_ADDED
363
            );
364
        }
365
        
366
        return $this;
367
    }
368
}
369