Passed
Push — master ( 95c09e...9b5291 )
by mon
01:37
created

AbstractMap::setValueAsDefault()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 9.2088
c 0
b 0
f 0
ccs 13
cts 13
cp 1
cc 5
nc 5
nop 3
crap 5
1
<?php
2
3
namespace FileEye\MimeMap\Map;
4
5
use FileEye\MimeMap\MappingException;
6
7
/**
8
 * Abstract class for mapping file extensions to MIME types.
9
 *
10
 * This class cannot be instantiated; extend from it to implement a map.
11
 */
12
abstract class AbstractMap
13
{
14
    /**
15
     * Returns the singleton.
16
     *
17
     * @return string
18
     */
19 29
    public static function getInstance()
20
    {
21 29
        if (!static::$instance) {
22 3
            static::$instance = new static();
23
        }
24 29
        return static::$instance;
25
    }
26
27
    /**
28
     * Returns this file's full qualified filename.
29
     *
30
     * @return string
31
     */
32 1
    public function getFileName()
33
    {
34 1
        throw new \LogicException(__METHOD__ . ' is not implemented in ' . get_called_class());
35
    }
36
37
    /**
38
     * Gets the map array.
39
     *
40
     * @return array
41
     */
42 3
    public function getMapArray()
43
    {
44 3
        return static::$map;
45
    }
46
47
    /**
48
     * Sorts the map.
49
     *
50
     * @return $this
51
     */
52 1
    public function sort()
53
    {
54 1
        ksort(static::$map['types']);
55 1
        ksort(static::$map['extensions']);
56 1
        return $this;
57
    }
58
59
    /**
60
     * Lists all the MIME types defined in the map.
61
     *
62
     * @param string $match (Optional) a match wildcard to limit the list.
63
     *
64
     * @return string[]
65
     */
66 6
    public function listTypes($match = null)
67
    {
68 6
        return $this->listEntries('types', $match);
69
    }
70
71
    /**
72
     * Lists all the extensions defined in the map.
73
     *
74
     * @param string $match (Optional) a match wildcard to limit the list.
75
     *
76
     * @return string[]
77
     */
78 2
    public function listExtensions($match = null)
79
    {
80 2
        return $this->listEntries('extensions', $match);
81
    }
82
83
    /**
84
     * Gets a list of entries of the map.
85
     *
86
     * @param string $key
87
     *   The main array key.
88
     * @param string $match
89
     *   (Optional) a match wildcard to limit the list.
90
     *
91
     * @return mixed|null
92
     *   The value of the entry, or null if missing.
93
     */
94 6
    protected function listEntries($key, $match = null)
95
    {
96 6
        $list = array_keys(static::$map[$key]);
97
98 6
        if (is_null($match)) {
99 2
            return $list;
100
        } else {
101 4
            $re = strtr($match, ['/' => '\\/', '*' => '.*']);
102
            return array_filter($list, function ($v) use ($re) {
103 4
                return preg_match("/$re/", $v) === 1;
104 4
            });
105
        }
106
    }
107
108
    /**
109
     * Determines if an entry exists form the 'types' array.
110
     *
111
     * @param string $type The type to be found.
112
     *
113
     * @return bool
114
     */
115 8
    public function hasType($type)
116
    {
117 8
        return (bool) $this->getType($type);
118
    }
119
120
    /**
121
     * Gets the content of an entry from the 'types' array.
122
     *
123
     * @param string $type The extension to be found.
124
     *
125
     * @return string[] The mapped file extensions.
126
     */
127 8
    public function getType($type)
128
    {
129 8
        $res = $this->getMapEntry('types', $type);
130 8
        return $res ?: [];
131
    }
132
133
    /**
134
     * Determines if an entry exists form the 'extensions' array.
135
     *
136
     * @param string $extension The extension to be found.
137
     *
138
     * @return bool
139
     */
140 1
    public function hasExtension($extension)
141
    {
142 1
        return (bool) $this->getExtension($extension);
143
    }
144
145
    /**
146
     * Gets the content of an entry from the 'extensions' array.
147
     *
148
     * @param string $extension The extension to be found.
149
     *
150
     * @return string[] The mapped MIME types.
151
     */
152 10
    public function getExtension($extension)
153
    {
154 10
        $res = $this->getMapEntry('extensions', $extension);
155 10
        return $res ?: [];
156
    }
157
158
    /**
159
     * Gets the content of an entry of the map.
160
     *
161
     * @param string $key
162
     *   The main array key.
163
     * @param string $entry
164
     *   The sub array key.
165
     *
166
     * @return mixed|null
167
     *   The value of the entry, or null if missing.
168
     */
169 16
    protected function getMapEntry($key, $entry)
170
    {
171 16
        return isset(static::$map[$key][$entry]) ? static::$map[$key][$entry] : null;
172
    }
173
174
    /**
175
     * Adds an entry to the map.
176
     *
177
     * Checks that no duplicate entries are made.
178
     *
179
     * @param string $key
180
     *   The main array key.
181
     * @param string $entry
182
     *   The sub array key.
183
     * @param string $value
184
     *   The value to add.
185
     *
186
     * @return $this
187
     */
188 4
    protected function addMapEntry($key, $entry, $value)
189
    {
190 4
        if (!isset(static::$map[$key][$entry])) {
191 4
            static::$map[$key][$entry] = [$value];
192
        } else {
193 3
            if (array_search($value, static::$map[$key][$entry]) === false) {
194 3
                static::$map[$key][$entry][] = $value;
195
            }
196
        }
197 4
        return $this;
198
    }
199
200
    /**
201
     * Removes an entry from the map.
202
     *
203
     * @param string $key
204
     *   The main array key.
205
     * @param string $entry
206
     *   The sub array key.
207
     * @param string $value
208
     *   The value.
209
     *
210
     * @return bool
211
     *   true if the entry was removed, false if the entry was not present.
212
     */
213 1
    protected function removeMapEntry($key, $entry, $value)
214
    {
215
        // Return false if no entry.
216 1
        if (!isset(static::$map[$key][$entry])) {
217 1
            return false;
218
        }
219
220
        // Return false if no value.
221 1
        $k = array_search($value, static::$map[$key][$entry]);
222 1
        if ($k === false) {
223 1
            return false;
224
        }
225
226
        // Remove the map entry.
227 1
        unset(static::$map[$key][$entry][$k]);
228
229
        // Remove the entry itself if no more values.
230 1
        if (empty(static::$map[$key][$entry])) {
231 1
            unset(static::$map[$key][$entry]);
232
        } else {
233
            // Resequence the remaining values.
234 1
            $tmp = [];
235 1
            foreach (static::$map[$key][$entry] as $v) {
236 1
                $tmp[] = $v;
237
            }
238 1
            static::$map[$key][$entry] = $tmp;
239
        }
240
241 1
        return true;
242
    }
243
244
    /**
245
     * Sets a value as the default for an entry.
246
     *
247
     * @param string $key
248
     *   The main array key.
249
     * @param string $entry
250
     *   The sub array key.
251
     * @param string $value
252
     *   The value.
253
     *
254
     * @throws MappingException if no mapping found.
255
     *
256
     * @return $this
257
     */
258 6
    protected function setValueAsDefault($key, $entry, $value)
259
    {
260
        // Throw exception if no entry.
261 6
        if (!isset(static::$map[$key][$entry])) {
262 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry}', '{$entry}' not defined");
263
        }
264
265
        // Throw exception if no entry-value pair.
266 4
        $k = array_search($value, static::$map[$key][$entry]);
267 4
        if ($k === false) {
268 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry}', '{$value}' not associated to '{$entry}'");
269
        }
