Test Failed
Pull Request — master (#15)
by mon
02:54
created

AbstractMap::getMapArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 0
crap 1
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 33
    public static function getInstance()
20
    {
21 33
        if (!static::$instance) {
22 3
            static::$instance = new static();
23
        }
24 33
        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 5
    public function getMapArray()
43
    {
44 5
        return static::$map;
45
    }
46
47
    /**
48
     * Sorts the map.
49
     *
50
     * @return $this
51
     */
52 6
    public function sort()
53
    {
54 6
        foreach (array_keys(static::$map) as $k) {
55 4
            ksort(static::$map[$k]);
56 4
            foreach (static::$map[$k] as &$sub) {
57 4
                ksort($sub);
58
            }
59
        }
60 6
        return $this;
61
    }
62
63
    /**
64
     * Determines if a MIME type exists.
65
     *
66
     * @param string $type The type to be found.
67
     *
68
     * @return bool
69
     */
70 9
    public function hasType($type)
71
    {
72
        // xx manage aliases
73 9
        return (bool) $this->getMapEntry('t', $type);
74
    }
75
76
    /**
77
     * Determines if a MIME type alias exists.
78
     *
79
     * @param string $alias The alias to be found.
80
     *
81
     * @return bool
82
     */
83 6
    public function hasAlias($alias)
84
    {
85 6
        return (bool) $this->getMapEntry('a', $alias);
86
    }
87
88
    /**
89
     * Determines if an entry exists from the 'extensions' array.
90
     *
91
     * @param string $extension The extension to be found.
92
     *
93
     * @return bool
94
     */
95 1
    public function hasExtension($extension)
96
    {
97 1
        return (bool) $this->getMapEntry('e', $extension);
98
    }
99
100
    /**
101
     * Lists all the MIME types defined in the map.
102
     *
103
     * @param string $match (Optional) a match wildcard to limit the list.
104
     *
105
     * @return string[]
106
     */
107 7
    public function listTypes($match = null)
108
    {
109
        // xx manage aliases
110 7
        return $this->listEntries('t', $match);
111
    }
112
113
    /**
114
     * Lists all the MIME types aliases defined in the map.
115
     *
116
     * @param string $match (Optional) a match wildcard to limit the list.
117
     *
118
     * @return string[]
119
     */
120 2
    public function listAliases($match = null)
121
    {
122 2
        return $this->listEntries('a', $match);
123
    }
124
125
    /**
126
     * Lists all the extensions defined in the map.
127
     *
128
     * @param string $match (Optional) a match wildcard to limit the list.
129
     *
130
     * @return string[]
131
     */
132 3
    public function listExtensions($match = null)
133
    {
134 3
        return $this->listEntries('e', $match);
135
    }
136
137
    /**
138
     * Adds a description of a MIME type.
139
     *
140
     * @param string $type
141
     *   A MIME type.
142
     * @param string $description
143
     *   The description of the MIME type.
144
     *
145
     * @throws MappingException if $type is an alias.
146
     *
147
     * @return $this
148
     */
149 1
    public function addTypeDescription($type, $description)
150
    {
151
        // Consistency checks.
152 1
        if ($this->hasAlias($type)) {
153
            throw new MappingException("Cannot add description for '{$type}', '{$type}' is an alias");
154
        }
155
156 1
        $this->addMapSubEntry('t', $type, 'desc', $description);
157 1
        return $this;
158
    }
159
160
    /**
161
     * Adds an alias of a MIME type.
162
     *
163
     * @param string $type
164
     *   A MIME type.
165
     * @param string $alias
166
     *   An alias of $type.
167
     *
168
     * @throws MappingException if no $type is found.
169
     *
170
     * @return $this
171
     */
172 1
    public function addTypeAlias($type, $alias)
173
    {
174 1
        $type = strtolower($type);
175 1
        $alias = strtolower($alias);
176
177
        // Consistency checks.
178 1
        if (!$this->hasType($type)) {
179
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$type}' not defined");
180
        }
181 1
        if ($this->hasType($alias)) {
182
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$alias}' is already defined as a type");
183
        }
184
185 1
        $this->addMapSubEntry('t', $type, 'a', $alias);
186 1
        $this->addMapSubEntry('a', $alias, 't', $type);
187 1
        return $this;
188
    }
