Test Failed
Pull Request — master (#58)
by mon
01:51
created

AbstractMap::addTypeAlias()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 5
nop 2
dl 0
loc 23
rs 9.2222
c 0
b 0
f 0
ccs 15
cts 15
cp 1
crap 6
1
: AbstractMap<?php
2
3
namespace FileEye\MimeMap\Map;
4
5
use FileEye\MimeMap\MalformedTypeException;
6
use FileEye\MimeMap\MappingException;
7
use FileEye\MimeMap\TypeParser;
8
9
/**
10
 * Abstract class for mapping file extensions to MIME types.
11
 *
12
 * This class cannot be instantiated; extend from it to implement a map.
13
 */
14
abstract class AbstractMap extends BaseMap
15
{
16
    /**
17
     * Normalizes a mime-type string to Media/Subtype.
18
     *
19
     * @param string $type_string
20
     *   MIME type string to parse.
21
     *
22
     * @throws MalformedTypeException when $type_string is malformed.
23
     *
24
     * @return string
25
     *   A MIME type string in the 'Media/Subtype' format.
26
     */
27 43
    protected function normalizeType(string $type_string): string
28
    {
29
        // Media and SubType are separated by a slash '/'.
30 43
        $media = TypeParser::parseStringPart($type_string, 0, '/');
31
32 42
        if (!$media['string']) {
33 2
            throw new MalformedTypeException('Media type not found');
34
        }
35 40
        if (!$media['delimiter_matched']) {
36 1
            throw new MalformedTypeException('Slash \'/\' to separate media type and subtype not found');
37
        }
38
39
        // SubType and Parameters are separated by semicolons ';'.
40 39
        $sub = TypeParser::parseStringPart($type_string, $media['end_offset'] + 1, ';');
41
42 38
        if (!$sub['string']) {
43 1
            throw new MalformedTypeException('Media subtype not found');
44
        }
45
46 37
        return strtolower((string) $media['string']) . '/' . strtolower((string) $sub['string']);
47
    }
48
49
    /**
50
     * Determines if a MIME type exists.
51
     *
52
     * @param string $type The type to be found.
53
     *
54
     * @return bool
55
     */
56 19
    public function hasType(string $type): bool
57
    {
58 19
        $type = $this->normalizeType($type);
59 19
        return (bool) $this->getMapEntry('t', $type);
60
    }
61
62
    /**
63
     * Determines if a MIME type alias exists.
64
     *
65
     * @param string $alias The alias to be found.
66
     *
67
     * @return bool
68
     */
69 32
    public function hasAlias(string $alias): bool
70
    {
71 32
        $alias = $this->normalizeType($alias);
72 32
        return (bool) $this->getMapEntry('a', $alias);
73
    }
74
75
    /**
76
     * Determines if an entry exists from the 'extensions' array.
77
     *
78
     * @param string $extension The extension to be found.
79
     *
80
     * @return bool
81
     */
82 1
    public function hasExtension(string $extension): bool
83
    {
84 1
        $extension = strtolower($extension);
85 1
        return (bool) $this->getMapEntry('e', $extension);
86
    }
87
88
    /**
89
     * Lists all the MIME types defined in the map.
90
     *
91
     * @param string $match (Optional) a match wildcard to limit the list.
92
     *
93
     * @return string[]
94
     */
95 7
    public function listTypes(string $match = null): array
96
    {
97 7
        return $this->listEntries('t', $match);
98
    }
99
100
    /**
101
     * Lists all the MIME types aliases defined in the map.
102
     *
103
     * @param string $match (Optional) a match wildcard to limit the list.
104
     *
105
     * @return string[]
106
     */
107 2
    public function listAliases(string $match = null): array
108
    {
109 2
        return $this->listEntries('a', $match);
110
    }
111
112
    /**
113
     * Lists all the extensions defined in the map.
114
     *
115
     * @param string $match (Optional) a match wildcard to limit the list.
116
     *
117
     * @return string[]
118
     */
119 3
    public function listExtensions(string $match = null): array
120
    {
121 3
        return $this->listEntries('e', $match);
122
    }
123
124
    /**
125
     * Adds a description of a MIME type.
126
     *
127
     * @param string $type
128
     *   A MIME type.
129
     * @param string $description
130
     *   The description of the MIME type.
131
     *
132
     * @throws MappingException if $type is an alias.
133
     *
134
     * @return $this
135
     */
136 3
    public function addTypeDescription(string $type, string $description): AbstractMap
137
    {
138 3
        $type = $this->normalizeType($type);
139
140
        // Consistency checks.
141 3
        if ($this->hasAlias($type)) {
142 1
            throw new MappingException("Cannot add description for '{$type}', '{$type}' is an alias");
143
        }
144
145 2
        $this->addMapSubEntry('t', $type, 'desc', $description);
146 2
        return $this;
147
    }
148
149
    /**
150
     * Adds an alias of a MIME type.
151
     *
152
     * @param string $type
153
     *   A MIME type.
154
     * @param string $alias
155
     *   An alias of $type.
156
     *
157
     * @throws MappingException if no $type is found.
158
     *
159
     * @return $this
160
     */
161 9
    public function addTypeAlias(string $type, string $alias): AbstractMap
162
    {
163 9
        $type = $this->normalizeType($type);
164 9
        $alias = $this->normalizeType($alias);
165
166
        // Consistency checks.
167 9
        if (!$this->hasType($type)) {
168 1
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$type}' not defined");
169
        }
170 8
        if ($this->hasType($alias)) {
171 2
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$alias}' is already defined as a type");
172
        }
173 7
        if ($this->hasAlias($alias)) {
174 2
            $unaliased_types = $this->getAliasTypes($alias);
175 2
            if (!empty($unaliased_types) && $unaliased_types[0] !== $type) {
176 1
                throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', it is an alias of '{$unaliased_types[0]}' already");
177
            }
178 1
            return $this;
179
        }
180
181 5
        $this->addMapSubEntry('t', $type, 'a', $alias);
182 5
        $this->addMapSubEntry('a', $alias, 't', $type);
183 5
        return $this;
184
    }
