Passed
Push — master ( e9611b...a3681d )
by f
13:07
created

AlchemyZippy   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 325
Duplicated Lines 0 %

Test Coverage

Coverage 9.01%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 112
c 1
b 0
f 0
dl 0
loc 325
rs 9.0399
ccs 10
cts 111
cp 0.0901
wmc 42

21 Methods

Rating   Name   Duplication   Size   Complexity  
A getFileContent() 0 4 1
A getFileNames() 0 3 1
A getArchiveInformation() 0 15 3
A getFileStream() 0 4 1
A extractFiles() 0 11 3
A isFileExists() 0 3 1
A addFileFromString() 0 8 1
A getMember() 0 3 1
A getFileData() 0 4 1
A extractArchive() 0 8 2
A __construct() 0 5 1
A deleteFiles() 0 12 3
A addFiles() 0 17 4
A init() 0 6 3
A isInstalled() 0 4 1
B checkFormatSupport() 0 22 7
A checkAdapterFor() 0 7 2
A getSupportedFormats() 0 7 1
A createArchive() 0 19 3
A getDescription() 0 3 1
A getInstallationInstruction() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like AlchemyZippy 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 AlchemyZippy, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace wapmorgan\UnifiedArchive\Drivers;
3
4
use Alchemy\Zippy\Archive\Member;
0 ignored issues
show
Bug introduced by
The type Alchemy\Zippy\Archive\Member 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...
5
use Alchemy\Zippy\Exception\NoAdapterOnPlatformException;
0 ignored issues
show
Bug introduced by
The type Alchemy\Zippy\Exception\...pterOnPlatformException 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...
6
use Alchemy\Zippy\Zippy;
0 ignored issues
show
Bug introduced by
The type Alchemy\Zippy\Zippy 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...
7
use Exception;
8
use wapmorgan\UnifiedArchive\ArchiveEntry;
9
use wapmorgan\UnifiedArchive\ArchiveInformation;
10
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
11
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
12
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
13
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
14
use wapmorgan\UnifiedArchive\Formats;
15
use wapmorgan\UnifiedArchive\Drivers\BasicDriver;
16
17
class AlchemyZippy extends BasicDriver
18
{
19
    const TYPE = self::TYPE_UTILITIES;
20
21
    /**
22
     * @var Zippy
23
     */
24
    protected static $zippy;
25
26
    /**
27
     * @var string
28
     */
29
    protected $fileName;
30
31
    /**
32
     * @var \Alchemy\Zippy\Archive\ArchiveInterface
0 ignored issues
show
Bug introduced by
The type Alchemy\Zippy\Archive\ArchiveInterface 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...
33
     */
34
    protected $archive;
35
36
    /**
37
     * @var array
38
     */
39
    protected $files;
40
41
    /**
42
     * @var string
43
     */
44
    protected $format;
45
46
    /**
47
     * @var Member[]
48
     */
49
    protected $members;
50
51
    /**
52 1
     * @inheritDoc
53
     */
54
    public static function getDescription()
55 1
    {
56
        return 'php-library and console programs';
57
    }
58
59
    public static function isInstalled()
60
    {
61
        self::init();
62 4
        return static::$zippy !== false;
63
    }
64 4
65 4
    /**
66
     * @inheritDoc
67
     */
68 4
    public static function getInstallationInstruction()
69
    {
70
        self::init();
71
        return 'install library [alchemy/zippy]: `composer require alchemy/zippy`' . "\n"  . ' and console programs (tar, zip): `apt install tar zip` - depends on OS'
72
            . "\n" . 'If you install SevenZip and AlchemyZippy:' . "\n" .
73
            '1. You should specify symfony/console version before installation to any **3.x.x version**: `composer require symfony/process:~3.4`, because they require different `symfony/process` versions.' . "\n" .
74 4
            '2. Install archive7z version 4.0.0: `composer require gemorroj/archive7z:~4.0`';
75
    }
76 4
77
    /**
78 4
     * @return mixed|void
79 4
     */
80
    public static function getSupportedFormats()
81
    {
82
        return [
83
            Formats::ZIP,
84
            Formats::TAR,
85
            Formats::TAR_GZIP,
86
            Formats::TAR_BZIP,
87
        ];
88
    }
89
90
    protected static function init()
91
    {
92
        if (!class_exists('\Alchemy\Zippy\Zippy'))
93
            static::$zippy = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type Alchemy\Zippy\Zippy of property $zippy.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
94
        else if (static::$zippy === null)
95
            static::$zippy = Zippy::load();
96
    }
97
98
    /**
99
     * @param $format
100
     * @return array
101
     */
102
    public static function checkFormatSupport($format)
103
    {
104
        static::init();
105
106
        if (static::$zippy === false)
0 ignored issues
show
introduced by
The condition static::zippy === false is always false.
Loading history...
107
            return [];
108
109
        switch ($format) {
110
            case Formats::TAR_BZIP:
111
            case Formats::TAR:
112
            case Formats::TAR_GZIP:
113
            case Formats::ZIP:
114
                if (static::checkAdapterFor($format) === false) {
115
                    return [];
116
                }
117
118
                return [
119
                    BasicDriver::OPEN,
120
                    BasicDriver::EXTRACT_CONTENT,
121
                    BasicDriver::APPEND,
122
                    BasicDriver::DELETE,
123
                    BasicDriver::CREATE,
124
                ];
125
        }
126
    }
127
128
    /**
129
     * @param $format
130
     * @param $adapter
131
     * @return bool
132
     */
133
    protected static function checkAdapterFor($format, &$adapter = null)
134
    {
135
        try {
136
            $adapter = static::$zippy->getAdapterFor($format);
137
            return true;
138
        } catch (NoAdapterOnPlatformException $e) {
139
            return false;
140
        }
141
    }
142
143
    /**
144
     * @param array $files
145
     * @param string $archiveFileName
146
     * @param int $archiveFormat
147
     * @param int $compressionLevel
148
     * @param null $password
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
149
     * @param $fileProgressCallable
150
     * @return int
151
     * @throws ArchiveCreationException
152
     * @throws UnsupportedOperationException
153
     */
154
    public static function createArchive(
155
        array $files,
156
        $archiveFileName,
157
        $archiveFormat,
158
        $compressionLevel = self::COMPRESSION_AVERAGE,
159
        $password = null,
160
        $fileProgressCallable = null
161
    )
162
    {
163
        if ($password !== null) {
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
164
            throw new UnsupportedOperationException('AlchemyZippy could not encrypt an archive');
165
        }
166
167
        try {
168
            $archive = static::$zippy->create($archiveFileName, $files);
0 ignored issues
show
Unused Code introduced by
The assignment to $archive is dead and can be removed.
Loading history...
169
        } catch (Exception $e) {
170
            throw new ArchiveCreationException('Could not create archive: '.$e->getMessage(), $e->getCode(), $e);
171
        }
172
        return count($files);
173
    }
174
175
    /**
176
     * @inheritDoc
177
     */
178
    public function __construct($archiveFileName, $format, $password = null)
179
    {
180
        $this->fileName = $archiveFileName;
181
        $this->format = $format;
182
        $this->archive = static::$zippy->open($archiveFileName);
183
    }
184
185
    /**
186
     * @inheritDoc
187
     */
188
    public function getArchiveInformation()
189
    {
190
        $this->files = [];
191
        $information = new ArchiveInformation();
192
193
        foreach ($this->archive->getMembers() as $member) {
194
            if ($member->isDir())
195
                continue;
196
197
            $this->files[] = $information->files[] = str_replace('\\', '/', $member->getLocation());
198
            $this->members[str_replace('\\', '/', $member->getLocation())] = $member;
199
            $information->compressedFilesSize += (int)$member->getSize();
200
            $information->uncompressedFilesSize += (int)$member->getSize();
201
        }
202
        return $information;
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208
    public function getFileNames()
209
    {
210
        return $this->files;
211
    }
212
213
    /**
214
     * @inheritDoc
215
     */
216
    public function isFileExists($fileName)
217
    {
218
        return in_array($fileName, $this->files);
219
    }
220
221
    protected function getMember($fileName)
222
    {
223
        return $this->members[$fileName];
224
225
//        foreach ($this->archive->getMembers() as $member) {
226
//            if ($member->isDir())
227
//                continue;
228
//            if ($member->getLocation() === $fileName)
229
//                return $member;
230
//        }
231
//        return null;
232
    }
233
234
    /**
235
     * @inheritDoc
236
     */
237
    public function getFileData($fileName)
238
    {
239
        $member = $this->getMember($fileName);
240
        return new ArchiveEntry($member->getLocation(), $member->getSize(), $member->getSize(), strtotime($member->getLastModifiedDate()), true);
241
    }
242
243
    /**
244
     * @inheritDoc
245
     */
246
    public function getFileContent($fileName)
247
    {
248
        $member = $this->getMember($fileName);
249
        return (string)$member;
250
    }
251
252
    /**
253
     * @inheritDoc
254
     */
255
    public function getFileStream($fileName)
256
    {
257
        $member = $this->getMember($fileName);
258
        return self::wrapStringInStream((string)$member);
259
    }
260
261
    /**
262
     * @inheritDoc
263
     */
264
    public function extractFiles($outputFolder, array $files)
265
    {
266
        try {
267
            foreach ($files as $file) {
268
                $member = $this->getMember($file);
269
                $member->extract($outputFolder);
270
            }
271
        } catch (Exception $e) {
272
            throw new ArchiveExtractionException('Could not extract archive: '.$e->getMessage(), $e->getCode(), $e);
273
        }
274
        return count($files);
275
    }
276
277
    /**
278
     * @inheritDoc
279
     */
280
    public function extractArchive($outputFolder)
281
    {
282
        try {
283
            $this->archive->extract($outputFolder);
284
        } catch (Exception $e) {
285
            throw new ArchiveExtractionException('Could not extract archive: '.$e->getMessage(), $e->getCode(), $e);
286
        }
287
        return count($this->files);
288
    }
289
290
    /**
291
     * @inheritDoc
292
     */
293
    public function deleteFiles(array $files)
294
    {
295
        $members = [];
296
        try {
297
            foreach ($files as $file) {
298
                $members[] = $this->getMember($file);
299
            }
300
            $this->archive->removeMembers($members);
301
        } catch (Exception $e) {
302
            throw new ArchiveModificationException('Could not remove files from archive: '.$e->getMessage(), $e->getCode(), $e);
303
        }
304
        return count($files);
305
    }
306
307
    /**
308
     * @inheritDoc
309
     */
310
    public function addFiles(array $files)
311
    {
312
        $added = 0;
313
        try {
314
            foreach ($files as $localName => $filename) {
315
                if (is_null($filename)) {
316
//                    $this->archive->addEmptyDir($localName);
317
                } else {
318
                    $this->archive->addMembers([$filename => $localName]);
319
                    $added++;
320
                }
321
            }
322
        } catch (Exception $e) {
323
            throw new ArchiveModificationException('Could not add file "'.$filename.'": '.$e->getMessage(), $e->getCode());
324
        }
325
        $this->getArchiveInformation();
326
        return $added;
327
    }
328
329
    /**
330
     * @param string $inArchiveName
331
     * @param string $content
332
     * @return bool
333
     */
334
    public function addFileFromString($inArchiveName, $content)
335
    {
336
        $fp = fopen('php://memory', 'w');
337
        fwrite($fp, $content);
338
        rewind($fp);
339
        $this->archive->addMembers([$inArchiveName => $fp]);
340
        fclose($fp);
341
        return true;
342
    }
343
}