Konfig::getFileParsers()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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
 * Main Konfig class.
26
 *
27
 * @category Main
28
 * @package  Konfig
29
 * @author   Xeriab Nabil (aka KodeBurner) <[email protected]>
30
 * @license  https://raw.github.com/xeriab/konfig/master/LICENSE MIT
31
 * @link     https://xeriab.github.io/projects/konfig
32
 *
33
 * @extends AbstractKonfig
34
 */
35
final class Konfig extends AbstractKonfig
36
{
37
    /**
38
     * Array of file parsers objects.
39
     *
40
     * @var array|null
41
     *
42
     * @since 0.1.0
43
     */
44
    protected $fileParsers;
45
46
    /**
47
     * Stores loaded configuration files.
48
     *
49
     * @var array Array of loaded configuration files
50
     *
51
     * @since 0.1.0
52
     */
53
    protected static $loadedFiles = [];
54
55
    /**
56
     * Array of loaded data.
57
     *
58
     * @var array|null
59
     *
60
     * @since 0.1.0
61
     */
62
    protected static $loadedData = null;
63
64
    /**
65
     * Loads a supported configuration file format.
66
     *
67
     * @param string|array|mixed $path      String file | configuration array
68
     * | Konfig instance | configuration array | Konfig instance
69
     * @param array              $parsers   Parsers
70
     * @param bool               $overwrite Whether to overwrite existing values
71
     * @param bool               $cache     Allow caching
72
     *
73
     * @throws EmptyDirectoryException If `$path` is an empty directory
74
     */
75 33
    public function __construct(
76
        $path = null,
77
        array $parsers = [],
78
        $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...
79
        $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...
80
    ) {
81 33
        $this->setFileParsers($parsers);
82
83 33
        $paths = $this->getValidPath($path);
84
85 24
        $this->data = [];
86
87 24
        foreach ($paths as $path) {
88
            // Get file information
89 24
            $info = pathinfo($path);
90
            // $info  = pathinfo($path, PATHINFO_EXTENSION);
91 24
            $parts = explode('.', $info['basename']);
92 24
            $ext = array_pop($parts);
93
94 24
            if ($ext === 'dist') {
95 3
                $ext = array_pop($parts);
96 1
            }
97
98 24
            $parser = $this->getParser($ext);
99
100
            // Try and load file
101 21
            $this->data = array_replace_recursive(
102 21
                $this->data,
103 21
                (array) $parser->parse($path)
104 7
            );
105
106 21
            self::$loadedFiles[$path] = true;
107 7
        }
108
109 21
        self::$loadedData = $this->data;
110
111 21
        parent::__construct($this->data);
112 21
    }
113
114
    /**
115
     * Static method for loading a Konfig instance.
116
     *
117
     * @param string|array|mixed $path      string file | configuration array
118
     *                                      | Konfig instance
119
     * @param array              $parsers   Parsers to use with Konfig
120
     * @param bool               $overwrite Whether to overwrite existing values
121
     * @param bool               $cache     Allow caching
122
     *
123
     * @return Konfig
124
     */
125 3
    public static function load(
126
        $path = null,
127
        array $parsers = [],
128
        $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...
129
        $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...
130
    ) {
131 3
        return new static($path, $parsers);
132
    }
133
134
    /**
135
     * Static method for getting loaded Konfig files.
136
     *
137
     * @return array
138
     */
139
    public static function loaded()
140
    {
141
        return self::$loadedFiles;
142
    }
143
144
    /**
145
     * Get file parsers.
146
     *
147
     * @return FileParser[]
148
     *
149
     * @since              0.1.0
150
     * @codeCoverageIgnore
151
     */
152
    public function getFileParsers()
153
    {
154
        return $this->fileParsers;
155
    }
156
157
    /**
158
     * Add file parsers.
159
     *
160
     * @param FileParser $fileParser Parser
161
     *
162
     * @return             void Void
163
     * @since              0.1.0
164
     * @codeCoverageIgnore
165
     */
166
    protected function addFileParser(FileParser $fileParser)
167
    {
168
        $this->fileParsers[] = $fileParser;
169
    }
170
171
    /**
172
     * Set file parsers.
173
     *
174
     * @param array $fileParsers Parsers array
175
     *
176
     * @return             void Void
177
     * @since              0.1.0
178
     * @codeCoverageIgnore
179
     */
180
    protected function setFileParsers(array $fileParsers = [])
181
    {
182
        if (empty($fileParsers)) {
183
            $fileParsers = [
184
                new FileParser\Xml(),
185
                new FileParser\Ini(),
186
                new FileParser\Json(),
187
                new FileParser\Php(),
188
                new FileParser\Yaml(),
189
                new FileParser\Neon(),
190
                new FileParser\Toml(),
191
                new FileParser\Properties(),
192
            ];
193
        }
194
195
        $this->fileParsers = [];
196
197
        foreach ($fileParsers as $fileParser) {
198
            $this->addFileParser($fileParser);
199
        }
200
    }
201
202
    /**
203
     * Gets a parser for a given file extension.
204
     *
205
     * @param string|null $ext File extension
206
     *
207
     * @return FileParser
208
     *
209
     * @throws Exception                      If `$ext` is empty
210
     * @throws UnsupportedFileFormatException If `$path`
211
     * is an unsupported file format
212
     */
213
    private function getParser($ext = null)
214
    {
215
        $parser = null;
216 27
217
        if (empty($ext)) {
218 27
            throw new Exception('Files with empty extensions are not allowed');
219
        }
220 27
221
        $fileParsers = $this->getFileParsers();
222
223
        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...
224 27
            if (in_array($ext, $fileParser->getSupportedFileExtensions(), true)) {
225
                $parser = $fileParser;
226 27
                break;
227 27
            }
228 21
        }
229 25
230
        // If none exist, then throw an exception
231 9
        if (is_null($parser)) {
232
            throw new UnsupportedFileFormatException(
233
                'Unsupported configuration format'
234 27
            );
235 6
        }
236 4
237 2
        return $parser;
238
    }
