Passed
Push — develop ( 728be8...044541 )
by Eric
13:09 queued 45s
created

Generator::generateMapping()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 18
nc 10
nop 0
dl 0
loc 33
rs 8.4444
c 0
b 0
f 0
ccs 19
cts 19
cp 1
crap 8
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Mimey - PHP package for converting file extensions to MIME types and vice versa.
7
 *
8
 * @author    Eric Sizemore <[email protected]>
9
 * @version   2.0.0
10
 * @copyright (C) 2023-2024 Eric Sizemore
11
 * @license   The MIT License (MIT)
12
 *
13
 * Copyright (C) 2023-2024 Eric Sizemore<https://www.secondversion.com/>.
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a copy
16
 * of this software and associated documentation files (the "Software"), to
17
 * deal in the Software without restriction, including without limitation the
18
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19
 * sell copies of the Software, and to permit persons to whom the Software is
20
 * furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in
23
 * all copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
 * THE SOFTWARE.
32
 */
33
34
/**
35
 * Esi\Mimey is a fork of Elephox\Mimey (https://github.com/elephox-dev/mimey) which is:
36
 *     Copyright (c) 2022 Ricardo Boss
37
 * Elephox\Mimey is a fork of ralouphie/mimey (https://github.com/ralouphie/mimey) which is:
38
 *     Copyright (c) 2016 Ralph Khattar
39
 */
40
41
namespace Esi\Mimey\Mapping;
42
43
use Esi\Mimey\Interface\MimeType;
44
45
// Exceptions
46
use JsonException;
47
48
// Functions & constants
49
use function preg_replace;
50
use function ucfirst;
51
use function ucwords;
52
use function str_replace;
53
use function sprintf;
54
use function file_get_contents;
55
use function dirname;
56
use function json_encode;
57
use function array_unique;
58
use function trim;
59
use function explode;
60
use function count;
61
use function array_values;
62
use function array_filter;
63
64
use const JSON_THROW_ON_ERROR;
65
use const JSON_PRETTY_PRINT;
66
67
/**
68
 * Generates a mapping for use in the MimeTypes class.
69
 *
70
 * Reads text in the format of httpd's mime.types and generates a PHP array containing the mappings.
71
 *
72
 * The psalm-type looks gnarly, but it covers just about everything.
73
 *
74
 * @psalm-type MimeTypeMap = array{
75
 *    mimes?: array<
76
 *        non-empty-string|string, list<non-empty-string>|array<int<0, max>, string>
77
 *    >|non-empty-array<
78
 *        non-falsy-string|string, non-empty-array<0, non-falsy-string>|array<int<0, max>, string>
79
 *    >,
80
 *    extensions?: array<
81
 *        non-empty-string, list<non-empty-string>
82
 *     >|non-empty-array<
83
 *        string|non-falsy-string, array<int<0, max>, string>|non-empty-array<0, non-falsy-string>
84
 *    >|array<
85
 *        string, array<int<0, max>, string>
86
 *    >
87
 * }
88
 */
