Passed
Pull Request — master (#15)
by mon
03:05
created

AbstractMap::addTypeDescription()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 6
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 32
    public static function getInstance()
20
    {
21 32
        if (!static::$instance) {
22 3
            static::$instance = new static();
0 ignored issues
show
Bug Best Practice introduced by
The property instance does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
23
        }
24 32
        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
            foreach (static::$map[$k] as &$sub) {
57 6
                ksort($sub);
58 4
            }
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 7
    public function hasType($type)
71
    {
72 7
        return (bool) $this->getMapEntry('t', $type);
73
    }
74
75
    /**
76
     * Determines if a MIME type alias exists.
77
     *
78
     * @param string $alias The alias to be found.
79
     *
80
     * @return bool
81
     */
82 3
    public function hasAlias($alias)
83
    {
84 3
        return (bool) $this->getMapEntry('a', $alias);
85
    }
86
87
    /**
88
     * Determines if an entry exists from the 'extensions' array.
89
     *
90
     * @param string $extension The extension to be found.
91
     *
92
     * @return bool
93
     */
94
    public function hasExtension($extension)
95
    {
96
        return (bool) $this->getMapEntry('e', $extension);
97
    }
98 7
99
    /**
100 7
     * Lists all the MIME types defined in the map.
101
     *
102 7
     * @param string $match (Optional) a match wildcard to limit the list.
103 3
     *
104
     * @return string[]
105 4
     */
106
    public function listTypes($match = null)
107 4
    {
108 4
        return $this->listEntries('t', $match);
109
    }
110
111
    /**
112
     * Lists all the MIME types aliases defined in the map.
113
     *
114
     * @param string $match (Optional) a match wildcard to limit the list.
115
     *
116
     * @return string[]
117
     */
118
    public function listAliases($match = null)
119 8
    {
120
        return $this->listEntries('a', $match);
121 8
    }
122
123
    /**
124
     * Lists all the extensions defined in the map.
125
     *
126
     * @param string $match (Optional) a match wildcard to limit the list.
127
     *
128
     * @return string[]
129
     */
130
    public function listExtensions($match = null)
131 8
    {
132
        return $this->listEntries('e', $match);
133 8
    }
134 8
135
    /**
136
     * Adds a description of a MIME type.
137
     *
138
     * @param string $type
139
     *   A MIME type.
140
     * @param string $description
141
     *   The description of the MIME type.
142
     *
143
     * @throws MappingException if $type is an alias.
144 1
     *
145
     * @return $this
146 1
     */
147
    public function addTypeDescription($type, $description)
148
    {
149
        // Consistency checks.
150
        if ($this->hasAlias($type)) {
151
            throw new MappingException("Cannot add description for '{$type}', '{$type}' is an alias");
152
        }
153
154
        $this->addMapSubEntry('t', $type, 'desc', $description);
155
        return $this;
156 10
    }
157
158 10
    /**
159 10
     * Adds an alias of a MIME type.
160
     *
161
     * @param string $type
162
     *   A MIME type.
163
     * @param string $alias
164
     *   An alias of $type.
165
     *
166
     * @throws MappingException if no $type is found.
167
     *
168
     * @return $this
169
     */
170
    public function addTypeAlias($type, $alias)
171
    {
172
        $type = strtolower($type);
173 16
        $alias = strtolower($alias);
174
175 16
        // Consistency checks.
176
        if (!$this->hasType($type)) {
177
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$type}' not defined");
178
        }
179
        if ($this->hasType($alias)) {
180
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$alias}' is already defined as a type");
181
        }
182
183
        $this->addMapSubEntry('t', $type, 'a', $alias);
184
        $this->addMapSubEntry('a', $alias, 't', $type);
185
        return $this;
186
    }
187
188
    /**
189
     * Adds a type-to-extension mapping.
190
     *
191
     * @param string $type
192 5
     *   A MIME type.
193
     * @param string $extension
194 5
     *   A file extension.
195 5
     *
196
     * @throws MappingException if $type is an alias.
197 4
     *
198 4
     * @return $this
199
     */
200
    public function addTypeExtensionMapping($type, $extension)
