Passed
Push — master ( c11447...ba145f )
by mon
02:14
created

MapUpdater::loadMapFromFreedesktopFile()   F

Complexity

Conditions 16
Paths 306

Size

Total Lines 71
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 16.2764

Importance

Changes 0
Metric Value
cc 16
eloc 39
c 0
b 0
f 0
nc 306
nop 1
dl 0
loc 71
rs 3.4083
ccs 35
cts 39
cp 0.8974
crap 16.2764

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace FileEye\MimeMap;
4
5
use FileEye\MimeMap\Map\EmptyMap;
6
use FileEye\MimeMap\Map\MimeMapInterface;
7
8
/**
9
 * Compiles the MIME type to file extension map.
10
 */
11
class MapUpdater
12
{
13
    /**
14
     * The default, empty, base map to use for update.
15
     */
16
    const DEFAULT_BASE_MAP_CLASS = EmptyMap::class;
17
18
    /**
19
     * The map object to update.
20
     *
21
     * @var MimeMapInterface
22
     */
23
    protected $map;
24
25
    /**
26
     * Returns the default file with override commands to be executed.
27
     *
28
     * The YAML file provides an array of calls to MapHandler methods to be
29
     * executed sequentially. Each entry indicates the method to be invoked and
30
     * the arguments to be passed in.
31
     *
32
     * @return string
33
     */
34 1
    public static function getDefaultMapBuildFile(): string
35
    {
36 1
        return __DIR__ . '/../resources/default_map_build.yml';
37
    }
38
39
    /**
40
     * Returns the map object being updated.
41
     *
42
     * @return MimeMapInterface
43
     */
44 8
    public function getMap(): MimeMapInterface
45
    {
46 8
        return $this->map;
47
    }
48
49
    /**
50
     * Sets the map object to update.
51
     *
52
     * @param string $map_class
53
     *   The FQCN of the map to be updated.
54
     *
55
     * @return $this
56
     */
57 8
    public function selectBaseMap(string $map_class): MapUpdater
58
    {
59 8
        $this->map = MapHandler::map($map_class);
60 8
        $this->map->backup();
61 8
        return $this;
62
    }
63
64
    /**
65
     * Loads a new type-to-extension map reading from a file in Apache format.
66
     *
67
     * @param string $source_file
68
     *   The source file. The file must conform to the format in the Apache
69
     *   source code repository file where MIME types and file extensions are
70
     *   associated.
71
     *
72
     * @return string[]
73
     *   An array of error messages.
74
     *
75
     * @throws \RuntimeException
76
     *   If it was not possible to access the file.
77
     */
78 3
    public function loadMapFromApacheFile(string $source_file): array
79
    {
80 3
        $errors = [];
81
82 3
        $lines = @file($source_file);
83 3
        if ($lines === false) {
84
            throw new \RuntimeException("Failed accessing {$source_file}");
85
        }
86 3
        foreach ($lines as $line) {
87 2
            if ($line[0] == '#') {
88 2
                continue;
89
            }
90 2
            $line = preg_replace("#\\s+#", ' ', trim($line));
91 2
            if (is_string($line)) {
92 2
                $parts = explode(' ', $line);
93 2
                $type = array_shift($parts);
94 2
                foreach ($parts as $extension) {
95 2
                    $this->map->addTypeExtensionMapping($type, $extension);
96
                }
97
            } else {
98
                $errors[] = "Error processing line: $line";
99
            }
100
        }
101 3
        $this->map->sort();
102
103 3
        return $errors;
104
    }
105
106
    /**
107
     * Loads a new type-to-extension map reading from a Freedesktop.org file.
108
     *
109
     * @param string $source_file
110
     *   The source file. The file must conform to the format in the
111
     *   Freedesktop.org database.
112
     *
113
     * @return string[]
114
     *   An array of error messages.
115
     */
116 3
    public function loadMapFromFreedesktopFile(string $source_file): array
117
    {
118 3
        $errors = [];
119
120 3
        $contents = file_get_contents($source_file);
121 3
        if ($contents === false) {
122
            $errors[] = 'Failed loading file ' . $source_file;
123
            return $errors;
124
        }
125
126 3
        $xml = simplexml_load_string($contents);
127 3
        if ($xml === false) {
128
            $errors[] = 'Malformed XML in file ' . $source_file;
129
            return $errors;
130
        }
131
132 3
        $aliases = [];
133
134 3
        foreach ($xml as $node) {
135 2
            $exts = [];
136 2
            foreach ($node->glob as $glob) {
137 2
                $pattern = (string) $glob['pattern'];
138 2
                if ('*' != $pattern[0] || '.' != $pattern[1]) {
139 2
                    continue;
140
                }
141 2
                $exts[] = substr($pattern, 2);
142
            }
143 2
            if (empty($exts)) {
144 2
                continue;
145
            }
146
147 2
            $type = (string) $node['type'];
148
149
            // Add description.
150 2
            if (isset($node->comment)) {
151 2
                $this->map->addTypeDescription($type, (string) $node->comment[0]);
152
            }
153 2
            if (isset($node->acronym)) {
154 2
                $acronym = (string) $node->acronym;
155 2
                if (isset($node->{'expanded-acronym'})) {
156 2
                    $acronym .= ': ' . (string) $node->{'expanded-acronym'};
157
                }
158 2
                $this->map->addTypeDescription($type, $acronym);
159
            }
160
161
            // Add extensions.
162 2
            foreach ($exts as $ext) {
163 2
                $this->map->addTypeExtensionMapping($type, $ext);
164
            }
165
166
            // All aliases are accumulated and processed at the end of the
167
            // cycle to allow proper consistency checking on the completely
168
            // developed list of types.
169 2
            foreach ($node->alias as $alias) {
170 2
                $aliases[$type][] = (string) $alias['type'];
171
            }
172
        }
173
174
        // Add all the aliases, provide logging of errors.
175 3
        foreach ($aliases as $type => $a) {
176 2
            foreach ($a as $alias) {
177
                try {
178 2
                    $this->map->addTypeAlias($type, $alias);
179 1
                } catch (MappingException $e) {
180 1
                    $errors[] = $e->getMessage();
181
                }
182
            }
183
        }
184 3
        $this->map->sort();
185
186 3
        return $errors;
187
    }
188
189
    /**
190
     * Applies to the map an array of overrides.
191
     *
192
     * @param array<int,array{0: string, 1: array<string>}> $overrides
193
     *   The overrides to be applied.
194
     *
195
     * @return string[]
196
     *   An array of error messages.
197
     */
198 3
    public function applyOverrides(array $overrides): array
199
    {
200 3
        $errors = [];
201
202 3
        foreach ($overrides as $command) {
203
            try {
204 3
                $callable = [$this->map, $command[0]];
205 3
                assert(is_callable($callable));
206 3
                call_user_func_array($callable, $command[1]);
207 1
            } catch (MappingException $e) {
208 1
                $errors[] = $e->getMessage();
209
            }
210
        }
211 3
        $this->map->sort();
212
213 3
        return $errors;
214
    }
215
216
    /**
217
     * Updates the map at a destination PHP file.
218
     *
219
     * @return $this
220
     */
221 1
    public function writeMapToPhpClassFile(string $file): MapUpdater
222
    {
223 1
        $content = file_get_contents($file);
224 1
        if ($content === false) {
225
            throw new \RuntimeException('Failed loading file ' . $file);
226
        }
227
228 1
        $newContent = preg_replace(
229
            '#protected static \$map = (.+?);#s',
230 1
            "protected static \$map = " . preg_replace('/\s+$/m', '', var_export($this->map->getMapArray(), true)) . ";",
231
            $content
232
        );
233 1
        file_put_contents($file, $newContent);
234
235 1
        return $this;
236
    }
237
}
238