Completed
Push — master ( 33953d...4a13d7 )
by Xeriab
03:37
created

Konfig::__callStatic()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 0
cts 0
cp 0
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
crap 6
1
<?php
2
3
/**
4
 * Konfig.
5
 *
6
 * Yet another simple configuration loader library.
7
 *
8
 * PHP version 5
9
 *
10
 * @category Library
11
 * @package  Konfig
12
 * @author   Xeriab Nabil (aka KodeBurner) <[email protected]>
13
 * @license  https://raw.github.com/xeriab/konfig/master/LICENSE MIT
14
 * @link     https://xeriab.github.io/projects/konfig
15
 */
16
17
namespace Exen\Konfig;
18
19
use Exen\Konfig\Exception\Exception;
20
use Exen\Konfig\Exception\EmptyDirectoryException;
21
use Exen\Konfig\Exception\FileNotFoundException;
22
use Exen\Konfig\Exception\UnsupportedFileFormatException;
23
24
/**
25
 * Konfig
26
 * Main Konfig class.
27
 *
28
 * @category Main
29
 * @package  Konfig
30
 * @author   Xeriab Nabil (aka KodeBurner) <[email protected]>
31
 * @license  https://raw.github.com/xeriab/konfig/master/LICENSE MIT
32
 * @link     https://xeriab.github.io/projects/konfig
33
 *
34
 * @extends AbstractKonfig
35
 */