201 5
    {
202
        $type = strtolower($type);
203
        $extension = strtolower($extension);
204
205
        // Consistency checks.
206
        if ($this->hasAlias($type)) {
207
            throw new MappingException("Cannot map '{$extension}' to '{$type}', '{$type}' is an alias");
208
        }
209
210
        // Add entry to 't'.
211
        $this->addMapSubEntry('t', $type, 'e', $extension);
212
213
        // Add entry to 'e'.
214
        $this->addMapSubEntry('e', $extension, 't', $type);
215
216
        return $this;
217 1
    }
218
219
    /**
220 1
     * Gets the descriptions of a MIME type.
221 1
     *
222
     * @param string $type The type to be found.
223
     *
224
     * @return string[] The mapped descriptions.
225 1
     */
226 1
    public function getTypeDescriptions($type)
227 1
    {
228
        $res = $this->getMapSubEntry('t', $type, 'desc');
229
        return $res ?: [];
230
    }
231 1
232
    /**
233
     * Gets the aliases of a MIME type.
234 1
     *
235 1
     * @param string $type The type to be found.
236
     *
237
     * @return string[] The mapped aliases.
238 1
     */
239 1
    public function getTypeAliases($type)
240 1
    {
241
        $res = $this->getMapSubEntry('t', $type, 'a');
242 1
        return $res ?: [];
243
    }
244
245 1
    /**
246
     * Gets the content of an entry from the 't' array.
247
     *
248
     * @param string $type The type to be found.
249
     *
250
     * @return string[] The mapped file extensions.
251
     */
252
    public function getTypeExtensions($type)
253
    {
254
        $res = $this->getMapSubEntry('t', $type, 'e');
255
        return $res ?: [];
256
    }
257
258
    /**
259
     * Changes the default extension for a MIME type.
260
     *
261
     * @param string $type
262 6
     *   A MIME type.
263
     * @param string $extension
264
     *   A file extension.
265 6
     *
266 2
     * @throws MappingException if no mapping found.
267
     *
268
     * @return $this
269
     */
270 4
    public function setTypeDefaultExtension($type, $extension)
271 4
    {
272 2
        return $this->setValueAsDefault('t', $type, 'e', $extension);
273
    }
274
275
    /**
276 2
     * Removes the entire mapping of a type.
277 2
     *
278 2
     * @param string $type
279 2
     *   A MIME type.
280
     *
281 2
     * @return bool
282
     *   true if the mapping was removed, false if the type was not present.
283 2
     */
284
    public function removeType($type)
285 2
    {
286
        $type = strtolower($type);
287
288
        // Return false if type is not found.
289
        if (!$this->hasType($type)) {
290
            return false;
291
        }
292
293
        // Loop through all the associated extensions and remove them.
294
        foreach ($this->getTypeExtensions($type) as $extension) {
295
            $this->removeTypeExtensionMapping($type, $extension);
296
        }
297
298 5
        // Loop through all the associated aliases and remove them.
299
        foreach ($this->getTypeAliases($type) as $alias) {
300 5
            $this->removeTypeAlias($type, $alias);
301 5
        }
302
303
        unset(static::$map['t'][$type]);
304 5
305
        return true;
306
    }
307 5
308
    /**
309 5
     * Removes a MIME type alias.
310
     *
311
     * @param string $type
312
     *   A MIME type.
313
     * @param string $alias
314
     *   The alias to be removed.
315
     *
316
     * @return bool
317
     *   true if the alias was removed, false if the alias was not present.
318
     */
319
    public function removeTypeAlias($type, $alias)
320
    {
321
        $type = strtolower($type);
322
        $alias = strtolower($alias);
323 1
324
        $type_ret = $this->removeMapSubEntry('t', $type, 'a', $alias);
325 1
        $alias_ret = $this->removeMapSubEntry('a', $alias, 't', $type);
326 1
327
        return $type_ret && $alias_ret;
328
    }
329 1
330
    /**
331
     * Removes a type-to-extension mapping.
332 1
     *
333
     * @param string $type
334 1
     *   A MIME type.
335
     * @param string $extension
336
     *   The file extension to be removed.
337
     *
338
     * @return bool
339
     *   true if the mapping was removed, false if the mapping was not present.
340
     */
341
    public function removeTypeExtensionMapping($type, $extension)