89
class Generator
90
{
91
    /**
92
     * @var  MimeTypeMap|array{}  $mapCache
1 ignored issue
show
Bug introduced by
The type Esi\Mimey\Mapping\MimeTypeMap was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
93
     */
94
    protected array $mapCache = [];
95
96
    /**
97
     * Create a new generator instance with the given mime.types text.
98
     *
99
     * @param  non-empty-string  $mimeTypesText  The text from the mime.types file.
100
     */
101 3
    public function __construct(protected string $mimeTypesText) {}
102
103
    /**
104
     * Read the given mime.types text and return a mapping compatible with the MimeTypes class.
105
     *
106
     * @return  MimeTypeMap|array{}  The mapping.
107
     */
108 3
    public function generateMapping(): array
109
    {
110 3
        if ($this->mapCache !== []) {
111 1
            return $this->mapCache;
112
        }
113
114 3
        $lines = explode("\n", $this->mimeTypesText);
115
116 3
        foreach ($lines as $line) {
117
            /** @var string $line **/
118 3
            $line = preg_replace('~#.*~', '', $line);
119 3
            $line = trim($line);
120
121 3
            $parts = $line !== '' ? array_values(array_filter(explode("\t", $line))) : [];
122
123 3
            if (count($parts) === 2) {
124 3
                $mime       = trim($parts[0]);
125 3
                $extensions = explode(' ', $parts[1]);
126
127 3
                foreach ($extensions as $extension) {
128 3
                    $extension = trim($extension);
129
130 3
                    if ($mime !== '' && $extension !== '') {
131 3
                        $this->mapCache['mimes'][$extension][] = $mime;
132 3
                        $this->mapCache['extensions'][$mime][] = $extension;
133 3
                        $this->mapCache['mimes'][$extension]   = array_unique($this->mapCache['mimes'][$extension]);
134 3
                        $this->mapCache['extensions'][$mime]   = array_unique($this->mapCache['extensions'][$mime]);
135
                    }
136
                }
137
            }
138
        }
139
140 3
        return $this->mapCache;
141
    }
142
143
    /**
144
     * Generate the JSON from the mapCache.
145
     *
146
     * @param   bool              $minify  Whether to minify the generated JSON.
147
     * @return  non-empty-string
148
     *
149
     * @throws JsonException
150
     */
151 1
    public function generateJson(bool $minify = true): string
152
    {
153 1
        return json_encode($this->generateMapping(), flags: JSON_THROW_ON_ERROR | ($minify ? 0 : JSON_PRETTY_PRINT));
154
    }
155
156
    /**
157
     * Generates the PHP Enum found in `dist`.
158
     *
159
     * @param   non-empty-string         $classname
160
     * @param   non-empty-string         $namespace
161
     * @return  non-empty-string|string
162
     */
163 1
    public function generatePhpEnum(string $classname = 'MimeType', string $namespace = 'Esi\Mimey'): string
164
    {
165 1
        $values = [
166 1
            'namespace'       => $namespace,
167 1
            'classname'       => $classname,
168 1
            'interface_usage' => $namespace !== __NAMESPACE__ ? ('use ' . MimeType::class . " as MimeTypeInterface;\n") : '',
169 1
            'cases'           => '',
170 1
            'type2ext'        => '',
171 1
            'ext2type'        => '',
172 1
        ];
173
174
        /** @var string $stub **/
175 1
        $stub = file_get_contents(dirname(__DIR__, 2) . '/stubs/mimeType.php.stub');
176
177 1
        $mapping = $this->generateMapping();
178 1
        $nameMap = [];
179
180 1
        foreach ($mapping['extensions'] as $mime => $extensions) { // @phpstan-ignore-line
181 1
            $nameMap[$mime] = $this->convertMimeTypeToCaseName($mime);
182
183 1
            $values['cases'] .= sprintf("    case %s = '%s';\n", $nameMap[$mime], $mime);
184 1
            $values['type2ext'] .= sprintf("            self::%s => '%s',\n", $nameMap[$mime], $extensions[0]);
185
        }
186
187 1
        foreach ($mapping['mimes'] as $extension => $mimes) { // @phpstan-ignore-line
188 1
            $values['ext2type'] .= sprintf("            '%s' => self::%s,\n", $extension, $nameMap[$mimes[0]]);
189
        }
190
191 1
        foreach ($values as $name => $value) {
192 1
            $stub = str_replace("%$name%", $value, $stub);
193
        }
194
195 1
        return $stub;
196
    }
197
198
    /**
199
     * @param non-empty-string|string $mimeType
200
     */
201 1
    protected function convertMimeTypeToCaseName(string $mimeType): string
202
    {
203
        // @phpstan-ignore-next-line
204 1
        return preg_replace('/([\/\-_+.]+)/', '', ucfirst(ucwords($mimeType, '/-_+.')));
205
    }
206
}
207