185
186
    /**
187
     * Adds a type-to-extension mapping.
188
     *
189
     * @param string $type
190
     *   A MIME type.
191
     * @param string $extension
192
     *   A file extension.
193
     *
194
     * @throws MappingException if $type is an alias.
195
     *
196
     * @return $this
197
     */
198 16
    public function addTypeExtensionMapping(string $type, string $extension): AbstractMap
199
    {
200 16
        $type = $this->normalizeType($type);
201 10
        $extension = strtolower($extension);
202
203
        // Consistency checks.
204 10
        if ($this->hasAlias($type)) {
205 2
            throw new MappingException("Cannot map '{$extension}' to '{$type}', '{$type}' is an alias");
206
        }
207
208
        // Add entry to 't'.
209 9
        $this->addMapSubEntry('t', $type, 'e', $extension);
210
211
        // Add entry to 'e'.
212 9
        $this->addMapSubEntry('e', $extension, 't', $type);
213
214 9
        return $this;
215
    }
216
217
    /**
218
     * Gets the descriptions of a MIME type.
219
     *
220
     * @param string $type The type to be found.
221
     *
222
     * @return string[] The mapped descriptions.
223
     */
224 1
    public function getTypeDescriptions(string $type): array
225
    {
226 1
        $type = $this->normalizeType($type);
227 1
        return $this->getMapSubEntry('t', $type, 'desc') ?: [];
228
    }
229
230
    /**
231
     * Gets the aliases of a MIME type.
232
     *
233
     * @param string $type The type to be found.
234
     *
235
     * @return string[] The mapped aliases.
236
     */
237 5
    public function getTypeAliases(string $type): array
238
    {
239 5
        $type = $this->normalizeType($type);
240 5
        return $this->getMapSubEntry('t', $type, 'a') ?: [];
241
    }
242
243
    /**
244
     * Gets the content of an entry from the 't' array.
245
     *
246
     * @param string $type The type to be found.
247
     *
248
     * @return string[] The mapped file extensions.
249
     */
250 6
    public function getTypeExtensions(string $type): array
251
    {
252 6
        $type = $this->normalizeType($type);
253 6
        return $this->getMapSubEntry('t', $type, 'e') ?: [];
254
    }
255
256
    /**
257
     * Changes the default extension for a MIME type.
258
     *
259
     * @param string $type
260
     *   A MIME type.
261
     * @param string $extension
262
     *   A file extension.
263
     *
264
     * @throws MappingException if no mapping found.
265
     *
266
     * @return $this
267
     */
268 3
    public function setTypeDefaultExtension(string $type, string $extension): AbstractMap
