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

AbstractMap::listAliases()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?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 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 39
    protected function normalizeType(string $type_string): string
28
    {
29
        // Media and SubType are separated by a slash '/'.
30 39
        $media = TypeParser::parseStringPart($type_string, 0, '/');
31
32 38
        if (!$media['string']) {
33 2
            throw new MalformedTypeException('Media type not found');
34
        }
35 36
        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 35
        $sub = TypeParser::parseStringPart($type_string, $media['end_offset'] + 1, ';');
41
42 34
        if (!$sub['string']) {
43 1
            throw new MalformedTypeException('Media subtype not found');
44
        }
45
46 33
        return strtolower((string) $media['string']) . '/' . strtolower((string) $sub['string']);
47
    }
48
49 17
    public function hasType(string $type): bool
50
    {
51 17
        $type = $this->normalizeType($type);
52 17
        return (bool) $this->getMapEntry('t', $type);
53
    }
54
55 28
    public function hasAlias(string $alias): bool
56
    {
57 28
        $alias = $this->normalizeType($alias);
58 28
        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 5
    public function listTypes(string $match = null): array
68
    {
69 5
        return $this->listEntries('t', $match);
70
    }
71
72
    public function listAliases(string $match = null): array
73
    {
74
        return $this->listEntries('a', $match);
75
    }
76
77 1
    public function listExtensions(string $match = null): array
78
    {
79 1
        return $this->listEntries('e', $match);
80
    }
81
82 1
    public function addTypeDescription(string $type, string $description): MimeMapInterface
83
    {
84 1
        $type = $this->normalizeType($type);
85
86
        // Consistency checks.
87 1
        if ($this->hasAlias($type)) {
88 1
            throw new MappingException("Cannot add description for '{$type}', '{$type}' is an alias");
89
        }
90
91
        $this->addMapSubEntry('t', $type, 'desc', $description);
92
        return $this;
93
    }
94
95 7
    public function addTypeAlias(string $type, string $alias): MimeMapInterface
96
    {
97 7
        $type = $this->normalizeType($type);
98 7
        $alias = $this->normalizeType($alias);
99
100
        // Consistency checks.
101 7
        if (!$this->hasType($type)) {
102 1
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$type}' not defined");
103
        }
104 6
        if ($this->hasType($alias)) {
105 1
            throw new MappingException("Cannot set '{$alias}' as alias for '{$type}', '{$alias}' is already defined as a type");
106
        }
107 5
        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 3
        $this->addMapSubEntry('t', $type, 'a', $alias);
116 3
        $this->addMapSubEntry('a', $alias, 't', $type);
117 3
        return $this;
118
    }
119
120 12
    public function addTypeExtensionMapping(string $type, string $extension): MimeMapInterface
121
    {
122 12
        $type = $this->normalizeType($type);
123 6
        $extension = strtolower($extension);
124
125
        // Consistency checks.
126 6
        if ($this->hasAlias($type)) {
127 1
            throw new MappingException("Cannot map '{$extension}' to '{$type}', '{$type}' is an alias");
128
        }
129
130
        // Add entry to 't'.
131 5
        $this->addMapSubEntry('t', $type, 'e', $extension);
132
133
        // Add entry to 'e'.
134 5
        $this->addMapSubEntry('e', $extension, 't', $type);
135
136 5
        return $this;
137
    }
138
139 1
    public function getTypeDescriptions(string $type): array
140
    {
141 1
        $type = $this->normalizeType($type);
142 1
        return $this->getMapSubEntry('t', $type, 'desc') ?: [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getMapSubE...ype, 'desc') ?: array() could return the type FileEye\MimeMap\Map\list which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
143
    }
144
145 5
    public function getTypeAliases(string $type): array
146
    {
147 5
        $type = $this->normalizeType($type);
148 5
        return $this->getMapSubEntry('t', $type, 'a') ?: [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getMapSubE... $type, 'a') ?: array() could return the type FileEye\MimeMap\Map\list which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
149
    }
150
151 6
    public function getTypeExtensions(string $type): array
152
    {
153 6
        $type = $this->normalizeType($type);
154 6
        return $this->getMapSubEntry('t', $type, 'e') ?: [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getMapSubE... $type, 'e') ?: array() could return the type FileEye\MimeMap\Map\list which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
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 2
    public function removeType(string $type): bool
165
    {
166 2
        $type = $this->normalizeType($type);
167
168
        // Return false if type is not found.
169 2
        if (!$this->hasType($type)) {
170 1
            return false;
171
        }
172
173
        // Loop through all the associated extensions and remove them.
174 2
        foreach ($this->getTypeExtensions($type) as $extension) {
175 2
            $this->removeTypeExtensionMapping($type, $extension);
176
        }
177
178
        // Loop through all the associated aliases and remove them.
179 2
        foreach ($this->getTypeAliases($type) as $alias) {
180 2
            $this->removeTypeAlias($type, $alias);
181
        }
182
183 2
        unset(static::$map['t'][$type]);
184
185 2
        return true;
186
    }
187
188 2
    public function removeTypeAlias(string $type, string $alias): bool
189
    {
190 2
        $type = $this->normalizeType($type);
191 2
        $alias = $this->normalizeType($alias);
192
193
        // Remove any extension mapped to the alias.
194 2
        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 2
        $type_ret = $this->removeMapSubEntry('t', $type, 'a', $alias);
202 2
        $alias_ret = $this->removeMapSubEntry('a', $alias, 't', $type);
203
204 2
        return $type_ret && $alias_ret;
205
    }
206
207 4
    public function removeTypeExtensionMapping(string $type, string $extension): bool
208
    {
209 4
        $type = $this->normalizeType($type);
210 4
        $extension = strtolower($extension);
211
212 4
        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 3
            $this->removeAliasedTypesExtensionMapping($type, $extension);
218 3
            $type_ret = $this->removeMapSubEntry('t', $type, 'e', $extension);
219 3
            $extension_ret = $this->removeMapSubEntry('e', $extension, 't', $type);
220
        }
221
222 4
        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 3
    protected function removeAliasedTypesExtensionMapping(string $type, string $extension): void
234
    {
235 3
        $type = $this->normalizeType($type);
236 3
        $extension = strtolower($extension);
237 3
        foreach ($this->getExtensionTypes($extension) as $associated_type) {
238 3
            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') ?: [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getMapSubE...$alias, 't') ?: array() could return the type FileEye\MimeMap\Map\list which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
249
    }
250
251 12
    public function getExtensionTypes(string $extension): array
252
    {
253 12
        $extension = strtolower($extension);
254 12
        return $this->getMapSubEntry('e', $extension, 't') ?: [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getMapSubE...ension, 't') ?: array() could return the type FileEye\MimeMap\Map\list which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
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)) {
0 ignored issues
show
Bug introduced by
It seems like $associated_types can also be of type FileEye\MimeMap\Map\list; however, parameter $haystack of in_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

268
            if (!in_array($type, /** @scrutinizer ignore-type */ $associated_types)) {
Loading history...
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