189
190
    /**
191
     * Adds a type-to-extension mapping.
192
     *
193
     * @param string $type
194
     *   A MIME type.
195
     * @param string $extension
196
     *   A file extension.
197
     *
198
     * @throws MappingException if $type is an alias.
199
     *
200
     * @return $this
201
     */
202 5
    public function addTypeExtensionMapping($type, $extension)
203
    {
204 5
        $type = strtolower($type);
205 5
        $extension = strtolower($extension);
206
207
        // Consistency checks.
208 5
        if ($this->hasAlias($type)) {
209
            throw new MappingException("Cannot map '{$extension}' to '{$type}', '{$type}' is an alias");
210
        }
211
212
        // Add entry to 't'.
213 5
        $this->addMapSubEntry('t', $type, 'e', $extension);
214
215
        // Add entry to 'e'.
216 5
        $this->addMapSubEntry('e', $extension, 't', $type);
217
218 5
        return $this;
219
    }
220
221
    /**
222
     * Gets the aliases of a MIME type.
223
     *
224
     * @param string $type The type to be found.
225
     *
226
     * @return string[] The mapped aliases.
227
     */
228 1
    public function getTypeAliases($type)
229
    {
230 1
        $res = $this->getMapSubEntry('t', $type, 'a');
231 1
        return $res ?: [];
232
    }
233
234
    /**
235
     * Gets the content of an entry from the 't' array.
236
     *
237
     * @param string $type The type to be found.
238
     *
239
     * @return string[] The mapped file extensions.
240
     */
241 5
    public function getTypeExtensions($type)
242
    {
243
        // xx manage aliases
244 5
        $res = $this->getMapSubEntry('t', $type, 'e');
245 5
        return $res ?: [];
246
    }
247
248
    /**
249
     * Changes the default extension for a MIME type.
250
     *
251
     * @param string $type
252
     *   A MIME type.
253
     * @param string $extension
254
     *   A file extension.
255
     *
256
     * @throws MappingException if no mapping found.
257
     *
258
     * @return $this
259
     */
260 3
    public function setTypeDefaultExtension($type, $extension)
261
    {
262 3
        return $this->setValueAsDefault('t', $type, 'e', $extension);
263
    }
264
265
    /**
266
     * Removes the entire mapping of a type.
267
     *
268
     * @param string $type
269
     *   A MIME type.
270
     *
271
     * @return bool
272
     *   true if the mapping was removed, false if the type was not present.
273
     */
274 1
    public function removeType($type)
275
    {
276 1
        $type = strtolower($type);
277
278
        // Return false if type is not found.
279 1
        if (!$this->hasType($type)) {
280 1
            return false;
281
        }
282
283
        // Loop through all the associated extensions and remove them.
284 1
        foreach ($this->getTypeExtensions($type) as $extension) {
285 1
            $this->removeTypeExtensionMapping($type, $extension);
286
        }
287
288
        // Loop through all the associated aliases and remove them.
289 1
        foreach ($this->getTypeAliases($type) as $alias) {
290
            $this->removeTypeAlias($type, $alias);
291
        }
292
        
293 1
        return $this->removeMapEntry('t', $type);
294
    }
295
296
    /**
297
     * Removes a MIME type alias.
298
     *
299
     * @param string $type
300
     *   A MIME type.
301
     * @param string $alias
302
     *   The alias to be removed.
303
     *
304
     * @return bool
305
     *   true if the alias was removed, false if the alias was not present.
306
     */
307 1
    public function removeTypeAlias($type, $alias)
308
    {
309 1
        $type = strtolower($type);
310 1
        $alias = strtolower($alias);
311
312 1
        $type_ret = $this->removeMapSubEntry('t', $type, 'a', $alias);
313 1
        $alias_ret = $this->removeMapSubEntry('a', $alias, 't', $type);
314
315 1
        return $type_ret && $alias_ret;
316
    }
317
318
    /**
319
     * Removes a type-to-extension mapping.
320
     *
321
     * @param string $type
322
     *   A MIME type.
323
     * @param string $extension
324
     *   The file extension to be removed.
325
     *
326
     * @return bool
327
     *   true if the mapping was removed, false if the mapping was not present.
328
     */