270
271
        // Move value to top of array and resequence the rest.
272 2
        $tmp = [$value];
273 2
        foreach (static::$map[$key][$entry] as $kk => $v) {
274 2
            if ($kk === $k) {
275 2
                continue;
276
            }
277 2
            $tmp[] = $v;
278
        }
279 2
        static::$map[$key][$entry] = $tmp;
280
281 2
        return $this;
282
    }
283
284
    /**
285
     * Adds a type-to-extension mapping.
286
     *
287
     * @param string $type
288
     *   A MIME type.
289
     * @param string $extension
290
     *   A file extension.
291
     *
292
     * @return $this
293
     */
294 4
    public function addMapping($type, $extension)
295
    {
296 4
        $type = strtolower($type);
297 4
        $extension = (string) strtolower($extension);
298
299
        // Add entry to 'types'.
300 4
        $this->addMapEntry('types', $type, $extension);
301
302
        // Add entry to 'extensions'.
303 4
        $this->addMapEntry('extensions', $extension, $type);
304
305 4
        return $this;
306
    }
307
308
    /**
309
     * Removes a type-to-extension mapping.
310
     *
311
     * @param string $type
312
     *   A MIME type.
313
     * @param string $extension
314
     *   A file extension.
315
     *
316
     * @return bool
317
     *   true if the mapping was removed, false if the mapping was not present.
318
     */
319 1
    public function removeMapping($type, $extension)
320
    {
321 1
        $type = strtolower($type);
322 1
        $extension = (string) strtolower($extension);
323
324
        // Remove entry from 'types'.
325 1
        $type_ret = $this->removeMapEntry('types', $type, $extension);
326
327
        // Remove entry from 'extensions'.
328 1
        $extension_ret = $this->removeMapEntry('extensions', $extension, $type);
329
330 1
        return $type_ret && $extension_ret;
331
    }
332
333
    /**
334
     * Removes the entire mapping of a type.
335
     *
336
     * @param string $type
337
     *   A MIME type.
338
     *
339
     * @return bool
340
     *   true if the mapping was removed, false if the type was not present.
341
     */
342 1
    public function removeType($type)
343
    {
344 1
        $type = strtolower($type);
345
346
        // Return false if type is not found.
347 1
        if (!isset(static::$map['types'][$type])) {
348 1
            return false;
349
        }
350
351
        // Loop through all the associated extensions and remove them. This
352
        // is also removing the type itself when the last extension is removed.
353 1
        foreach (static::$map['types'][$type] as $extension) {
354 1
            $this->removeMapping($type, $extension);
355
        }
356
357 1
        return true;
358
    }
359
360
    /**
361
     * Changes the default extension for a MIME type.
362
     *
363
     * @param string $type
364
     *   A MIME type.
365
     * @param string $extension
366
     *   A file extension.
367
     *
368
     * @throws MappingException if no mapping found.
369
     *
370
     * @return $this
371
     */
372 3
    public function setTypeDefaultExtension($type, $extension)
373
    {
374 3
        $type = strtolower($type);
375 3
        $extension = (string) strtolower($extension);
376
377 3
        return $this->setValueAsDefault('types', $type, $extension);
378
    }
379
380
    /**
381
     * Changes the default MIME type for a file extension.
382
     *
383
     * @param string $extension
384
     *   A file extension.
385
     * @param string $type
386
     *   A MIME type.
387
     *
388
     * @throws MappingException if no mapping found.
389
     *
390
     * @return $this
391
     */
392 3
    public function setExtensionDefaultType($extension, $type)
393
    {
394 3
        $type = strtolower($type);
395 3
        $extension = (string) strtolower($extension);
396
397 3
        return $this->setValueAsDefault('extensions', $extension, $type);
398
    }
399
}
400