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

AbstractMap::hasType()   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 1
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 27
    public static function getInstance()
20
    {
21 27
        if (!static::$instance) {
22 3
            static::$instance = new static();
23
        }
24 27
        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 4
    public function hasType($type)
71
    {
72 4
        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 7
    public function hasAlias($alias)
83
    {
84 7
        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 1
    public function hasExtension($extension)
95
    {
96 1
        return (bool) $this->getMapEntry('e', $extension);
97
    }
98
99
    /**
100
     * Lists all the MIME types defined in the map.
101
     *
102
     * @param string $match (Optional) a match wildcard to limit the list.
103
     *
104
     * @return string[]
105
     */
106 3
    public function listTypes($match = null)
107
    {
108 3
        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 2
    public function listAliases($match = null)
119
    {
120 2
        return $this->listEntries('a', $match);
121
    }
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 3
    public function listExtensions($match = null)
131
    {
132 3
        return $this->listEntries('e', $match);
133
    }
134
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
     *
145
     * @return $this
146
     */
147 2
    public function addTypeDescription($type, $description)
148
    {
149
        // Consistency checks.
150 2
        if ($this->hasAlias($type)) {
151 1
            throw new MappingException("Cannot add description for '{$type}', '{$type}' is an alias");
152
        }
153
154 1
        $this->addMapSubEntry('t', $type, 'desc', $description);
155 1
        return $this;
156
    }
157
158
    /**
159
     * 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 3
    public function addTypeAlias($type, $alias)
171
    {
172 3
        $type = strtolower($type);
173 3
        $alias = strtolower($alias);
174
175
        // Consistency checks.
176 3
        if (!$this->hasType($type)) {
177 1
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$type}' not defined");
178
        }
179 2
        if ($this->hasType($alias)) {
180 2
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$alias}' is already defined as a type");
181
        }
182
183 1
        $this->addMapSubEntry('t', $type, 'a', $alias);
184 1
        $this->addMapSubEntry('a', $alias, 't', $type);
185 1
        return $this;
186
    }
187
188
    /**
189
     * Adds a type-to-extension mapping.
190
     *
191
     * @param string $type
192
     *   A MIME type.
193
     * @param string $extension
194
     *   A file extension.
195
     *
196
     * @throws MappingException if $type is an alias.
197
     *
198
     * @return $this
199
     */
200 5
    public function addTypeExtensionMapping($type, $extension)
201
    {
202 5
        $type = strtolower($type);
203 5
        $extension = strtolower($extension);
204
205
        // Consistency checks.
206 5
        if ($this->hasAlias($type)) {
207 1
            throw new MappingException("Cannot map '{$extension}' to '{$type}', '{$type}' is an alias");
208
        }
209
210
        // Add entry to 't'.
211 4
        $this->addMapSubEntry('t', $type, 'e', $extension);
212
213
        // Add entry to 'e'.
214 4
        $this->addMapSubEntry('e', $extension, 't', $type);
215
216 4
        return $this;
217
    }
218
219
    /**
220
     * Gets the descriptions of a MIME type.
221
     *
222
     * @param string $type The type to be found.
223
     *
224
     * @return string[] The mapped descriptions.
225
     */
226
    public function getTypeDescriptions($type)
227
    {
228
        $res = $this->getMapSubEntry('t', $type, 'desc');
229
        return $res ?: [];
230
    }
231
232
    /**
233
     * Gets the aliases of a MIME type.
234
     *
235
     * @param string $type The type to be found.
236
     *
237
     * @return string[] The mapped aliases.
238
     */
239
    public function getTypeAliases($type)
240
    {
241
        $res = $this->getMapSubEntry('t', $type, 'a');
242
        return $res ?: [];
243
    }
244
245
    /**
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
     *   A MIME type.
263
     * @param string $extension
264
     *   A file extension.
265
     *
266
     * @throws MappingException if no mapping found.
267
     *
268
     * @return $this
269
     */
270 2
    public function setTypeDefaultExtension($type, $extension)
271
    {
272 2
        return $this->setValueAsDefault('t', $type, 'e', $extension);
273
    }
274
275
    /**
276
     * Removes the entire mapping of a type.
277
     *
278
     * @param string $type
279
     *   A MIME type.
280
     *
281
     * @return bool
282
     *   true if the mapping was removed, false if the type was not present.
283
     */
284
    public function removeType($type)
285
    {
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
        // Loop through all the associated aliases and remove them.
299
        foreach ($this->getTypeAliases($type) as $alias) {
300
            $this->removeTypeAlias($type, $alias);
301
        }
302
303
        unset(static::$map['t'][$type]);
304
305
        return true;
306
    }
307
308
    /**
309
     * 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
324
        $type_ret = $this->removeMapSubEntry('t', $type, 'a', $alias);
325
        $alias_ret = $this->removeMapSubEntry('a', $alias, 't', $type);
326
327
        return $type_ret && $alias_ret;
328
    }
329
330
    /**
331
     * Removes a type-to-extension mapping.
332
     *
333
     * @param string $type
334
     *   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
        $type_ret = $this->removeMapSubEntry('t', $type, 'e', $extension);
347
        $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $type);
348
349
        return $type_ret && $extension_ret;
350
    }
351
352
    /**
353
     * Gets the content of an entry from the 'extensions' array.
354
     *
355
     * @param string $extension The extension to be found.
356
     *
357
     * @return string[] The mapped MIME types.
358
     */
359 7
    public function getExtensionTypes($extension)
360
    {
361 7
        $res = $this->getMapSubEntry('e', $extension, 't');
362 7
        return $res ?: [];
363
    }
364
365
    /**
366
     * Changes the default MIME type for a file extension.
367
     *
368
     * @param string $extension
369
     *   A file extension.
370
     * @param string $type
371
     *   A MIME type.
372
     *
373
     * @throws MappingException if no mapping found.
374
     *
375
     * @return $this
376
     */
377 3
    public function setExtensionDefaultType($extension, $type)
378
    {
379 3
        return $this->setValueAsDefault('e', $extension, 't', $type);
380
    }
381
382
    /**
383
     * Gets a list of entries of the map.
384
     *
385
     * @param string $entry
386
     *   The main array entry.
387
     * @param string $match
388
     *   (Optional) a match wildcard to limit the list.
389
     *
390
     * @return array
391
     *   The list of the entries.
392
     */
393 3
    protected function listEntries($entry, $match = null)
394
    {
395 3
        $entry = strtolower($entry);
396
397 3
        if (!isset(static::$map[$entry])) {
398 1
            return [];
399
        }
400
401 3
        $list = array_keys(static::$map[$entry]);
402
403 3
        if (is_null($match)) {
404 3
            return $list;
405
        } else {
406
            $re = strtr($match, ['/' => '\\/', '*' => '.*']);
407
            return array_filter($list, function ($v) use ($re) {
408
                return preg_match("/$re/", $v) === 1;
409
            });
410
        }
411
    }
412
413
    /**
414
     * Gets the content of an entry of the map.
415
     *
416
     * @param string $entry
417
     *   The main array entry.
418
     * @param string $entry_key
419
     *   The main entry value.
420
     *
421
     * @return mixed|null
422
     *   The value of the entry, or null if missing.
423
     */
424 11
    protected function getMapEntry($entry, $entry_key)
425
    {
426 11
        $entry = strtolower($entry);
427 11
        $entry_key = strtolower($entry_key);
428 11
        return isset(static::$map[$entry][$entry_key]) ? static::$map[$entry][$entry_key] : null;
429
    }
430
431
    /**
432
     * Gets the content of a subentry of the map.
433
     *
434
     * @param string $entry
435
     *   The main array entry.
436
     * @param string $entry_key
437
     *   The main entry value.
438
     * @param string $sub_entry
439
     *   The sub entry.
440
     *
441
     * @return mixed|null
442
     *   The value of the entry, or null if missing.
443
     */
444 7
    protected function getMapSubEntry($entry, $entry_key, $sub_entry)
445
    {
446 7
        $entry = strtolower($entry);
447 7
        $entry_key = strtolower($entry_key);
448 7
        $sub_entry = strtolower($sub_entry);
449 7
        return isset(static::$map[$entry][$entry_key][$sub_entry]) ? static::$map[$entry][$entry_key][$sub_entry] : null;
450
    }
451
452
    /**
453
     * Adds an entry to the map.
454
     *
455
     * Checks that no duplicate entries are made.
456
     *
457
     * @param string $entry
458
     *   The main array entry.
459
     * @param string $entry_key
460
     *   The main entry value.
461
     * @param string $sub_entry
462
     *   The sub entry.
463
     * @param string $value
464
     *   The value to add.
465
     *
466
     * @return $this
467
     */
468 4
    protected function addMapSubEntry($entry, $entry_key, $sub_entry, $value)
469
    {
470 4
        $entry = strtolower($entry);
471 4
        $entry_key = strtolower($entry_key);
472 4
        $sub_entry = strtolower($sub_entry);
473 4
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
474 4
            static::$map[$entry][$entry_key][$sub_entry] = [$value];
475
        } else {
476 3
            if (array_search($value, static::$map[$entry][$entry_key][$sub_entry]) === false) {
477 3
                static::$map[$entry][$entry_key][$sub_entry][] = $value;
478
            }
479
        }
480 4
        return $this;
481
    }
482
483
    /**
484
     * Removes an entry from the map.
485
     *
486
     * @param string $entry
487
     *   The main array entry.
488
     * @param string $entry_key
489
     *   The main entry value.
490
     * @param string $sub_entry
491
     *   The sub entry.
492
     * @param string $value
493
     *   The value to remove.
494
     *
495
     * @return bool
496
     *   true if the entry was removed, false if the entry was not present.
497
     */
498
    protected function removeMapSubEntry($entry, $entry_key, $sub_entry, $value)
499
    {
500
        $entry = strtolower($entry);
501
        $entry_key = strtolower($entry_key);
502
        $sub_entry = strtolower($sub_entry);
503
504
        // Return false if no entry.
505
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
506
            return false;
507
        }
508
509
        // Return false if no value.
510
        $k = array_search($value, static::$map[$entry][$entry_key][$sub_entry]);
511
        if ($k === false) {
512
            return false;
513
        }
514
515
        // Remove the map entry.
516
        unset(static::$map[$entry][$entry_key][$sub_entry][$k]);
517
518
        // Remove the entry itself if no more values.
519
        if (empty(static::$map[$entry][$entry_key][$sub_entry])) {
520
            unset(static::$map[$entry][$entry_key][$sub_entry]);
521
        } else {
522
            // Resequence the remaining values.
523
            $tmp = [];
524
            foreach (static::$map[$entry][$entry_key][$sub_entry] as $v) {
525
                $tmp[] = $v;
526
            }
527
            static::$map[$entry][$entry_key][$sub_entry] = $tmp;
528
        }
529
530
        return true;
531
    }
532
533
    /**
534
     * Sets a value as the default for an entry.
535
     *
536
     * @param string $entry
537
     *   The main array entry.
538
     * @param string $entry_key
539
     *   The main entry value.
540
     * @param string $sub_entry
541
     *   The sub entry.
542
     * @param string $value
543
     *   The value to add.
544
     *
545
     * @throws MappingException if no mapping found.
546
     *
547
     * @return $this
548
     */
549 5
    protected function setValueAsDefault($entry, $entry_key, $sub_entry, $value)
550
    {
551 5
        $entry = strtolower($entry);
552 5
        $entry_key = strtolower($entry_key);
553 5
        $sub_entry = strtolower($sub_entry);
554
555
        // Throw exception if no entry.
556 5
        if (!isset(static::$map[$entry][$entry_key][$sub_entry])) {
557 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry_key}', '{$entry_key}' not defined");
558
        }
559
560
        // Throw exception if no entry-value pair.
561 3
        $k = array_search($value, static::$map[$entry][$entry_key][$sub_entry]);
562 3
        if ($k === false) {
563 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry_key}', '{$value}' not associated to '{$entry_key}'");
564
        }
565
566
        // Move value to top of array and resequence the rest.
567 1
        $tmp = [$value];
568 1
        foreach (static::$map[$entry][$entry_key][$sub_entry] as $kk => $v) {
569 1
            if ($kk === $k) {
570 1
                continue;
571
            }
572 1
            $tmp[] = $v;
573
        }
574 1
        static::$map[$entry][$entry_key][$sub_entry] = $tmp;
575
576 1
        return $this;
577
    }
578
}
579