329 1
    public function removeTypeExtensionMapping($type, $extension)
330
    {
331 1
        $type = strtolower($type);
332 1
        $extension = strtolower($extension);
333
334 1
        $type_ret = $this->removeMapSubEntry('t', $type, 'e', $extension);
335 1
        $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $type);
336
337 1
        return $type_ret && $extension_ret;
338
    }
339
340
    /**
341
     * Gets the content of an entry from the 'extensions' array.
342
     *
343
     * @param string $extension The extension to be found.
344
     *
345
     * @return string[] The mapped MIME types.
346
     */
347 9
    public function getExtensionTypes($extension)
348
    {
349 9
        $res = $this->getMapSubEntry('e', $extension, 't');
350 9
        return $res ?: [];
351
    }
352
353
    /**
354
     * Changes the default MIME type for a file extension.
355
     *
356
     * @param string $extension
357
     *   A file extension.
358
     * @param string $type
359
     *   A MIME type.
360
     *
361
     * @throws MappingException if no mapping found.
362
     *
363
     * @return $this
364
     */
365 3
    public function setExtensionDefaultType($extension, $type)
366
    {
367 3
        return $this->setValueAsDefault('e', $extension, 't', $type);
368
    }
369
370
    /**
371
     * Gets a list of entries of the map.
372
     *
373
     * @param string $entry
374
     *   The main array entry.
375
     * @param string $match
376
     *   (Optional) a match wildcard to limit the list.
377
     *
378
     * @return mixed|null
379
     *   The value of the entry, or null if missing.
380
     */
381 7
    protected function listEntries($entry, $match = null)
382
    {
383 7
        $entry = strtolower($entry);
384 7
        $list = array_keys(static::$map[$entry]);
385
386 7
        if (is_null($match)) {
387 3
            return $list;
388
        } else {
389 4
            $re = strtr($match, ['/' => '\\/', '*' => '.*']);
390
            return array_filter($list, function ($v) use ($re) {
391 4
                return preg_match("/$re/", $v) === 1;
392 4
            });
393
        }
394
    }
395
396
    /**
397
     * Gets the content of an entry of the map.
398
     *
399
     * @param string $entry
400
     *   The main array entry.
401
     * @param string $entry_key
402
     *   The main entry value.
403
     *
404
     * @return mixed|null
405
     *   The value of the entry, or null if missing.
406
     */
407 14
    protected function getMapEntry($entry, $entry_key)
408
    {
409 14
        $entry = strtolower($entry);
410 14
        $entry_key = strtolower($entry_key);
411 14
        return isset(static::$map[$entry][$entry_key]) ? static::$map[$entry][$entry_key] : null;
412
    }
413
414
    /**
415
     * Removes an entry from the map.
416
     *
417
     * @param string $entry
418
     *   The main array entry.
419
     * @param string $entry_key
420
     *   The main entry value.
421
     *
422
     * @return bool
423
     *   true if the entry was removed, false if the entry was not present.
424
     */
425 1
    protected function removeMapEntry($entry, $entry_key)
426
    {
427 1
        $entry = strtolower($entry);
428 1
        $entry_key = strtolower($entry_key);
429
430
        // Return false if no entry.
431 1
        if (!isset(static::$map[$entry][$entry_key])) {
432
            return false;
433
        }
434
435
        // Remove the map entry.
436 1
        unset(static::$map[$entry][$entry_key]);
437
438 1
        return true;
439
    }
440
441
    /**
442
     * Gets the content of a subentry of the map.
443
     *
444
     * @param string $entry
445
     *   The main array entry.
446
     * @param string $entry_key
447
     *   The main entry value.
448
     * @param string $sub_entry
449
     *   The sub entry.
450
     *
451
     * @return mixed|null
452
     *   The value of the entry, or null if missing.
453
     */
454 12
    protected function getMapSubEntry($entry, $entry_key, $sub_entry)
455
    {
456 12
        $entry = strtolower($entry);
457 12
        $entry_key = strtolower($entry_key);
458 12
        $sub_entry = strtolower($sub_entry);
459 12
        return isset(static::$map[$entry][$entry_key][$sub_entry]) ? static::$map[$entry][$entry_key][$sub_entry] : null;
460
    }