36
final class Konfig extends AbstractKonfig
37
{
38
    /**
39
     * Array of file parsers objects.
40
     *
41
     * @var array|null
42
     *
43
     * @since 0.1.0
44
     */
45
    protected $fileParsers;
46
47
    /**
48
     * Stores loaded configuration files.
49
     *
50
     * @var array Array of loaded configuration files
51
     *
52
     * @since 0.1.0
53
     */
54
    protected static $loadedFiles = [];
55
56
    /**
57
     * Array of loaded data.
58
     *
59
     * @var array|null
60
     *
61
     * @since 0.1.0
62
     */
63
    protected static $loadedData = null;
64
65
    /**
66
     * Loads a supported configuration file format.
67
     *
68
     * @param string|array|mixed $path    String file
69
     *                                    | configuration array | Konfig instance
70
     * @param array              $parsers Parsers
71
     *
72
     * @throws EmptyDirectoryException If `$path` is an empty directory
73
     */
74 33
    public function __construct($path = null, array $parsers = [])
75
    {
76 33
        $this->setFileParsers($parsers);
77
78 33
        $paths = $this->getValidPath($path);
79
80 24
        $this->data = [];
81
82 24
        foreach ($paths as $path) {
83
            // Get file information
84 24
            $info = pathinfo($path);
85
            // $info  = pathinfo($path, PATHINFO_EXTENSION);
86 24
            $parts = explode('.', $info['basename']);
87 24
            $ext = array_pop($parts);
88
89 24
            if ($ext === 'dist') {
90 3
                $ext = array_pop($parts);
91 2
            }
92
93 24
            $parser = $this->getParser($ext);
94
95
            // Try and load file
96 21
            $this->data = array_replace_recursive(
97 21
                $this->data,
98 21
                (array) $parser->parse($path)
99 14
            );
100
101 21
            self::$loadedFiles[$path] = true;
102 14
        }
103
104 21
        self::$loadedData = $this->data;
105
106 21
        parent::__construct($this->data);
107 21
    }
108
109
    /**
110
     * Static method for loading a Konfig instance.
111
     *
112
     * @param string|array|mixed $path      string file | configuration array
113
     *                                      | Konfig instance
114
     * @param array              $parsers   Parsers to use with Konfig
115
     * @param bool               $overwrite Whether to overwrite existing values
116
     * @param bool               $cache     Allow caching
117
     *
118
     * @return Konfig
119
     */
120 3
    public static function load(
121
        $path = null,
122
        array $parsers = [],
123
        $overwrite = false,
0 ignored issues
show
Unused Code introduced by
The parameter $overwrite is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
124
        $cache = true
0 ignored issues
show
Unused Code introduced by
The parameter $cache is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
125
    ) {
126 3
        return new static($path, $parsers);
127
    }
128
129
    /**
130
     * Static method for getting loaded Konfig files.
131
     *
132
     * @return array
133
     */
134
    public static function loaded()
135
    {
136
        return self::$loadedFiles;
137
    }
138
139
    /**
140
     * Get file parsers.
141
     *
142
     * @return FileParser[]
143
     *
144
     * @since              0.1.0
145
     * @codeCoverageIgnore
146
     */
147
    public function getFileParsers()
148
    {
149
        return $this->fileParsers;
150
    }
151
152
    /**
153
     * Add file parsers.
154
     *
155
     * @param FileParser $fileParser Parser
156
     *
157
     * @return             void Void
158
     * @since              0.1.0
159
     * @codeCoverageIgnore
160
     */
161
    protected function addFileParser(FileParser $fileParser)
162
    {
163
        $this->fileParsers[] = $fileParser;
164
    }
165
166
    /**
167
     * Set file parsers.
168
     *
169
     * @param array $fileParsers Parsers array
170
     *
171
     * @return             void Void
172
     * @since              0.1.0
173
     * @codeCoverageIgnore
174
     */
175
    protected function setFileParsers(array $fileParsers = [])
176
    {
177
        if (empty($fileParsers)) {
178
            $fileParsers = [
179
                new FileParser\Xml(),
180
                new FileParser\Ini(),
181
                new FileParser\Json(),
182
                new FileParser\Yaml(),
183
                new FileParser\Neon(),
184
                new FileParser\Toml(),
185
                new FileParser\Php(),
186
                new FileParser\Properties(),
187
            ];
188
        }
189
190
        $this->fileParsers = [];
191
192
        foreach ($fileParsers as $fileParser) {
193
            $this->addFileParser($fileParser);
194
        }
195
    }
196
197
    /**
198
     * Gets a parser for a given file extension.
199
     *
200
     * @param string $ext File extension
201
     *
202
     * @return FileParser
203
     *
204
     * @throws             Exception                      If `$ext` is empty
205
     * @throws             UnsupportedFileFormatException If `$path`
206
     * is an unsupported file format
207
     * @codeCoverageIgnore
208
     */
209
    private function getParser($ext = null)
210
    {
211
        $parser = null;
212
213
        if (empty($ext)) {
214
            throw new Exception('Files with empty extensions are not allowed');
215
        }
216
217
        $fileParsers = $this->getFileParsers();
218
219
        foreach ($fileParsers as $fileParser) {
0 ignored issues
show
Bug introduced by
The expression $fileParsers of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
220
            if (in_array($ext, $fileParser->getSupportedFileExtensions(), true)) {
221
                $parser = $fileParser;
222
                break;
223
            }
224
        }
225
226
        // If none exist, then throw an exception
227
        if (is_null($parser)) {
228
            throw new UnsupportedFileFormatException(
229
                'Unsupported configuration format'
230
            );
231
        }
232
233
        return $parser;
234
    }
235
236
    /**
237
     * Gets an array of paths.
238
     *
239
     * @param array $path Path to analyze and handle
240
     *
241
     * @return array
242
     *
243
     * @throws FileNotFoundException If a file is not found in `$path`
244
     */
245
    private function pathFromArray($path)
246
    {
247
        $paths = [];
248
249
        foreach ($path as $unverifiedPath) {
250
            try {
251
                // Check if `$unverifiedPath` is optional
252
                // If it exists, then it's added to the list
253
                // If it doesn't, it throws an exception which we catch
254
                if ($unverifiedPath[0] !== '?') {
255
                    $paths = array_merge(
256
                        $paths,
257
                        $this->getValidPath($unverifiedPath)
258
                    );
259
260
                    continue;
261
                }
262
263
                $optionalPath = ltrim($unverifiedPath, '?');
264
265
                $paths = array_merge($paths, $this->getValidPath($optionalPath));
266
            } catch (FileNotFoundException $e) {
267
                // If `$unverifiedPath` is optional, then skip it
268
                if ($unverifiedPath[0] === '?') {
269
                    continue;
270
                }
271
272
                // Otherwise rethrow the exception
273
                throw $e;
274
            }
275
        }
276
277
        return $paths;
278
    }
279
280
    /**
281
     * Checks `$path` to see if it is either an array, a directory, or a file.
282
     *
283
     * @param string|array $path Path to analyze and handle
284
     *
285
     * @return array
286
     *
287
     * @throws EmptyDirectoryException If `$path` is an empty directory
288
     * @throws FileNotFoundException   If a file is not found at `$path`
289
     */
290 30
    private function getValidPath($path)
291
    {
292
        // If `$path` is array
293 30
        if (is_array($path)) {
294 12
            return $this->pathFromArray($path);
295
        }
296
297
        // If `$path` is a directory
298 30
        if (is_dir($path)) {
299 6
            $paths = glob($path.'/*.*');
300
301 6
            if (empty($paths)) {
302 3
                throw new EmptyDirectoryException(
303 3
                    "Configuration directory: [$path] is empty"
304 2
                );
305
            }
306
307 3
            return $paths;
308
        }
309
310
        // If `$path` is not a file, throw an exception
311 24
        if (!file_exists($path)) {
312 9
            throw new FileNotFoundException(
313 9
                "Configuration file: [$path] cannot be found"
314 6
            );
315
        }
316
317 21
        return [$path];
318
    }
319
320
    /**
321
     * __call.
322
     *
323
     * @param string       $name      Method name
324
     * @param string|array $arguments Arguments to pass
325
     *
326
     * @return             mixed
327
     * @since              0.2.5
328
     * @codeCoverageIgnore
329
     */
330
    public function __call($name, $arguments)
331
    {
332
        switch ($name) {
333
            case 'get':
334
                return call_user_func_array(
335
                    [get_called_class(), 'get'],
336
                    $arguments
337
                );
338
        }
339
    }
340
341
    /**
342
     * __callStatic.
343
     *
344
     * @param string       $name      Method name
345
     * @param string|array $arguments Arguments to pass
346
     *
347
     * @return             mixed
348
     * @since              0.2.5
349
     * @codeCoverageIgnore
350
     */
351
    public static function __callStatic($name, $arguments)
352
    {
353
        switch ($name) {
354
            case 'get':
355
                return call_user_func_array(
356
                    [get_called_class(), 'get'],
357
                    $arguments
358
                );
359
        }
360
    }
361
362
    /**
363
     * __toString.
364
     *
365
     * @return             string
366
     * @since              0.1.2
367
     * @codeCoverageIgnore
368
     */
369
    public function __toString()
370
    {
371
        return 'Exen\Konfig\Konfig' . PHP_EOL;
372
    }
373
}
374
375
// END OF ./src/Konfig.php FILE
376