342
    {
343
        $type = strtolower($type);
344
        $extension = strtolower($extension);
345
346 1
        $type_ret = $this->removeMapSubEntry('t', $type, 'e', $extension);
347
        $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $type);
348 1
349
        return $type_ret && $extension_ret;
350
    }
351 1
352 1
    /**
353
     * Gets the parent types of an alias.
354
     *
355
     * @param string $alias The alias to be found.
356
     *
357 1
     * @return string[]
358 1
     */
359
    public function getAliasTypes($alias)
0 ignored issues
show
Unused Code introduced by
The parameter $alias is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

359
    public function getAliasTypes(/** @scrutinizer ignore-unused */ $alias)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
360
    {
361 1
        $res = $this->getMapSubEntry('a', $extension, 't');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $extension seems to be never defined.
Loading history...
362
        return $res ?: [];
363
    }
364
365
    /**
366
     * Gets the content of an entry from the 'extensions' array.
367
     *
368
     * @param string $extension The extension to be found.
369
     *
370
     * @return string[] The mapped MIME types.
371
     */
372
    public function getExtensionTypes($extension)
373
    {
374
        $res = $this->getMapSubEntry('e', $extension, 't');
375
        return $res ?: [];
376 3
    }
377
378 3
    /**
379 3
     * Changes the default MIME type for a file extension.
380
     *
381 3
     * @param string $extension
382
     *   A file extension.
383
     * @param string $type
384
     *   A MIME type.
385
     *
386
     * @throws MappingException if no mapping found.
387
     *
388
     * @return $this
389
     */
390
    public function setExtensionDefaultType($extension, $type)
391
    {
392
        return $this->setValueAsDefault('e', $extension, 't', $type);
393
    }
394
395
    /**
396 3
     * Gets a list of entries of the map.
397
     *
398 3
     * @param string $entry
399 3
     *   The main array entry.
400
     * @param string $match
401 3
     *   (Optional) a match wildcard to limit the list.
402
     *
403
     * @return array
404
     *   The list of the entries.
405
     */
406
    protected function listEntries($entry, $match = null)
407
    {
408
        $entry = strtolower($entry);
409
410
        if (!isset(static::$map[$entry])) {
411
            return [];
412
        }
413
414
        $list = array_keys(static::$map[$entry]);
415
416
        if (is_null($match)) {
417
            return $list;
418
        } else {
419
            $re = strtr($match, ['/' => '\\/', '*' => '.*']);
420
            return array_filter($list, function ($v) use ($re) {
421
                return preg_match("/$re/", $v) === 1;
422
            });
423
        }
424
    }
425
426
    /**
427
     * Gets the content of an entry of the map.
428
     *
429
     * @param string $entry
430
     *   The main array entry.
431
     * @param string $entry_key
432
     *   The main entry value.
433
     *
434
     * @return mixed|null
435
     *   The value of the entry, or null if missing.
436
     */
437
    protected function getMapEntry($entry, $entry_key)
438
    {
439
        $entry = strtolower($entry);
440
        $entry_key = strtolower($entry_key);
441
        return isset(static::$map[$entry][$entry_key]) ? static::$map[$entry][$entry_key] : null;
442
    }
443
444
    /**
445
     * Gets the content of a subentry of the map.
446
     *
447
     * @param string $entry
448
     *   The main array entry.
449
     * @param string $entry_key
450
     *   The main entry value.
451
     * @param string $sub_entry
452
     *   The sub entry.
453
     *
454
     * @return mixed|null
455
     *   The value of the entry, or null if missing.
456
     */
457
    protected function getMapSubEntry($entry, $entry_key, $sub_entry)
458
    {
459
        $entry = strtolower($entry);
460
        $entry_key = strtolower($entry_key);
461
        $sub_entry = strtolower($sub_entry);
462
        return isset(static::$map[$entry][$entry_key][$sub_entry]) ? static::$map[$entry][$entry_key][$sub_entry] : null;
463
    }
464
465
    /**
466
     * Adds an entry to the map.
467
     *
468
     * Checks that no duplicate entries are made.
469
     *
470
     * @param string $entry
471
     *   The main array entry.
472
     * @param string $entry_key
473
     *   The main entry value.
474
     * @param string $sub_entry
475
     *   The sub entry.
476
     * @param string $value
477
     *   The value to add.
478
     *
479
     * @return $this
480
     */
