Completed
Push — master ( 88b8c9...f7af16 )
by Michael
02:28
created

FileLoader::getFilesNamespace()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 17
rs 9.4286
cc 2
eloc 10
nc 2
nop 1
1
<?php
2
namespace Michaels\Manager;
3
4
use Michaels\Manager\Contracts\DecoderInterface;
5
use Michaels\Manager\Bags\FileBag;
6
use Michaels\Manager\Exceptions\UnsupportedFilesException;
7
use Michaels\Manager\Exceptions\BadFileDataException;
8
use Exception;
9
10
/**
11
 * Loads configuration files and converts them to php arrays using Decoders
12
 * @package Michaels\Manager
13
 */
14
class FileLoader
15
{
16
    /**
17
     * The data which will be decoded.
18
     * @var array
19
     */
20
    protected $dataToDecode = [];
21
22
    /**
23
     * The array of supported Mime types, which is defined in each decoder class.
24
     * @var array
25
     */
26
    protected $supportedMimeTypes = [];
27
28
    /**
29
     * A container for the SPLFileInfo objects
30
     * @var FileBag
31
     */
32
    protected $fileBag;
33
34
    /**
35
     * An array holding data about the loaded decoders.
36
     * @var array
37
     */
38
    protected $decoders = [];
39
40
    /**
41
     * Should there be an attempt to load an unsupported file type (determined by the mime types array), then they
42
     * will be stored in this array for later display in an error message.
43
     *
44
     * @var array
45
     */
46
    protected $unsupportedFiles = [];
47
48
    /**
49
     * The data array, once it has been processed through a decoder.
50
     * @var array
51
     */
52
    protected $decodedData = [];
53
54
    /**
55
     * Add a file decoder to the FileLoader
56
     * @param DecoderInterface $decoder
57
     */
58
    public function addDecoder(DecoderInterface $decoder)
59
    {
60
        $mimeTypes = $decoder->getMimeType();
61
        if ($this->isSupportedMimeType($mimeTypes[0])) {
62
            return; // we already have the decoder loaded!
63
        }
64
        $this->supportedMimeTypes = array_merge($this->supportedMimeTypes, $mimeTypes);
65
        foreach ($mimeTypes as $type) {
66
            $this->decoders[$type] = $decoder;
67
        }
68
    }
69
70
    /**
71
     * Add a file bag, or change an array of SplFileInfo Objects to proper objects.
72
     *
73
     * @param mixed $files a FileBag or an array of SplFileInfo objects.
74
     */
75
    public function addFiles($files)
76
    {
77
        if ($files instanceof Filebag) {
78
            $this->fileBag = $files;
79
            return;
80
        }
81
82
        if (is_array($files)) {
83
            $this->fileBag = new FileBag($files);
84
            return;
85
        }
86
        throw new BadFileDataException('The attempt at adding files to the file loader failed, due to the files not
87
        being a FileBag Object or an array of SplInfoObjects.');
88
    }
89
90
    /**
91
     * Process the current FileBag and return an array
92
     * @return array
93
     * @throws Exception
94
     */
95
    public function process()
96
    {
97
        return $this->decodedData = $this->decodeFileBagData($this->fileBag);
98
    }
99
100
    /**
101
     * Process file bag to load into the data manager.
102
     * A file bag is an array of SplFileInfo objects.
103
     *
104
     * @param array|FileBag $fileBag
105
     * @return array
106
     * @throws Exception
107
     */
108
    public function decodeFileBagData(FileBag $fileBag)
109
    {
110
        $decodedData = [];
111
        $files = $fileBag->getAllFileInfoObjects();
112
        if (empty($files)) {
113
            throw new Exception("FileBag is empty. Make sure you have initialized the FileLoader and added files.");
114
        }
115
116
        foreach ($files as $file) {
117
            list($namespace, $file) = $this->getFilesNamespace($file);
118
119
            // Decode the actual file and save data
120
            $fileData = $this->decodeFile($file);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $fileData is correct as $this->decodeFile($file) (which targets Michaels\Manager\FileLoader::decodeFile()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
121
            if ($fileData) {
122
                foreach ($fileData as $k => $v) {
123
                    $decodedData[$namespace][$k] = $v;
124
                }
125
            }
126
        }
127
128
        if (!empty($this->unsupportedFiles)) {
129
            $badFiles = implode(", ", $this->unsupportedFiles);
130
            throw new UnsupportedFilesException(
131
                'The file(s) ' . $badFiles . ' are not supported by the available decoders.'
132
            );
133
        }
134
135
        return $decodedData;
136
    }
137
138
    /**
139
     * Check to make sure the mime type is ok.
140
     * @param $type a mime type
141
     * @return bool
142
     */
143
    protected function isSupportedMimeType($type)
144
    {
145
        return in_array($type, $this->supportedMimeTypes);
146
    }
147
148
    /**
149
     * Returns the contents of the file.
150
     *
151
     * @return string the contents of the file
152
     * @throws \RuntimeException
153
     */
154
    protected function getFileContents($file)
155
    {
156
        if ($file->getExtension() === 'php') {
157
            $content = include $file->getPathname();
158
            return $content;
159
        }
160
161
        $level = error_reporting(0);
162
        $content = file_get_contents($file->getPathname());
163
        error_reporting($level);
164
        if (false === $content) {
165
            $error = error_get_last();
166
            throw new \RuntimeException($error['message']);
167
        }
168
        return $content;
169
    }
170
171
    /**
172
     * Default decoder class factory method.
173
     * Checks to make sure we have a default decoder available and if so, adds it as a decoder to the file loader.
174
     *
175
     * @param $mimeType
176
     */
177
    protected function checkAndAddDefaultDecoder($mimeType)
178
    {
179
        $decoderClass = ucfirst($mimeType) . "Decoder";
180
181
        if (file_exists(__DIR__ . '/Decoders/' . $decoderClass . '.php') && !$this->isSupportedMimeType($mimeType)) {
182
            $nameSpace = "Michaels\\Manager\\Decoders\\";
183
            $fullQualifiedClassName = $nameSpace . $decoderClass;
184
            $decoder = new $fullQualifiedClassName();
185
            $this->addDecoder($decoder);
186
        }
187
    }
188
189
    /**
190
     * Decodes a single file using registered decoders
191
     * @param $file
192
     * @return null
193
     */
194
    protected function decodeFile($file)
195
    {
196
        $mimeType = $file->getExtension();
197
198
        $this->checkAndAddDefaultDecoder($mimeType);
199
200
        if ($this->isSupportedMimeType($mimeType)) {
201
            $data = $this->getFileContents($file);
202
            return $this->decoders[$mimeType]->decode($data);
203
        }
204
205
        $this->unsupportedFiles[] = $file->getFilename();
206
        return false;
207
    }
208
209
    /**
210
     * Returns currently attached custom decoders
211
     * @return array
212
     */
213
    public function getDecoders()
214
    {
215
        return $this->decoders;
216
    }
217
218
    /**
219
     * Returns currently supported Mime Types
220
     * @return array
221
     */
222
    public function getMimeTypes()
223
    {
224
        return $this->supportedMimeTypes;
225
    }
226
227
    /**
228
     * Cleans up a file name for use as a namespace
229
     * @param $ns
230
     * @return mixed
231
     */
232
    public function sanitizeNamespace($ns)
233
    {
234
        // dots to underscores
235
        $ns = str_replace(".", "_", $ns);
236
237
        // spaces to underscores
238
        $ns = str_replace(" ", "_", $ns);
239
240
        // dashes to underscores
241
        $ns = str_replace("-", "_", $ns);
242
243
        // Alpha numeric
244
        $ns = preg_replace("/[^A-Za-z0-9\.\_\- ]/", '', $ns);
245
246
        return $ns;
247
    }
248
249
    /**
250
     * Gets or creates the file's namespace
251
     * @param $file
252
     * @return array with the namespace and fileobject
253
     */
254
    protected function getFilesNamespace($file)
255
    {
256
        $namespace = null;
1 ignored issue
show
Unused Code introduced by
$namespace is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
257
258
        if (is_array($file)) {
259
            // We are using a custom namespace
260
            $namespace = $this->sanitizeNamespace($file[1]);
261
            $file = $file[0];
262
            return [$namespace, $file];
263
264
        } else {
265
            // We are namespacing using the file's name
266
            $filename = rtrim($file->getBasename(), '.' . $file->getExtension());
267
            $namespace = $this->sanitizeNamespace($filename);
268
            return [$namespace, $file];
269
        }
270
    }
271
}
272