Passed
Push — master ( 3f67b7...07fe76 )
by f
02:48
created

Formats   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Test Coverage

Coverage 55.93%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 56
eloc 157
c 2
b 0
f 0
dl 0
loc 310
ccs 66
cts 118
cp 0.5593
rs 5.5199

12 Methods

Rating   Name   Duplication   Size   Complexity  
A checkFormatSupport() 0 13 4
A canEncrypt() 0 3 1
A canStream() 0 3 1
A canOpen() 0 14 4
A canCreate() 0 3 1
A canUpdate() 0 3 1
A getFormatDriver() 0 15 5
A getFormatMimeType() 0 3 1
A getFormatsReport() 0 18 2
A canAppend() 0 3 1
A retrieveAllFormats() 0 10 4
D detectArchiveFormat() 0 72 31

How to fix   Complexity   

Complex Class

Complex classes like Formats often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Formats, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace wapmorgan\UnifiedArchive;
3
4
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedArchiveException;
5
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
6
use wapmorgan\UnifiedArchive\Drivers\AlchemyZippy;
7
use wapmorgan\UnifiedArchive\Drivers\Cab;
8
use wapmorgan\UnifiedArchive\Drivers\Iso;
9
use wapmorgan\UnifiedArchive\Drivers\OneFile\Gzip;
0 ignored issues
show
Bug introduced by
The type wapmorgan\UnifiedArchive\Drivers\OneFile\Gzip 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...
10
use wapmorgan\UnifiedArchive\Drivers\OneFile\Lzma;
11
use wapmorgan\UnifiedArchive\Drivers\OneFile\Bzip;
12
use wapmorgan\UnifiedArchive\Drivers\Rar;
13
use wapmorgan\UnifiedArchive\Drivers\SevenZip;
14
use wapmorgan\UnifiedArchive\Formats\Tar;
0 ignored issues
show
Bug introduced by
The type wapmorgan\UnifiedArchive\Formats\Tar 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...
15
use wapmorgan\UnifiedArchive\Drivers\TarByPear;
16
use wapmorgan\UnifiedArchive\Drivers\TarByPhar;
17
use wapmorgan\UnifiedArchive\Drivers\Zip;
18
19
class Formats
20
{
21
    // archived and compressed
22
    const ZIP = 'zip';
23
    const SEVEN_ZIP = '7z';
24
    const RAR = 'rar';
25
    const CAB = 'cab';
26
    const TAR = 'tar';
27
    const TAR_GZIP = 'tgz';
28
    const TAR_BZIP = 'tbz2';
29
    const TAR_LZMA = 'txz';
30
    const TAR_LZW = 'tar.z';
31
    const ARJ = 'arj';
32
33
    // compressed
34
    const GZIP = 'gz';
35
    const BZIP = 'bz2';
36
    const LZMA = 'xz';
37
38
    // non-usual archives
39
    const UEFI = 'uefi';
40
    const GPT = 'gpt';
41
    const MBR = 'mbr';
42
    const MSI = 'msi';
43
    const ISO = 'iso';
44
    const DMG = 'dmg';
45
    const UDF = 'udf';
46
    const RPM = 'rpm';
47
    const DEB = 'deb';
48
49
    /**
50
     * @var string[] List of archive format drivers
51
     */
52
    public static $drivers = [
53
        Zip::class,
54
        Rar::class,
55
        Gzip::class,
56
        Bzip::class,
57
        Lzma::class,
58
        Iso::class,
59
        Cab::class,
60
        TarByPhar::class,
61
        SevenZip::class,
62
        AlchemyZippy::class,
63
        TarByPear::class,
64
    ];
65
66
    /** @var array<string, array<string>> List of all available types with their drivers */
67
    protected static $availableFormats;
68
69
    /** @var array List of all drivers with formats and support-state */
70
    protected static $formatsSupport;
71
72
    protected static $mimeTypes = [
73
        'application/zip' => Formats::ZIP,
74
        'application/x-7z-compressed' => Formats::SEVEN_ZIP,
75
        'application/x-rar' => Formats::RAR,
76
        'application/zlib' => Formats::GZIP,
77
        'application/gzip'  => Formats::GZIP,
78
        'application/x-gzip' => Formats::GZIP,
79
        'application/x-bzip2' => Formats::BZIP,
80
        'application/x-lzma' => Formats::LZMA,
81
        'application/x-iso9660-image' => Formats::ISO,
82
        'application/vnd.ms-cab-compressed' => Formats::CAB,
83
        'application/x-tar' => Formats::TAR,
84
        'application/x-gtar' => Formats::TAR_GZIP,
85
    ];
86
87
    /**
88
     * Detect archive type by its filename or content
89
     *
90
     * @param string $fileName Archive filename
91
     * @param bool $contentCheck Whether archive type can be detected by content
92
     * @return string|bool One of UnifiedArchive type constants OR false if type is not detected
93
     */
94 36
    public static function detectArchiveFormat($fileName, $contentCheck = true)
95
    {
96
        // by file name
97 36
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
0 ignored issues
show
Bug introduced by
It seems like pathinfo($fileName, wapm...ive\PATHINFO_EXTENSION) can also be of type array; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

97
        $ext = strtolower(/** @scrutinizer ignore-type */ pathinfo($fileName, PATHINFO_EXTENSION));
Loading history...
98
99 36
        if (stripos($fileName, '.tar.') !== false && preg_match('~\.(?<ext>tar\.(gz|bz2|xz|z))$~', strtolower($fileName), $match)) {
100 12
            switch ($match['ext']) {
101 12
                case 'tar.gz':
102 4
                    return Formats::TAR_GZIP;
103 8
                case 'tar.bz2':
104 4
                    return Formats::TAR_BZIP;
105 4
                case 'tar.xz':
106 4
                    return Formats::TAR_LZMA;
107
                case 'tar.z':
108
                    return Formats::TAR_LZW;
109
            }
110
        }
111
112
        switch ($ext) {
113 24
            case 'zip':
114 18
            case 'jar':
115 6
                return Formats::ZIP;
116 18
            case '7z':
117 4
                return Formats::SEVEN_ZIP;
118 14
            case 'rar':
119 1
                return Formats::RAR;
120 13
            case 'gz':
121
                return Formats::GZIP;
122 13
            case 'bz2':
123
                return Formats::BZIP;
124 13
            case 'xz':
125
                return Formats::LZMA;
126 13
            case 'iso':
127 4
                return Formats::ISO;
128 9
            case 'cab':
129
                return Formats::CAB;
130 9
            case 'tar':
131 6
                return Formats::TAR;
132 3
            case 'tgz':
133 1
                return Formats::TAR_GZIP;
134 2
            case 'tbz2':
135 1
                return Formats::TAR_BZIP;
136 1
            case 'txz':
137 1
                return Formats::TAR_LZMA;
138
            case 'arj':
139
                return Formats::ARJ;
140
            case 'efi':
141
                return Formats::UEFI;
142
            case 'gpt':
143
                return Formats::GPT;
144
            case 'mbr':
145
                return Formats::MBR;
146
            case 'msi':
147
                return Formats::MSI;
148
            case 'dmg':
149
                return Formats::DMG;
150
            case 'rpm':
151
                return Formats::RPM;
152
            case 'deb':
153
                return Formats::DEB;
154
            case 'udf':
155
                return Formats::UDF;
156
        }
157
158
        // by file content
159
        if ($contentCheck) {
160
            $mime_type = mime_content_type($fileName);
161
            if (isset(static::$mimeTypes[$mime_type]))
162
                return static::$mimeTypes[$mime_type];
163
        }
164
165
        return false;
166
    }
167
168
    /**
169
     * Checks whether specific archive type can be opened with current system configuration
170
     *
171
     * @param string $format One of predefined archive types (class constants)
172
     * @return bool
173
     */
174 25
    public static function canOpen($format)
175
    {
176 25
        static::retrieveAllFormats();
177
178 25
        if (!isset(static::$formatsSupport[$format])) {
179 6
            static::$formatsSupport[$format] = [];
180 6
            foreach (static::$availableFormats[$format] as $format_driver) {
181 6
                if ($format_driver::checkFormatSupport($format))
182
                {
183 6
                    static::$formatsSupport[$format][] = $format_driver;
184
                }
185
            }
186
        }
187 25
        return !empty(static::$formatsSupport[$format]);
188
    }
189
190
    /**
191
     * Checks whether specified archive can be streamed
192
     *
193
     * @param string $format One of predefined archive types (class constants)
194
     * @return bool
195
     */
196
    public static function canStream($format)
197
    {
198
        return static::checkFormatSupport($format, 'canStream');
199
    }
200
201
    /**
202
     * Checks whether specified archive can be created
203
     *
204
     * @param string $format One of predefined archive types (class constants)
205
     * @return bool
206
     */
207 2
    public static function canCreate($format)
208
    {
209 2
        return static::checkFormatSupport($format, 'canCreateArchive');
210
    }
211
212
    /**
213
     * Checks whether specified archive can be created
214
     *
215
     * @param string $format One of predefined archive types (class constants)
216
     * @return bool
217
     */
218 2
    public static function canAppend($format)
219
    {
220 2
        return static::checkFormatSupport($format, 'canAddFiles');
221
    }
222
223
    /**
224
     * Checks whether specified archive can be created
225
     *
226
     * @param string $format One of predefined archive types (class constants)
227
     * @return bool
228
     */
229 2
    public static function canUpdate($format)
230
    {
231 2
        return static::checkFormatSupport($format, 'canDeleteFiles');
232
    }
233
234
    /**
235
     * Checks whether specified archive can be created
236
     *
237
     * @param string $format One of predefined archive types (class constants)
238
     * @return bool
239
     */
240
    public static function canEncrypt($format)
241
    {
242
        return static::checkFormatSupport($format, 'canEncrypt');
243
    }
244
245
    /**
246
     * @param string $format
247
     * @param string $function
248
     * @return bool
249
     */
250 4
    protected static function checkFormatSupport($format, $function)
251
    {
252
253 4
        static::retrieveAllFormats();
254 4
        if (!static::canOpen($format))
255
            return false;
256
257 4
        foreach (static::$formatsSupport[$format] as $driver) {
258 4
            if ($driver::$function($format))
259 4
                return true;
260
        }
261
262
        return false;
263
    }
264
265
    /**
266
     * @param string $format
267
     * @param bool $createAbility
268
     * @return mixed
269
     */
270 25
    public static function getFormatDriver($format, $createAbility = false)
271
    {
272 25
        static::retrieveAllFormats();
273
274 25
        if (!static::canOpen($format))
275
            throw new UnsupportedArchiveException('Unsupported archive type: '.$format.' of archive ');
276
277 25
        if (!$createAbility)
278 23
            return current(static::$formatsSupport[$format]);
279
280 2
        foreach (static::$formatsSupport[$format] as $driver) {
281 2
            if ($driver::canCreateArchive($format))
282 2
                return $driver;
283
        }
284
        return false;
285
    }
286
287
    /**
288
     * @param $format
289
     * @return false|int|string
290
     */
291
    public static function getFormatMimeType($format)
292
    {
293
        return array_search($format, static::$mimeTypes, true);
294
    }
295
296
    public static function getFormatsReport()
297
    {
298
        static::retrieveAllFormats();
299
        $result = [];
300
301
        foreach (static::$availableFormats as $format => $formatDrivers) {
302
            $result[$format] = [
303
                'open' => static::canOpen($format),
304
                'stream' => static::canStream($format),
305
                'create' => static::canCreate($format),
306
                'append' => static::canAppend($format),
307
                'update' => static::canUpdate($format),
308
                'encrypt' => static::canEncrypt($format),
309
                'drivers' => static::$formatsSupport[$format],
310
            ];
311
        }
312
313
        return $result;
314
    }
315
316
    /**
317
     * Tests system configuration
318
     */
319 25
    protected static function retrieveAllFormats()
320
    {
321 25
        if (static::$availableFormats === null) {
0 ignored issues
show
introduced by
The condition static::availableFormats === null is always false.
Loading history...
322 1
            static::$availableFormats = [];
323 1
            foreach (Formats::$drivers as $handlerClass)
324
            {
325 1
                $handler_formats = $handlerClass::getSupportedFormats();
326 1
                foreach ($handler_formats as $handler_format)
327
                {
328 1
                    static::$availableFormats[$handler_format][] = $handlerClass;
329
                }
330
            }
331
        }
332
    }
333
}