481
    protected function addMapSubEntry($entry, $entry_key, $sub_entry, $value)
482
    {
483
        $entry = strtolower($entry);
484
        $entry_key = strtolower($entry_key);
485
        $sub_entry = strtolower($sub_entry);
486
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
487
            static::$map[$entry][$entry_key][$sub_entry] = [$value];
0 ignored issues
show
Bug Best Practice introduced by
The property map does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
488
        } else {
489
            if (array_search($value, static::$map[$entry][$entry_key][$sub_entry]) === false) {
490
                static::$map[$entry][$entry_key][$sub_entry][] = $value;
491
            }
492
        }
493
        return $this;
494
    }
495
496
    /**
497
     * Removes an entry from the map.
498
     *
499
     * @param string $entry
500
     *   The main array entry.
501
     * @param string $entry_key
502
     *   The main entry value.
503
     * @param string $sub_entry
504
     *   The sub entry.
505
     * @param string $value
506
     *   The value to remove.
507
     *
508
     * @return bool
509
     *   true if the entry was removed, false if the entry was not present.
510
     */
511
    protected function removeMapSubEntry($entry, $entry_key, $sub_entry, $value)
512
    {
513
        $entry = strtolower($entry);
514
        $entry_key = strtolower($entry_key);
515
        $sub_entry = strtolower($sub_entry);
516
517
        // Return false if no entry.
518
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
519
            return false;
520
        }
521
522
        // Return false if no value.
523
        $k = array_search($value, static::$map[$entry][$entry_key][$sub_entry]);
524
        if ($k === false) {
525
            return false;
526
        }
527
528
        // Remove the map entry.
529
        unset(static::$map[$entry][$entry_key][$sub_entry][$k]);
530
531
        // Remove the entry itself if no more values.
532
        if (empty(static::$map[$entry][$entry_key][$sub_entry])) {
533
            unset(static::$map[$entry][$entry_key][$sub_entry]);
534
        } else {
535
            // Resequence the remaining values.
536
            $tmp = [];
537
            foreach (static::$map[$entry][$entry_key][$sub_entry] as $v) {
538
                $tmp[] = $v;
539
            }
540
            static::$map[$entry][$entry_key][$sub_entry] = $tmp;
0 ignored issues
show
Bug Best Practice introduced by
The property map does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
541
        }
542
543
        return true;
544
    }
545
546
    /**
547
     * Sets a value as the default for an entry.
548
     *
549
     * @param string $entry
550
     *   The main array entry.
551
     * @param string $entry_key
552
     *   The main entry value.
553
     * @param string $sub_entry
554
     *   The sub entry.
555
     * @param string $value
556
     *   The value to add.
557
     *
558
     * @throws MappingException if no mapping found.
559
     *
560
     * @return $this
561
     */
562
    protected function setValueAsDefault($entry, $entry_key, $sub_entry, $value)
563
    {
564
        $entry = strtolower($entry);
565
        $entry_key = strtolower($entry_key);
566
        $sub_entry = strtolower($sub_entry);
567
568
        // Throw exception if no entry.
569
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
570
            throw new MappingException("Cannot set '{$value}' as default for '{$entry_key}', '{$entry_key}' not defined");
571
        }
572
573
        // Throw exception if no entry-value pair.
574
        $k = array_search($value, static::$map[$entry][$entry_key][$sub_entry]);
575
        if ($k === false) {
576
            throw new MappingException("Cannot set '{$value}' as default for '{$entry_key}', '{$value}' not associated to '{$entry_key}'");
577
        }
578
579
        // Move value to top of array and resequence the rest.
580
        $tmp = [$value];
581
        foreach (static::$map[$entry][$entry_key][$sub_entry] as $kk => $v) {
582
            if ($kk === $k) {
583
                continue;
584
            }
585
            $tmp[] = $v;
586
        }
587
        static::$map[$entry][$entry_key][$sub_entry] = $tmp;
0 ignored issues
show
Bug Best Practice introduced by
The property map does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
588
589
        return $this;
590
    }
591
}
592