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