Completed
Push — master ( 0c83ff...fee93b )
by Xeriab
04:37
created

Konfig::getValidPath()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 25
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 3 Features 0
Metric Value
c 7
b 3
f 0
dl 0
loc 25
rs 8.439
cc 5
eloc 11
nc 5
nop 1
1
<?php
2
/**
3
 * Konfig
4
 *
5
 * Yet another simple configuration file loader library.
6
 *
7
 * @author  Xeriab Nabil (aka KodeBurner) <[email protected]>
8
 * @license https://raw.github.com/xeriab/konfig/master/LICENSE MIT
9
 * @link    https://xeriab.github.io/projects/konfig
10
 */
11
namespace Exen\Konfig;
12
13
use Exception;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Exen\Konfig\Exception.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
14
use Exen\Konfig\Exception\EmptyDirectoryException;
15
use Exen\Konfig\Exception\FileNotFoundException;
16
use Exen\Konfig\Exception\UnsupportedFileFormatException;
17
18
final class Konfig extends AbstractKonfig
19
{
20
    /**
21
     * @var FileParser[] $fileParsers Array of file parsers objects
22
     * @since 0.1
23
     */
24
    protected $fileParsers;
25
26
    /**
27
     * Stores loaded configuration files
28
     *
29
     * @var array $loadedFiles Array of loaded configuration files
30
     * @since 0.1
31
     */
32
    protected static $loadedFiles = [];
33
34
    /**
35
     * Loads a supported configuration file format.
36
     *
37
     * @param  string|array|mixed $path String file | configuration array | Konfig instance
38
     * @throws EmptyDirectoryException If `$path` is an empty directory
39
     */
40
    public function __construct($path, array $parsers = [])
41
    {
42
        $this->setFileParsers($parsers);
43
44
        $paths = $this->getValidPath($path);
45
46
        $this->data = [];
47
48
        foreach ($paths as $path) {
49
            // Get file information
50
            $ext    = pathinfo($path, PATHINFO_EXTENSION);
51
            $parser = $this->getParser($ext);
52
53
            // Try and load file
54
            $this->data = array_replace_recursive($this->data, $parser->parse($path));
55
56
            self::$loadedFiles[$path] = true;
57
        }
58
59
        parent::__construct($this->data);
60
    }
61
62
    /**
63
     * Static method for loading a Konfig instance.
64
     *
65
     * @param  string|array|mixed $path string file | configuration array | Konfig instance
66
     * @return Konfig
67
     */
68
    public static function load($path = null)
69
    {
70
        return new static($path);
71
    }
72
73
    /**
74
     * Static method for getting loaded Konfig files.
75
     *
76
     * @return array
77
     */
78
    public static function loaded()
79
    {
80
        return self::$loadedFiles;
81
    }
82
83
    /**
84
     * Static method for getting all Konfig keys.
85
     *
86
     * @return array
87
     */
88
    public static function keys()
89
    {
90
        // @TODO: Fix this soon
91
    }
92
93
    /**
94
     * @return FileParser[]
95
     * @since 0.1
96
     */
97
    public function getFileParsers()
98
    {
99
        return $this->fileParsers;
100
    }
101
102
    /**
103
     * @return void
104
     * @since 0.1
105
     */
106
    protected function addFileParser(FileParser $fileParser)
107
    {
108
        $this->fileParsers[] = $fileParser;
109
    }
110
111
    /**
112
     * @return void
113
     * @since 0.1
114
     */
115
    protected function setFileParsers(array $fileParsers = [])
116
    {
117
        if (empty($fileParsers)) {
118
            $fileParsers = [
119
                new FileParser\Xml(),
120
                new FileParser\Ini(),
121
                new FileParser\Json(),
122
                new FileParser\Yaml(),
123
                new FileParser\Neon(),
124
                new FileParser\Toml(),
125
                new FileParser\Php(),
126
            ];
127
        }
128
129
        $this->fileParsers = [];
130
131
        foreach ($fileParsers as $fileParser) {
132
            $this->addFileParser($fileParser);
133
        }
134
    }
135
136
    /**
137
     * Gets a parser for a given file extension
138
     *
139
     * @param  string $ext
140
     * @return Konfig\FileParser
141
     * @throws UnsupportedFileFormatException If `$path` is an unsupported file format
142
     */
143
    private function getParser($ext)
144
    {
145
        $parser = null;
146
147
        if (empty($ext)) {
148
            // @TODO: Throw an exception.
149
        }
150
151
        $fileParsers = $this->getFileParsers();
152
153
        foreach ($fileParsers as $fileParser) {
154
            if (in_array($ext, $fileParser->getSupportedFileExtensions(), true)) {
155
                $parser = $fileParser;
156
                break;
157
            }
158
        }
159
160
        // If none exist, then throw an exception
161
        if (is_null($parser)) {
162
            throw new UnsupportedFileFormatException('Unsupported configuration format');
163
        }
164
165
        return $parser;
166
    }
167
168
    /**
169
     * Gets an array of paths
170
     *
171
     * @param array $path
172
     * @return array
173
     * @throws FileNotFoundException If a file is not found in `$path`
174
     */
175
    private function pathFromArray($path)
176
    {
177
        $paths = [];
178
179
        foreach ($path as $unverifiedPath) {
180
            try {
181
                // Check if `$unverifiedPath` is optional
182
                // If it exists, then it's added to the list
183
                // If it doesn't, it throws an exception which we catch
184
                if ($unverifiedPath[0] !== '?') {
185
                    $paths = array_merge($paths, $this->getValidPath($unverifiedPath));
186
                    continue;
187
                }
188
189
                $optionalPath = ltrim($unverifiedPath, '?');
190
191
                $paths = array_merge($paths, $this->getValidPath($optionalPath));
192
            } catch (FileNotFoundException $e) {
193
                // If `$unverifiedPath` is optional, then skip it
194
                if ($unverifiedPath[0] === '?') {
195
                    continue;
196
                }
197
198
                // Otherwise rethrow the exception
199
                throw $e;
200
            }
201
        }
202
203
        return $paths;
204
    }
205
206
    /**
207
     * Checks `$path` to see if it is either an array, a directory, or a file
208
     *
209
     * @param  string|array $path
210
     * @return array
211
     * @throws EmptyDirectoryException If `$path` is an empty directory
212
     * @throws FileNotFoundException If a file is not found at `$path`
213
     */
214
    private function getValidPath($path = null)
215
    {
216
        // If `$path` is array
217
        if (is_array($path)) {
218
            return $this->pathFromArray($path);
219
        }
220
221
        // If `$path` is a directory
222
        if (is_dir($path)) {
223
            $paths = glob($path . '/*.*');
224
225
            if (empty($paths)) {
226
                throw new EmptyDirectoryException("Configuration directory: [$path] is empty");
227
            }
228
229
            return $paths;
230
        }
231
232
        // If `$path` is not a file, throw an exception
233
        if (!file_exists($path)) {
234
            throw new FileNotFoundException("Configuration file: [$path] cannot be found");
235
        }
236
237
        return [$path];
238
    }
239
240
    /**
241
     * @return string
242
     * @since 0.1
243
     */
244
    public function __toString()
245
    {
246
        return 'Konfig';
247
    }
248
}
249
250
#: END OF ./src/Konfig.php FILE
251