239
240 21
    /**
241
     * Gets an array of paths.
242
     *
243
     * @param array $path Path to analyze and handle
244
     *
245
     * @return array
246
     *
247
     * @throws             FileNotFoundException If a file is not found in `$path`
248
     * @codeCoverageIgnore
249
     */
250
    private function pathFromArray($path)
251
    {
252
        $paths = [];
253
254
        foreach ($path as $unverifiedPath) {
255
            try {
256
                // Check if `$unverifiedPath` is optional
257
                // If it exists, then it's added to the list
258
                // If it doesn't, it throws an exception which we catch
259
                if ($unverifiedPath[0] !== '?') {
260
                    $paths = array_merge(
261
                        $paths,
262
                        $this->getValidPath($unverifiedPath)
263
                    );
264
265
                    continue;
266
                }
267
268
                $optionalPath = ltrim($unverifiedPath, '?');
269
270
                $paths = array_merge($paths, $this->getValidPath($optionalPath));
271
            } catch (FileNotFoundException $e) {
272
                // If `$unverifiedPath` is optional, then skip it
273
                if ($unverifiedPath[0] === '?') {
274
                    continue;
275
                }
276
277
                // Otherwise rethrow the exception
278
                throw $e;
279
            }
280
        }
281
282
        return $paths;
283
    }
284
285
    /**
286
     * Checks `$path` to see if it is either an array, a directory, or a file.
287
     *
288
     * @param string|array $path Path to analyze and handle
289
     *
290
     * @return array
291
     *
292
     * @throws EmptyDirectoryException If `$path` is an empty directory
293
     * @throws FileNotFoundException   If a file is not found at `$path`
294
     */
295
    private function getValidPath($path)
296
    {
297
        // If `$path` is array
298 30
        if (is_array($path)) {
299
            return $this->pathFromArray($path);
300
        }
301 30
302 12
        // If `$path` is a directory
303
        if (is_dir($path)) {
304
            $paths = glob($path.'/*.*');
305
306 30
            if (empty($paths)) {
307 6
                throw new EmptyDirectoryException(
308
                    "Configuration directory: [$path] is empty"
309 6
                );
310 3
            }
311 3
312 1
            return $paths;
313
        }
314
315 3
        // If `$path` is not a file, throw an exception
316
        if (!file_exists($path)) {
317
            throw new FileNotFoundException(
318
                "Configuration file: [$path] cannot be found"
319 24
            );
320 9
        }
321 9
322 3
        return [$path];
323
    }
324
325 21
    /**
326
     * __toString.
327
     *
328
     * @return             string
329
     * @since              0.1.2
330
     * @codeCoverageIgnore
331
     */
332
    public function __toString()
333
    {
334
        return 'Exen\Konfig\Konfig' . PHP_EOL;
335
    }
336
}
337
338
// END OF ./src/Konfig.php FILE
339