AbstractMap::removeTypeExtensionMapping()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 11
nc 4
nop 2
dl 0
loc 16
ccs 11
cts 11
cp 1
crap 3
rs 9.9
c 0
b 0
f 0
1
<?php declare(strict_types=1);
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 implements MimeMapInterface
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 56
    protected function normalizeType(string $type_string): string
28
    {
29
        // Media and SubType are separated by a slash '/'.
30 56
        $media = TypeParser::parseStringPart($type_string, 0, '/');
31
32 55
        if (!$media['string']) {
33 2
            throw new MalformedTypeException('Media type not found');
34
        }
35 53
        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 52
        $sub = TypeParser::parseStringPart($type_string, $media['end_offset'] + 1, ';');
41
42 51
        if (!$sub['string']) {
43 1
            throw new MalformedTypeException('Media subtype not found');
44
        }
45
46 50
        return strtolower((string) $media['string']) . '/' . strtolower((string) $sub['string']);
47
    }
48
49 26
    public function hasType(string $type): bool
50
    {
51 26
        $type = $this->normalizeType($type);
52 26
        return (bool) $this->getMapEntry('t', $type);
53
    }
54
55 45
    public function hasAlias(string $alias): bool
56
    {
57 45
        $alias = $this->normalizeType($alias);
58 45
        return (bool) $this->getMapEntry('a', $alias);
59
    }
60
61 1
    public function hasExtension(string $extension): bool
62
    {
63 1
        $extension = strtolower($extension);
64 1
        return (bool) $this->getMapEntry('e', $extension);
65
    }
66
67 7
    public function listTypes(string $match = null): array
68
    {
69 7
        return $this->listEntries('t', $match);
70
    }
71
72 2
    public function listAliases(string $match = null): array
73
    {
74 2
        return $this->listEntries('a', $match);
75
    }
76
77 3
    public function listExtensions(string $match = null): array
78
    {
79 3
        return $this->listEntries('e', $match);
80
    }
81
82 3
    public function addTypeDescription(string $type, string $description): MimeMapInterface
83
    {
84 3
        $type = $this->normalizeType($type);
85
86
        // Consistency checks.
87 3
        if ($this->hasAlias($type)) {
88 1
            throw new MappingException("Cannot add description for '{$type}', '{$type}' is an alias");
89
        }
90
91 2
        $this->addMapSubEntry('t', $type, 'desc', $description);
92 2
        return $this;
93
    }
94
95 9
    public function addTypeAlias(string $type, string $alias): MimeMapInterface
96
    {
97 9
        $type = $this->normalizeType($type);
98 9
        $alias = $this->normalizeType($alias);
99
100
        // Consistency checks.
101 9
        if (!$this->hasType($type)) {
102 1
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$type}' not defined");
103
        }
104 8
        if ($this->hasType($alias)) {
105 2
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$alias}' is already defined as a type");
106
        }
107 7
        if ($this->hasAlias($alias)) {
108 2
            $unaliased_types = $this->getAliasTypes($alias);
109 2
            if (!empty($unaliased_types) && $unaliased_types[0] !== $type) {
110 1
                throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', it is an alias of '{$unaliased_types[0]}' already");
111
            }
112 1
            return $this;
113
        }
114
115 5
        $this->addMapSubEntry('t', $type, 'a', $alias);
116 5
        $this->addMapSubEntry('a', $alias, 't', $type);
117 5
        return $this;
118
    }
119
120 16
    public function addTypeExtensionMapping(string $type, string $extension): MimeMapInterface
121
    {
122 16
        $type = $this->normalizeType($type);
123 10
        $extension = strtolower($extension);
124
125
        // Consistency checks.
126 10
        if ($this->hasAlias($type)) {
127 2
            throw new MappingException("Cannot map '{$extension}' to '{$type}', '{$type}' is an alias");
128
        }
129
130
        // Add entry to 't'.
131 9
        $this->addMapSubEntry('t', $type, 'e', $extension);
132
133
        // Add entry to 'e'.
134 9
        $this->addMapSubEntry('e', $extension, 't', $type);
135
136 9
        return $this;
137
    }
138
139 5
    public function getTypeDescriptions(string $type): array
140
    {
141 5
        $type = $this->normalizeType($type);
142 5
        return $this->getMapSubEntry('t', $type, 'desc') ?: [];
143
    }
144
145 12
    public function getTypeAliases(string $type): array
146
    {
147 12
        $type = $this->normalizeType($type);
148 12
        return $this->getMapSubEntry('t', $type, 'a') ?: [];
149
    }
150
151 13
    public function getTypeExtensions(string $type): array
152
    {
153 13
        $type = $this->normalizeType($type);
154 13
        return $this->getMapSubEntry('t', $type, 'e') ?: [];
155
    }
156
157 3
    public function setTypeDefaultExtension(string $type, string $extension): MimeMapInterface
