Completed
Push — feature-20rc1 ( 008ae2 )
by Rob
16:55
created

ContentTypeAttribute::hasSuffix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the `liip/LiipImagineBundle` project.
5
 *
6
 * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Liip\ImagineBundle\File\Attributes;
13
14
use Liip\ImagineBundle\Exception\InvalidArgumentException;
15
16
/**
17
 * @author Rob Frawley 2nd <[email protected]>
18
 */
19
class ContentTypeAttribute
20
{
21
    use AttributeTrait;
22
23
    /**
24
     * @var string
25
     */
26
    private const PREFIX_UNREGISTERED = 'x';
27
28
    /**
29
     * @var string
30
     */
31
    private const PREFIX_VENDOR = 'vnd';
32
33
    /**
34
     * @var string
35
     */
36
    private const PREFIX_PERSONAL = 'prs';
37
38
    /**
39
     * @var string
40
     */
41
    private $type;
42
43
    /**
44
     * @var string
45
     */
46
    private $subType;
47
48
    /**
49
     * @var string|null
50
     */
51
    private $prefix;
52
53
    /**
54
     * @var string|null
55
     */
56
    private $deliminator;
57
58
    /**
59
     * @var string|null
60
     */
61
    private $suffix;
62
63
    /**
64
     * @param string|null $type
65
     * @param string|null $subType
66
     * @param string|null $prefix
67
     * @param string|null $suffix
68
     * @param string|null $deliminator
69
     */
70
    public function __construct(
71
        string $type = null,
72
        string $subType = null,
73
        string $prefix = null,
74
        string $suffix = null,
75
        string $deliminator = null
76
    ) {
77
        $this->type = self::sanitize($type);
78
        $this->subType = self::sanitize($subType);
79
        $this->prefix = self::sanitizePrefix($prefix);
80
        $this->suffix = self::sanitize($suffix);
81
        $this->deliminator = self::sanitizeDeliminator($deliminator);
82
    }
83
84
    /**
85
     * @return string
86
     */
87
    public function stringify(): string
88
    {
89
        return $this->hasType() && $this->hasSubType() ? vsprintf('%s/%s%s%s%s', [
90
            $this->getType(),
91
            $this->hasPrefix() ? $this->getPrefix() : '',
92
            $this->hasPrefix() && $this->hasDeliminator() ? $this->getDeliminator() : '',
93
            $this->getSubType(),
94
            $this->hasSuffix() ? sprintf('+%s', $this->getSuffix()) : '',
95
        ]) : '';
96
    }
97
98
    /**
99
     * @return null|string
100
     */
101
    public function getType(): ?string
102
    {
103
        return $this->type;
104
    }
105
106
    /**
107
     * @return bool
108
     */
109
    public function hasType(): bool
110
    {
111
        return null !== $this->getType();
112
    }
113
114
    /**
115
     * @param string|null $type
116
     *
117
     * @return bool
118
     */
119
    public function isTypeMatch(string $type = null): bool
120
    {
121
        return $this->getType() === $type;
122
    }
123
124
    /**
125
     * @return null|string
126
     */
127
    public function getSubType(): ?string
128
    {
129
        return $this->subType;
130
    }
131
132
    /**
133
     * @return bool
134
     */
135
    public function hasSubType(): bool
136
    {
137
        return null !== $this->getSubType();
138
    }
139
140
    /**
141
     * @param string|null $subType
142
     *
143
     * @return bool
144
     */
145
    public function isSubTypeMatch(string $subType = null): bool
146
    {
147
        return $this->getSubType() === $subType;
148
    }
149
150
    /**
151
     * @return null|string
152
     */
153
    public function getPrefix(): ?string
154
    {
155
        return $this->prefix;
156
    }
157
158
    /**
159
     * @return bool
160
     */
161
    public function hasPrefix(): bool
162
    {
163
        return null !== $this->getPrefix();
164
    }
165
166
    /**
167
     * @param string|null $prefix
168
     *
169
     * @return bool
170
     */
171
    public function isPrefixMatch(string $prefix = null): bool
172
    {
173
        return $this->getPrefix() === $prefix;
174
    }
175
176
    /**
177
     * @return bool
178
     */
179
    public function isPrefixUnregistered(): bool
180
    {
181
        return $this->isPrefixMatch(self::PREFIX_UNREGISTERED);
182
    }
183
184
    /**
185
     * @return bool
186
     */
187
    public function isPrefixVendor(): bool
188
    {
189
        return $this->isPrefixMatch(self::PREFIX_VENDOR);
190
    }
191
192
    /**
193
     * @return bool
194
     */
195
    public function isPrefixPersonal(): bool
196
    {
197
        return $this->isPrefixMatch(self::PREFIX_PERSONAL);
198
    }
199
200
    /**
201
     * @return bool
202
     */
203
    public function isPrefixStandard(): bool
204
    {
205
        return false === $this->isPrefixUnregistered()
206
            && false === $this->isPrefixVendor()
207
            && false === $this->isPrefixPersonal();
208
    }
209
210
    /**
211
     * @return null|string
212
     */
213
    public function getDeliminator(): ?string
214
    {
215
        return $this->deliminator;
216
    }
217
218
    /**
219
     * @return bool
220
     */
221
    public function hasDeliminator(): bool
222
    {
223
        return null !== $this->getDeliminator();
224
    }
225
226
    /**
227
     * @param string|null $deliminator
228
     *
229
     * @return bool
230
     */
231
    public function isDeliminatorMatch(string $deliminator = null): bool
232
    {
233
        return $this->getDeliminator() === $deliminator;
234
    }
235
236
    /**
237
     * @return null|string
238
     */
239
    public function getSuffix(): ?string
240
    {
241
        return $this->suffix;
242
    }
243
244
    /**
245
     * @return bool
246
     */
247
    public function hasSuffix(): bool
248
    {
249
        return null !== $this->getSuffix();
250
    }
251
252
    /**
253
     * @param string|null $suffix
254
     *
255
     * @return bool
256
     */
257
    public function isSuffixMatch(string $suffix = null): bool
258
    {
259
        return $this->getSuffix() === $suffix;
260
    }
261
262
    /**
263
     * @param string|null $type
264
     * @param string|null $subType
265
     * @param string|null $prefix
266
     * @param string|null $suffix
267
     *
268
     * @return bool
269
     */
270
    public function isMatch(string $type = null, string $subType = null, string $prefix = null, string $suffix = null): bool
271
    {
272
        return true === $this->isTypeMatch($type ?: $this->getType())
273
            && true === $this->isSubTypeMatch($subType ?: $this->getSubType())
274
            && true === $this->isPrefixMatch($prefix ?: $this->getPrefix())
275
            && true === $this->isSuffixMatch($suffix ?: $this->getSuffix());
276
    }
277
278
    /**
279
     * @return bool
280
     */
281
    public function isValid(): bool
282
    {
283
        return true === $this->hasType()
284
            && true === $this->hasSubType()
285
            && true === self::isParsable($this->stringify());
286
    }
287
288
    /**
289
     * @param string $string
290
     *
291
     * @return array|null
292
     */
293
    public static function explodeParsable(string $string = null): ?array
294
    {
295
        $matched = 1 === preg_match(
296
                '{^(?<type>[^/]+)/((?<prefix>vnd|prs|x)(?<deliminator>\.|\-))?(?<sub_type>[^+]+?)(\+(?<suffix>.+))?$}',
297
                $string, $matches
298
            );
299
300
        $section = function (string $index) use ($matches): ?string {
301
            return empty($matches[$index]) ? null : $matches[$index];
302
        };
303
304
        return $matched ? [
305
            'type' => self::sanitize($matches['type']),
306
            'subType' => self::sanitize($matches['sub_type']),
307
            'prefix' => self::sanitizePrefix($section('prefix')),
308
            'suffix' => self::sanitize($section('suffix')),
309
            'deliminator' => self::sanitizeDeliminator($section('deliminator')),
310
        ] : null;
311
    }
312
313
    /**
314
     * @param string|null $prefix
315
     *
316
     * @return null|string
317
     */
318
    private static function sanitizePrefix(string $prefix = null): ?string
319
    {
320
        if (null === $prefix || in_array($prefix, [self::PREFIX_UNREGISTERED, self::PREFIX_VENDOR, self::PREFIX_PERSONAL], true)) {
321
            return self::sanitize($prefix);
322
        }
323
324
        throw new InvalidArgumentException(
325
            'Invalid mime type prefix "%s" provided (accepted values are "%s", "%s", and "%s").', $prefix,
326
            self::PREFIX_UNREGISTERED, self::PREFIX_VENDOR, self::PREFIX_PERSONAL
327
        );
328
    }
329
330
    /**
331
     * @param string|null $deliminator
332
     *
333
     * @return null|string
334
     */
335
    private static function sanitizeDeliminator(string $deliminator = null): ?string
336
    {
337
        if (null === $deliminator || in_array($deliminator, ['.', '-'], true)) {
338
            return self::sanitize($deliminator);
339
        }
340
341
        throw new InvalidArgumentException(
342
            'Invalid mime type deliminator "%s" provided (accepted values are "." and "-").', $deliminator
343
        );
344
    }
345
}
346