269
    {
270 3
        $type = $this->normalizeType($type);
271 3
        $extension = strtolower($extension);
272 3
        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 2
    public function removeType(string $type): bool
285
    {
286 2
        $type = $this->normalizeType($type);
287
288
        // Return false if type is not found.
289 2
        if (!$this->hasType($type)) {
290 1
            return false;
291
        }
292
293
        // Loop through all the associated extensions and remove them.
294 2
        foreach ($this->getTypeExtensions($type) as $extension) {
295 2
            $this->removeTypeExtensionMapping($type, $extension);
296
        }
297
298
        // Loop through all the associated aliases and remove them.
299 2
        foreach ($this->getTypeAliases($type) as $alias) {
300 2
            $this->removeTypeAlias($type, $alias);
301
        }
302
303 2
        unset(static::$map['t'][$type]);
304
305 2
        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 2
    public function removeTypeAlias(string $type, string $alias): bool
320
    {
321 2
        $type = $this->normalizeType($type);
322 2
        $alias = $this->normalizeType($alias);
323
324
        // Remove any extension mapped to the alias.
325 2
        if ($extensions = $this->getMapSubEntry('a', $alias, 'e')) {
326 1
            foreach ($extensions as $extension) {
327 1
                $this->removeMapSubEntry('a', $alias, 'e', $extension);
328 1
                $this->removeMapSubEntry('e', $extension, 't', $alias);
329
            }
330
        }
331
332 2
        $type_ret = $this->removeMapSubEntry('t', $type, 'a', $alias);
333 2
        $alias_ret = $this->removeMapSubEntry('a', $alias, 't', $type);
334
335 2
        return $type_ret && $alias_ret;
336
    }
337
338
    /**
339
     * Removes a type-to-extension mapping.
340
     *
341
     * @param string $type
342
     *   A MIME type.
343
     * @param string $extension
344
     *   The file extension to be removed.
345
     *
346
     * @return bool
347
     *   true if the mapping was removed, false if the mapping was not present.
348
     */
349 4
    public function removeTypeExtensionMapping(string $type, string $extension): bool
350
    {
351 4
        $type = $this->normalizeType($type);
352 4
        $extension = strtolower($extension);
353
354 4
        if ($this->hasAlias($type)) {
355 1
            $alias = $type;
356 1
            $type_ret = $this->removeMapSubEntry('a', $alias, 'e', $extension);
357 1
            $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $alias);
358
        } else {
359 3
            $this->removeAliasedTypesExtensionMapping($type, $extension);
360 3
            $type_ret = $this->removeMapSubEntry('t', $type, 'e', $extension);
361 3
            $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $type);
362
        }
363
364 4
        return $type_ret && $extension_ret;
365
    }
366
367
    /**
368
     * Removes aliased types extension mapping.
369
     *
370
     * @param string $type
371
     *   A MIME type.
372
     * @param string $extension
373
     *   The file extension to be removed.
374
     */
375 3
    protected function removeAliasedTypesExtensionMapping(string $type, string $extension): void
376
    {
377 3
        $type = $this->normalizeType($type);
378 3
        $extension = strtolower($extension);
379 3
        foreach ($this->getExtensionTypes($extension) as $associated_type) {
380 3
            if ($this->hasAlias($associated_type) && $type === $this->getAliasTypes($associated_type)[0]) {
381 2
                $this->removeMapSubEntry('a', $associated_type, 'e', $extension);
382 2
                $this->removeMapSubEntry('e', $extension, 't', $associated_type);
383
            }
384
        }
385
    }
386
387
    /**
388
     * Gets the parent types of an alias.
389
     *
390
     * There should not be multiple types for an alias.
391
     *
392
     * @param string $alias The alias to be found.
393
     *
394
     * @return string[]
395
     */
396 9
    public function getAliasTypes(string $alias): array
397
    {
398 9
        $alias = $this->normalizeType($alias);
399 9
        return $this->getMapSubEntry('a', $alias, 't') ?: [];
400
    }
401
402
    /**
403
     * Gets the content of an entry from the 'extensions' array.
404
     *
405
     * @param string $extension The extension to be found.
406
     *
407
     * @return string[] The mapped MIME types.
408
     */
409 12
    public function getExtensionTypes(string $extension): array
410
    {
411 12
        $extension = strtolower($extension);
412 12
        return $this->getMapSubEntry('e', $extension, 't') ?: [];
413
    }
414
415
    /**
416
     * Changes the default MIME type for a file extension.
417
     *
418
     * Allows a MIME type alias to be set as default for the extension.
419
     *
420
     * @param string $extension
421
     *   A file extension.
422
     * @param string $type
423
     *   A MIME type.
424
     *
425
     * @throws MappingException if no mapping found.
426
     *
427
     * @return $this
428
     */
429 7
    public function setExtensionDefaultType(string $extension, string $type): AbstractMap
430
    {
431 7
        $type = $this->normalizeType($type);
432 7
        $extension = strtolower($extension);
433
434 7
        if ($this->hasAlias($type)) {
435 4
            $alias = $type;
436 4
            $type = $this->getAliasTypes($alias)[0];
437
            // Check that the alias is referring to a type associated with that
438
            // extension.
439 4
            $associated_types = $this->getMapSubEntry('e', $extension, 't') ?: [];
440 4
            if (!in_array($type, $associated_types)) {
441 1
                throw new MappingException("Cannot set '{$alias}' as default type for extension '{$extension}', its unaliased type '{$type}' is not associated to '{$extension}'");
442
            }
443 3
            $this->addMapSubEntry('a', $alias, 'e', $extension);
444 3
            $this->addMapSubEntry('e', $extension, 't', $alias);
445 3
            return $this->setValueAsDefault('e', $extension, 't', $alias);
446
        } else {
447 3
            return $this->setValueAsDefault('e', $extension, 't', $type);
448
        }
449
    }
450
}
0 ignored issues
show
Bug introduced by
A parse error occurred: Namespace declaration statement has to be the very first statement in the script
Loading history...
451