158
    {
159 3
        $type = $this->normalizeType($type);
160 3
        $extension = strtolower($extension);
161 3
        return $this->setValueAsDefault('t', $type, 'e', $extension);
162
    }
163
164 9
    public function removeType(string $type): bool
165
    {
166 9
        $type = $this->normalizeType($type);
167
168
        // Return false if type is not found.
169 9
        if (!$this->hasType($type)) {
170 1
            return false;
171
        }
172
173
        // Loop through all the associated extensions and remove them.
174 8
        foreach ($this->getTypeExtensions($type) as $extension) {
175 8
            $this->removeTypeExtensionMapping($type, $extension);
176
        }
177
178
        // Loop through all the associated aliases and remove them.
179 8
        foreach ($this->getTypeAliases($type) as $alias) {
180 5
            $this->removeTypeAlias($type, $alias);
181
        }
182
183 8
        unset(static::$map['t'][$type]);
184
185 8
        return true;
186
    }
187
188 6
    public function removeTypeAlias(string $type, string $alias): bool
189
    {
190 6
        $type = $this->normalizeType($type);
191 6
        $alias = $this->normalizeType($alias);
192
193
        // Remove any extension mapped to the alias.
194 6
        if ($extensions = $this->getMapSubEntry('a', $alias, 'e')) {
195 1
            foreach ($extensions as $extension) {
196 1
                $this->removeMapSubEntry('a', $alias, 'e', $extension);
197 1
                $this->removeMapSubEntry('e', $extension, 't', $alias);
198
            }
199
        }
200
201 6
        $type_ret = $this->removeMapSubEntry('t', $type, 'a', $alias);
202 6
        $alias_ret = $this->removeMapSubEntry('a', $alias, 't', $type);
203
204 6
        return $type_ret && $alias_ret;
205
    }
206
207 13
    public function removeTypeExtensionMapping(string $type, string $extension): bool
208
    {
209 13
        $type = $this->normalizeType($type);
210 13
        $extension = strtolower($extension);
211
212 13
        if ($this->hasAlias($type)) {
213 1
            $alias = $type;
214 1
            $type_ret = $this->removeMapSubEntry('a', $alias, 'e', $extension);
215 1
            $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $alias);
216
        } else {
217 12
            $this->removeAliasedTypesExtensionMapping($type, $extension);
218 12
            $type_ret = $this->removeMapSubEntry('t', $type, 'e', $extension);
219 12
            $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $type);
220
        }
221
222 13
        return $type_ret && $extension_ret;
223
    }
224
225
    /**
226
     * Removes aliased types extension mapping.
227
     *
228
     * @param string $type
229
     *   A MIME type.
230
     * @param string $extension
231
     *   The file extension to be removed.
232
     */
233 12
    protected function removeAliasedTypesExtensionMapping(string $type, string $extension): void
234
    {
235 12
        $type = $this->normalizeType($type);
236 12
        $extension = strtolower($extension);
237 12
        foreach ($this->getExtensionTypes($extension) as $associated_type) {
238 12
            if ($this->hasAlias($associated_type) && $type === $this->getAliasTypes($associated_type)[0]) {
239 2
                $this->removeMapSubEntry('a', $associated_type, 'e', $extension);
240 2
                $this->removeMapSubEntry('e', $extension, 't', $associated_type);
241
            }
242
        }
243
    }
244
245 9
    public function getAliasTypes(string $alias): array
246
    {
247 9
        $alias = $this->normalizeType($alias);
248 9
        return $this->getMapSubEntry('a', $alias, 't') ?: [];
249
    }
250
251 19
    public function getExtensionTypes(string $extension): array
252
    {
253 19
        $extension = strtolower($extension);
254 19
        return $this->getMapSubEntry('e', $extension, 't') ?: [];
255
    }
256
257 7
    public function setExtensionDefaultType(string $extension, string $type): MimeMapInterface
258
    {
259 7
        $type = $this->normalizeType($type);
260 7
        $extension = strtolower($extension);
261
262 7
        if ($this->hasAlias($type)) {
263 4
            $alias = $type;
264 4
            $type = $this->getAliasTypes($alias)[0];
265
            // Check that the alias is referring to a type associated with that
266
            // extension.
267 4
            $associated_types = $this->getMapSubEntry('e', $extension, 't') ?: [];
268 4
            if (!in_array($type, $associated_types)) {
269 1
                throw new MappingException("Cannot set '{$alias}' as default type for extension '{$extension}', its unaliased type '{$type}' is not associated to '{$extension}'");
270
            }
271 3
            $this->addMapSubEntry('a', $alias, 'e', $extension);
272 3
            $this->addMapSubEntry('e', $extension, 't', $alias);
273 3
            return $this->setValueAsDefault('e', $extension, 't', $alias);
274
        } else {
275 3
            return $this->setValueAsDefault('e', $extension, 't', $type);
276
        }
277
    }
278
}
279