Passed
Pull Request — master (#5)
by mon
02:39
created

MapHandler::getMapFileName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace FileEye\MimeMap;
4
5
/**
6
 * Class for managing the type-to-extension map.
7
 */
8
class MapHandler
9
{
10
    /**
11
     * The default map PHP class.
12
     */
13
    const DEFAULT_MAP_CLASS = '\FileEye\MimeMap\TypeExtensionMap';
14
15
    /**
16
     * The map class to use.
17
     *
18
     * It's static so it can be overridden by ::setDefaultMapClass and any new
19
     * instance take the overriden setting.
20
     *
21
     * @var string
22
     */
23
    protected static $mapClass = MapHandler::DEFAULT_MAP_CLASS;
24
25
    /**
26
     * Mapping between file extensions and MIME types.
27
     *
28
     * The array has two main keys, 'types' that maps MIME types to file
29
     * extensions, and 'extensions' that map file extensions to MIME types.
30
     *
31
     * @var array
32
     */
33
    protected $map;
34
35
    /**
36
     * Sets a map class as default for new instances.
37
     *
38
     * @param string $class A FQCN.
39
     */
40 1
    public static function setDefaultMapClass($class)
41
    {
42 1
        static::$mapClass = $class;
43 1
    }
44
45
    /**
46
     * Constructor.
47
     *
48
     * @param array $map
49
     *   (Optional) The mapping to be used for this instance. If null, the
50
     *   default map will be used.
51
     */
52 22
    public function __construct(array $map = null)
53
    {
54 22
        if (is_null($map)) {
55 18
            $map_class = static::$mapClass;
56 18
            $this->map = &$map_class::$map;
57
        } else {
58 5
            $this->map = $map;
59
        }
60 22
    }
61
62
    /**
63
     * Returns the filename of the PHP file where the map is loaded from.
64
     *
65
     * @return string
66
     */
67 1
    public function getMapFileName()
68
    {
69 1
        $map_class = static::$mapClass;
70 1
        return $map_class::getFileName();
71
    }
72
73
    /**
74
     * Returns the map associated with this instance.
75
     *
76
     * @return array
77
     */
78 18
    public function get()
79
    {
80 18
        return $this->map;
81
    }
82
83
    /**
84
     * Sorts the map.
85
     *
86
     * @return $this
87
     */
88 3
    public function sort()
89
    {
90 3
        ksort($this->map['types']);
91 3
        ksort($this->map['extensions']);
92 3
        return $this;
93
    }
94
95
    /**
96
     * Adds an entry to the map.
97
     *
98
     * Checks that no duplicate entries are made.
99
     *
100
     * @param string $key
101
     *   The main array key.
102
     * @param string $entry
103
     *   The sub array key.
104
     * @param string $value
105
     *   The value to add.
106
     *
107
     * @return $this
108
     */
109 6
    protected function addMapEntry($key, $entry, $value)
110
    {
111 6
        if (!isset($this->map[$key][$entry])) {
112 6
            $this->map[$key][$entry] = [$value];
113
        } else {
114 5
            if (array_search($value, $this->map[$key][$entry]) === false) {
115 5
                $this->map[$key][$entry][] = $value;
116
            }
117
        }
118 6
        return $this;
119
    }
120
121
    /**
122
     * Removes an entry from the map.
123
     *
124
     * @param string $key
125
     *   The main array key.
126
     * @param string $entry
127
     *   The sub array key.
128
     * @param string $value
129
     *   The value.
130
     *
131
     * @return bool
132
     *   true if the entry was removed, false if the entry was not present.
133
     */
134 1
    protected function removeMapEntry($key, $entry, $value)
135
    {
136
        // Return false if no entry.
137 1
        if (!isset($this->map[$key][$entry])) {
138 1
            return false;
139
        }
140
141
        // Return false if no value.
142 1
        $k = array_search($value, $this->map[$key][$entry]);
143 1
        if ($k === false) {
144 1
            return false;
145
        }
146
147
        // Remove the map entry.
148 1
        unset($this->map[$key][$entry][$k]);
149
150
        // Remove the entry itself if no more values.
151 1
        if (empty($this->map[$key][$entry])) {
152 1
            unset($this->map[$key][$entry]);
153
        } else {
154
            // Resequence the remaining values.
155 1
            $tmp = [];
156 1
            foreach ($this->map[$key][$entry] as $v) {
157 1
                $tmp[] = $v;
158
            }
159 1
            $this->map[$key][$entry] = $tmp;
160
        }
161
162 1
        return true;
163
    }
164
165
    /**
166
     * Sets a value as the default for an entry.
167
     *
168
     * @param string $key
169
     *   The main array key.
170
     * @param string $entry
171
     *   The sub array key.
172
     * @param string $value
173
     *   The value.
174
     *
175
     * @throws MappingException if no mapping found.
176
     *
177
     * @return $this
178
     */
179 6
    protected function setValueAsDefault($key, $entry, $value)
180
    {
181
        // Throw exception if no entry.
182 6
        if (!isset($this->map[$key][$entry])) {
183 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry}', '{$entry}' not defined");
184
        }
185
186
        // Throw exception if no entry-value pair.
187 4
        $k = array_search($value, $this->map[$key][$entry]);
188 4
        if ($k === false) {
189 2
            throw new MappingException("Cannot set '{$value}' as default for '{$entry}', '{$value}' not associated to '{$entry}'");
190
        }
191
192
        // Move value to top of array and resequence the rest.
193 2
        $tmp = [$value];
194 2
        foreach ($this->map[$key][$entry] as $kk => $v) {
195 2
            if ($kk === $k) {
196 2
                continue;
197
            }
198 2
            $tmp[] = $v;
199
        }
200 2
        $this->map[$key][$entry] = $tmp;
201
202 2
        return $this;
203
    }
204
205
    /**
206
     * Adds a type-to-extension mapping.
207
     *
208
     * @param string $type
209
     *   A MIME type.
210
     * @param string $extension
211
     *   A file extension.
212
     *
213
     * @return $this
214
     */
215 6
    public function addMapping($type, $extension)
216
    {
217 6
        $type = strtolower($type);
218 6
        $extension = (string) strtolower($extension);
219
220
        // Add entry to 'types'.
221 6
        $this->addMapEntry('types', $type, $extension);
222
223
        // Add entry to 'extensions'.
224 6
        $this->addMapEntry('extensions', $extension, $type);
225
226 6
        return $this;
227
    }
228
229
    /**
230
     * Removes a type-to-extension mapping.
231
     *
232
     * @param string $type
233
     *   A MIME type.
234
     * @param string $extension
235
     *   A file extension.
236
     *
237
     * @return bool
238
     *   true if the mapping was removed, false if the mapping was not present.
239
     */
240 1
    public function removeMapping($type, $extension)
241
    {
242 1
        $type = strtolower($type);
243 1
        $extension = (string) strtolower($extension);
244
245
        // Remove entry from 'types'.
246 1
        $type_ret = $this->removeMapEntry('types', $type, $extension);
247
248
        // Remove entry from 'extensions'.
249 1
        $extension_ret = $this->removeMapEntry('extensions', $extension, $type);
250
251 1
        return $type_ret && $extension_ret;
252
    }
253
254
    /**
255
     * Removes the entire mapping of a type.
256
     *
257
     * @param string $type
258
     *   A MIME type.
259
     *
260
     * @return bool
261
     *   true if the mapping was removed, false if the type was not present.
262
     */
263 1
    public function removeType($type)
264
    {
265 1
        $type = strtolower($type);
266
267
        // Return false if type is not found.
268 1
        if (!isset($this->map['types'][$type])) {
269 1
            return false;
270
        }
271
272
        // Loop through all the associated extensions and remove them. This
273
        // is also removing the type itself when the last extension is removed.
274 1
        foreach ($this->map['types'][$type] as $extension) {
275 1
            $this->removeMapping($type, $extension);
276
        }
277
278 1
        return true;
279
    }
280
281
    /**
282
     * Changes the default extension for a MIME type.
283
     *
284
     * @param string $type
285
     *   A MIME type.
286
     * @param string $extension
287
     *   A file extension.
288
     *
289
     * @throws MappingException if no mapping found.
290
     *
291
     * @return $this
292
     */
293 3
    public function setTypeDefaultExtension($type, $extension)
294
    {
295 3
        $type = strtolower($type);
296 3
        $extension = (string) strtolower($extension);
297
298 3
        return $this->setValueAsDefault('types', $type, $extension);
299
    }
300
301
    /**
302
     * Changes the default MIME type for a file extension.
303
     *
304
     * @param string $extension
305
     *   A file extension.
306
     * @param string $type
307
     *   A MIME type.
308
     *
309
     * @throws MappingException if no mapping found.
310
     *
311
     * @return $this
312
     */
313 3
    public function setExtensionDefaultType($extension, $type)
314
    {
315 3
        $type = strtolower($type);
316 3
        $extension = (string) strtolower($extension);
317
318 3
        return $this->setValueAsDefault('extensions', $extension, $type);
319
    }
320
}
321