461
462
    /**
463
     * Adds an entry to the map.
464
     *
465
     * Checks that no duplicate entries are made.
466
     *
467
     * @param string $entry
468
     *   The main array entry.
469
     * @param string $entry_key
470
     *   The main entry value.
471
     * @param string $sub_entry
472
     *   The sub entry.
473
     * @param string $value
474
     *   The value to add.
475
     *
476
     * @return $this
477
     */
478 5
    protected function addMapSubEntry($entry, $entry_key, $sub_entry, $value)
479
    {
480 5
        $entry = strtolower($entry);
481 5
        $entry_key = strtolower($entry_key);
482 5
        $sub_entry = strtolower($sub_entry);
483 5
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
484 5
            static::$map[$entry][$entry_key][$sub_entry] = [$value];
485
        } else {
486 4
            if (array_search($value, static::$map[$entry][$entry_key][$sub_entry]) === false) {
487 4
                static::$map[$entry][$entry_key][$sub_entry][] = $value;
488
            }
489
        }
490 5
        return $this;
491
    }
492
493
    /**
494
     * Removes an entry from the map.
495
     *
496
     * @param string $entry
497
     *   The main array entry.
498
     * @param string $entry_key
499
     *   The main entry value.
500
     * @param string $sub_entry
501
     *   The sub entry.
502
     * @param string $value
503
     *   The value to remove.
504
     *
505
     * @return bool
506
     *   true if the entry was removed, false if the entry was not present.
507
     */
508 1
    protected function removeMapSubEntry($entry, $entry_key, $sub_entry, $value)
509
    {
510 1
        $entry = strtolower($entry);
511 1
        $entry_key = strtolower($entry_key);
512 1
        $sub_entry = strtolower($sub_entry);
513
514
        // Return false if no entry.
515 1
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
516 1
            return false;
517
        }
518
519
        // Return false if no value.
520 1
        $k = array_search($value, static::$map[$entry][$entry_key][$sub_entry]);
521 1
        if ($k === false) {
522 1
            return false;
523
        }
524
525
        // Remove the map entry.
526 1
        unset(static::$map[$entry][$entry_key][$sub_entry][$k]);
527
528
        // Remove the entry itself if no more values.
529 1
        if (empty(static::$map[$entry][$entry_key][$sub_entry])) {
530 1
            unset(static::$map[$entry][$entry_key][$sub_entry]);
531
        } else {
532
            // Resequence the remaining values.
533 1
            $tmp = [];
534 1
            foreach (static::$map[$entry][$entry_key][$sub_entry] as $v) {
535 1
                $tmp[] = $v;
536
            }
537 1
            static::$map[$entry][$entry_key][$sub_entry] = $tmp;
538
        }
539
540 1
        return true;
541
    }
542
543
    /**
544
     * Sets a value as the default for an entry.
545
     *
546
     * @param string $entry
547
     *   The main array entry.
548
     * @param string $entry_key
549
     *   The main entry value.
550
     * @param string $sub_entry
551
     *   The sub entry.
552
     * @param string $value
553
     *   The value to add.
554
     *
555
     * @throws MappingException if no mapping found.
556
     *
557
     * @return $this
558
     */
559 6
    protected function setValueAsDefault($entry, $entry_key, $sub_entry, $value)
560
    {
561 6
        $entry = strtolower($entry);
562 6
        $entry_key = strtolower($entry_key);
563 6
        $sub_entry = strtolower($sub_entry);
564
565
        // Throw exception if no entry.
566 6
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
567 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry_key}', '{$entry_key}' not defined");
568
        }
569
570
        // Throw exception if no entry-value pair.
571 4
        $k = array_search($value, static::$map[$entry][$entry_key][$sub_entry]);
572 4
        if ($k === false) {
573 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry_key}', '{$value}' not associated to '{$entry_key}'");
574
        }
575
576
        // Move value to top of array and resequence the rest.
577 2
        $tmp = [$value];
578 2
        foreach (static::$map[$entry][$entry_key][$sub_entry] as $kk => $v) {
579 2
            if ($kk === $k) {
580 2
                continue;
581
            }
582 2
            $tmp[] = $v;
583
        }
584 2
        static::$map[$entry][$entry_key][$sub_entry] = $tmp;
585
586 2
        return $this;
587
    }
588
}
589