Passed
Pull Request — master (#59)
by mon
07:20
created

Type::getSubTypeComment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
ccs 4
cts 5
cp 0.8
crap 2.032
1
<?php declare(strict_types=1);
2
3
namespace FileEye\MimeMap;
4
5
use FileEye\MimeMap\Map\MimeMapInterface;
6
7
/**
8
 * Class for working with MIME types
9
 */
10
class Type implements TypeInterface
11
{
12
    /**
13
     * Short format [e.g. image/jpeg] for strings.
14
     */
15
    const SHORT_TEXT = 0;
16
17
    /**
18
     * Full format [e.g. image/jpeg; p="1"] for strings.
19
     */
20
    const FULL_TEXT = 1;
21
22
    /**
23
     * Full format with comments [e.g. image/jpeg; p="1" (comment)] for strings.
24
     */
25
    const FULL_TEXT_WITH_COMMENTS = 2;
26
27
    /**
28
     * The MIME media type.
29
     *
30
     * @var string
31
     */
32
    protected $media;
33
34
    /**
35
     * The MIME media type comment.
36
     *
37
     * @var string|null
38
     */
39
    protected $mediaComment;
40
41
    /**
42
     * The MIME media sub-type.
43
     *
44
     * @var string
45
     */
46
    protected $subType;
47
48
    /**
49
     * The MIME media sub-type comment.
50
     *
51
     * @var string|null
52
     */
53
    protected $subTypeComment;
54
55
    /**
56
     *  MIME type descriptions.
57
     *
58
     * @var string[]
59
     */
60
    protected $descriptions;
61
62
    /**
63
     * Optional MIME parameters.
64
     *
65
     * @var TypeParameter[]
66
     */
67
    protected $parameters = [];
68
69
    /**
70
     * The MIME types map.
71
     *
72
     * @var MimeMapInterface
73
     */
74
    protected $map;
75
76 69
    public function __construct(string $type_string, string $map_class = null)
77
    {
78 69
        TypeParser::parse($type_string, $this);
79 63
        $this->map = MapHandler::map($map_class);
80
    }
81
82 49
    public function getMedia(): string
83
    {
84 49
        return $this->media;
85
    }
86
87 65
    public function setMedia(string $media): TypeInterface
88
    {
89 65
        $this->media = $media;
90 65
        return $this;
91
    }
92
93 32
    public function hasMediaComment(): bool
94
    {
95 32
        return $this->mediaComment !== null;
96
    }
97
98 3
    public function getMediaComment(): string
99
    {
100 3
        if ($this->hasMediaComment()) {
101 3
            assert(is_string($this->mediaComment));
102 3
            return $this->mediaComment;
103
        }
104
        throw new UndefinedException('Media comment is not defined');
105
    }
106
107 3
    public function setMediaComment(string $comment = null): TypeInterface
108
    {
109 3
        $this->mediaComment = $comment;
110 3
        return $this;
111
    }
112
113 50
    public function getSubType(): string
114
    {
115 50
        return $this->subType;
116
    }
117
118 63
    public function setSubType(string $sub_type): TypeInterface
119
    {
120 63
        $this->subType = $sub_type;
121 63
        return $this;
122
    }
123
124 32
    public function hasSubTypeComment(): bool
125
    {
126 32
        return $this->subTypeComment !== null;
127
    }
128
129 6
    public function getSubTypeComment(): string
130
    {
131 6
        if ($this->hasSubTypeComment()) {
132 6
            assert(is_string($this->subTypeComment));
133 6
            return $this->subTypeComment;
134
        }
135
        throw new UndefinedException('Subtype comment is not defined');
136
    }
137
138 6
    public function setSubTypeComment(string $comment = null): TypeInterface
139
    {
140 6
        $this->subTypeComment = $comment;
141 6
        return $this;
142
    }
143
144 30
    public function hasParameters(): bool
145
    {
146 30
        return (bool) $this->parameters;
147
    }
148
149 23
    public function getParameters(): array
150
    {
151 23
        if ($this->hasParameters()) {
152 23
            return $this->parameters;
153
        }
154
        throw new UndefinedException("No parameters defined");
155
    }
156
157 24
    public function hasParameter(string $name): bool
158
    {
159 24
        return isset($this->parameters[$name]);
160
    }
161
162 24
    public function getParameter(string $name): TypeParameter
163
    {
164 24
        if ($this->hasParameter($name)) {
165 24
            return $this->parameters[$name];
166
        }
167
        throw new UndefinedException("Parameter $name is not defined");
168
    }
169
170 27
    public function addParameter(string $name, string $value, string $comment = null): void
171
    {
172 27
        $this->parameters[$name] = new TypeParameter($name, $value, $comment);
173
    }
174
175 1
    public function removeParameter(string $name): void
176
    {
177 1
        unset($this->parameters[$name]);
178
    }
179
180 57
    public function toString(int $format = Type::FULL_TEXT): string
181
    {
182 57
        $type = strtolower($this->media);
183 57
        if ($format > Type::FULL_TEXT && $this->hasMediaComment()) {
184 3
            $type .= ' (' .  $this->getMediaComment() . ')';
185
        }
186 57
        $type .= '/' . strtolower($this->subType);
187 57
        if ($format > Type::FULL_TEXT && $this->hasSubTypeComment()) {
188 6
            $type .= ' (' .  $this->getSubTypeComment() . ')';
189
        }
190 57
        if ($format > Type::SHORT_TEXT && count($this->parameters)) {
191 24
            foreach ($this->parameters as $parameter) {
192 24
                $type .= '; ' . $parameter->toString($format);
193
            }
194
        }
195 57
        return $type;
196
    }
197
198 1
    public function isExperimental(): bool
199
    {
200 1
        return substr($this->getMedia(), 0, 2) == 'x-' || substr($this->getSubType(), 0, 2) == 'x-';
201
    }
202
203 1
    public function isVendor(): bool
204
    {
205 1
        return substr($this->getSubType(), 0, 4) == 'vnd.';
206
    }
207
208 19
    public function isWildcard(): bool
209
    {
210 19
        return ($this->getMedia() === '*' && $this->getSubtype() === '*') || strpos($this->getSubtype(), '*') !== false;
211
    }
212
213 24
    public function isAlias(): bool
214
    {
215 24
        return $this->map->hasAlias($this->toString(static::SHORT_TEXT));
216
    }
217
218 1
    public function wildcardMatch(string $wildcard): bool
219
    {
220 1
        $wildcard_type = new static($wildcard);
221
222 1
        if (!$wildcard_type->isWildcard()) {
223 1
            return false;
224
        }
225
226 1
        $wildcard_re = strtr($wildcard_type->toString(static::SHORT_TEXT), [
227
            '/' => '\\/',
228
            '*' => '.*',
229
        ]);
230 1
        $subject = $this->toString(static::SHORT_TEXT);
231
232 1
        return preg_match("/$wildcard_re/", $subject) === 1;
233
    }
234
235 13
    public function buildTypesList(): array
236
    {
237 13
        $subject = $this->toString(static::SHORT_TEXT);
238
239
        // Find all types.
240 13
        $types = [];
241 13
        if (!$this->isWildcard()) {
242 13
            if ($this->map->hasType($subject)) {
243 13
                $types[] = $subject;
244
            }
245
        } else {
246 1
            foreach ($this->map->listTypes($subject) as $t) {
247 1
                $types[] = $t;
248
            }
249
        }
250
251 13
        if (!empty($types)) {
252 8
            return $types;
253
        }
254
255 5
        throw new MappingException('No MIME type found for ' . $subject . ' in map');
256
    }
257
258
    /**
259
     * Returns the unaliased MIME type.
260
     *
261
     * @return TypeInterface
262
     *   $this if the current type is not an alias, the parent type if the
263
     *   current type is an alias.
264
     */
265 18
    protected function getUnaliasedType(): TypeInterface
266
    {
267 18
        return $this->isAlias() ? new static($this->map->getAliasTypes($this->toString(static::SHORT_TEXT))[0]) : $this;
268
    }
269
270 5
    public function hasDescription(): bool
271
    {
272 5
        if ($this->descriptions === null) {
273 5
            $this->descriptions = $this->map->getTypeDescriptions($this->getUnaliasedType()->toString(static::SHORT_TEXT));
274
        }
275 5
        return isset($this->descriptions[0]);
276
    }
277
278 5
    public function getDescription(bool $include_acronym = false): string
279
    {
280 5
        if (!$this->hasDescription()) {
281 4
            throw new MappingException('No description available for type: ' . $this->toString(static::SHORT_TEXT));
282
        }
283
284 1
        $res = $this->descriptions[0];
285 1
        if ($include_acronym && isset($this->descriptions[1])) {
286 1
            $res .= ', ' . $this->descriptions[1];
287
        }
288
289 1
        return $res;
290
    }
291
292 6
    public function getAliases(): array
293
    {
294
        // Fail if the current type is an alias already.
295 6
        if ($this->isAlias()) {
296 1
            $subject = $this->toString(static::SHORT_TEXT);
297 1
            throw new MappingException("Cannot get aliases for '{$subject}', it is an alias itself");
298
        }
299
300
        // Build the array of aliases.
301 5
        $aliases = [];
302 5
        foreach ($this->buildTypesList() as $t) {
303 4
            foreach ($this->map->getTypeAliases((string) $t) as $a) {
304 3
                $aliases[$a] = $a;
305
            }
306
        }
307
308 4
        return array_keys($aliases);
309
    }
310
311 7
    public function getDefaultExtension(): string
312
    {
313 7
        $unaliased_type = $this->getUnaliasedType();
314 7
        $subject = $unaliased_type->toString(static::SHORT_TEXT);
315
316 7
        if (!$unaliased_type->isWildcard()) {
317 4
            $proceed = $this->map->hasType($subject);
318
        } else {
319 3
            $proceed = count($this->map->listTypes($subject)) === 1;
320
        }
321
322 7
        if ($proceed) {
323 3
            return $unaliased_type->getExtensions()[0];
324
        }
325
326 4
        throw new MappingException('Cannot determine default extension for type: ' . $unaliased_type->toString(static::SHORT_TEXT));
327
    }
328
329 9
    public function getExtensions(): array
330
    {
331
        // Build the array of extensions.
332 9
        $extensions = [];
333 9
        foreach ($this->getUnaliasedType()->buildTypesList() as $t) {
334 5
            foreach ($this->map->getTypeExtensions((string) $t) as $e) {
335 5
                $extensions[$e] = $e;
336
            }
337
        }
338 5
        return array_keys($extensions);
339
    }
340
}
341