ZipAdapter::doExtract()   B
last analyzed

Complexity

Conditions 6
Paths 5

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nc 5
nop 2
dl 0
loc 33
rs 8.9777
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of Compressy.
5
 *
6
 * (c) Alchemy <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Gocobachi\Compressy\Adapter;
13
14
use Gocobachi\Compressy\Adapter\Resource\ResourceInterface;
15
use Gocobachi\Compressy\Adapter\VersionProbe\ZipVersionProbe;
16
use Gocobachi\Compressy\Archive\Archive;
17
use Gocobachi\Compressy\Archive\Member;
18
use Gocobachi\Compressy\Exception\InvalidArgumentException;
19
use Gocobachi\Compressy\Exception\NotSupportedException;
20
use Gocobachi\Compressy\Exception\RuntimeException;
21
use Gocobachi\Compressy\Parser\ParserInterface;
22
use Gocobachi\Compressy\ProcessBuilder\ProcessBuilderFactoryInterface;
23
use Gocobachi\Compressy\Resource\Resource as ZippyResource;
24
use Gocobachi\Compressy\Resource\ResourceManager;
25
use Symfony\Component\Process\Exception\ExceptionInterface as ProcessException;
26
27
/**
28
 * ZipAdapter allows you to create and extract files from archives using Zip
29
 *
30
 * @see http://www.gnu.org/software/tar/manual/tar.html
31
 */
32
class ZipAdapter extends AbstractBinaryAdapter
33
{
34
    public function __construct(
35
        ParserInterface $parser,
36
        ResourceManager $manager,
37
        ProcessBuilderFactoryInterface $inflator,
38
        ProcessBuilderFactoryInterface $deflator
39
    ) {
40
        parent::__construct($parser, $manager, $inflator, $deflator);
41
42
        $this->probe = new ZipVersionProbe($inflator, $deflator);
43
    }
44
45
    /**
46
     * @inheritdoc
47
     */
48
    protected function doCreate($path, $files, $recursive)
49
    {
50
        $files = (array) $files;
51
52
        $builder = $this
53
            ->inflator
54
            ->create();
55
56
        if (0 === count($files)) {
57
            throw new NotSupportedException('Can not create empty zip archive');
58
        }
59
60
        if ($recursive) {
61
            $builder->add('-r');
62
        }
63
64
        $builder->add($path);
65
66
        $collection = $this->manager->handle(getcwd(), $files);
67
        $builder->setWorkingDirectory($collection->getContext());
68
69
        $collection->forAll(function($i, ZippyResource $resource) use ($builder) {
70
            return $builder->add($resource->getTarget());
71
        });
72
73
        $process = $builder->getProcess();
74
75
        try {
76
            $process->run();
77
        } catch (ProcessException $e) {
78
            $this->manager->cleanup($collection);
79
            throw $e;
80
        }
81
82
        $this->manager->cleanup($collection);
83
84
        if (!$process->isSuccessful()) {
85
            throw new RuntimeException(sprintf(
86
                'Unable to execute the following command %s {output: %s}',
87
                $process->getCommandLine(),
88
                $process->getErrorOutput()
89
            ));
90
        }
91
92
        return new Archive($this->createResource($path), $this, $this->manager);
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98
    protected function doListMembers(ResourceInterface $resource)
99
    {
100
        $process = $this
101
            ->deflator
102
            ->create()
103
            ->add('-l')
104
            ->add($resource->getResource())
105
            ->getProcess();
106
107
        $process->run();
108
109
        if (!$process->isSuccessful()) {
110
            throw new RuntimeException(sprintf(
111
                'Unable to execute the following command %s {output: %s}',
112
                $process->getCommandLine(),
113
                $process->getErrorOutput()
114
            ));
115
        }
116
117
        $members = array();
118
119
        foreach ($this->parser->parseFileListing($process->getOutput() ?: '') as $member) {
120
            $members[] = new Member(
121
                $resource,
122
                $this,
123
                $member['location'],
124
                $member['size'],
125
                $member['mtime'],
126
                $member['is_dir']
127
            );
128
        }
129
130
        return $members;
131
    }
132
133
    /**
134
     * @inheritdoc
135
     */
136
    protected function doAdd(ResourceInterface $resource, $files, $recursive)
137
    {
138
        $files = (array) $files;
139
140
        $builder = $this
141
            ->inflator
142
            ->create();
143
144
        if ($recursive) {
145
            $builder->add('-r');
146
        }
147
148
        $builder
149
            ->add('-u')
150
            ->add($resource->getResource());
151
152
        $collection = $this->manager->handle(getcwd(), $files);
153
154
        $builder->setWorkingDirectory($collection->getContext());
155
156
        $collection->forAll(function($i, ZippyResource $resource) use ($builder) {
157
            return $builder->add($resource->getTarget());
158
        });
159
160
        $process = $builder->getProcess();
161
162
        try {
163
            $process->run();
164
        } catch (ProcessException $e) {
165
            $this->manager->cleanup($collection);
166
            throw $e;
167
        }
168
169
        $this->manager->cleanup($collection);
170
171
        if (!$process->isSuccessful()) {
172
            throw new RuntimeException(sprintf(
173
                'Unable to execute the following command %s {output: %s}',
174
                $process->getCommandLine(),
175
                $process->getErrorOutput()
176
            ));
177
        }
178
    }
179
180
    /**
181
     * @inheritdoc
182
     */
183
    protected function doGetDeflatorVersion()
184
    {
185
        $process = $this
186
            ->deflator
187
            ->create()
188
            ->add('-h')
189
            ->getProcess();
190
191
        $process->run();
192
193
        if (!$process->isSuccessful()) {
194
            throw new RuntimeException(sprintf(
195
                'Unable to execute the following command %s {output: %s}',
196
                $process->getCommandLine(),
197
                $process->getErrorOutput()
198
            ));
199
        }
200
201
        return $this->parser->parseDeflatorVersion($process->getOutput() ?: '');
202
    }
203
204
    /**
205
     * @inheritdoc
206
     */
207
    protected function doGetInflatorVersion()
208
    {
209
        $process = $this
210
            ->inflator
211
            ->create()
212
            ->add('-h')
213
            ->getProcess();
214
215
        $process->run();
216
217
        if (!$process->isSuccessful()) {
218
            throw new RuntimeException(sprintf(
219
                'Unable to execute the following command %s {output: %s}',
220
                $process->getCommandLine(),
221
                $process->getErrorOutput()
222
            ));
223
        }
224
225
        return $this->parser->parseInflatorVersion($process->getOutput() ?: '');
226
    }
227
228
    /**
229
     * @inheritdoc
230
     */
231
    protected function doRemove(ResourceInterface $resource, $files)
232
    {
233
        $files = (array) $files;
234
235
        $builder = $this
236
            ->inflator
237
            ->create();
238
239
        $builder
240
            ->add('-d')
241
            ->add($resource->getResource());
242
243
        if (!$this->addBuilderFileArgument($files, $builder)) {
244
            throw new InvalidArgumentException('Invalid files');
245
        }
246
247
        $process = $builder->getProcess();
248
249
        $process->run();
250
251
        if (!$process->isSuccessful()) {
252
            throw new RuntimeException(sprintf(
253
                'Unable to execute the following command %s {output: %s}',
254
                $process->getCommandLine(),
255
                $process->getErrorOutput()
256
            ));
257
        }
258
259
        return $files;
260
    }
261
262
    /**
263
     * @inheritdoc
264
     */
265
    public static function getName()
266
    {
267
        return 'zip';
268
    }
269
270
    /**
271
     * @inheritdoc
272
     */
273
    public static function getDefaultDeflatorBinaryName()
274
    {
275
        return array('unzip');
276
    }
277
278
    /**
279
     * @inheritdoc
280
     */
281
    public static function getDefaultInflatorBinaryName()
282
    {
283
        return array('zip');
284
    }
285
286
    /**
287
     * @inheritdoc
288
     */
289
    protected function doExtract(ResourceInterface $resource, $to)
290
    {
291
        if (null !== $to && !is_dir($to)) {
292
            throw new InvalidArgumentException(sprintf("%s is not a directory", $to));
293
        }
294
295
        $builder = $this
296
            ->deflator
297
            ->create();
298
299
        $builder
300
            ->add('-o')
301
            ->add($resource->getResource());
302
303
        if (null !== $to) {
304
            $builder
305
                ->add('-d')
306
                ->add($to);
307
        }
308
309
        $process = $builder->getProcess();
310
311
        $process->run();
312
313
        if (!$process->isSuccessful()) {
314
            throw new RuntimeException(sprintf(
315
                'Unable to execute the following command %s {output: %s}',
316
                $process->getCommandLine(),
317
                $process->getErrorOutput()
318
            ));
319
        }
320
321
        return new \SplFileInfo($to ?: $resource->getResource());
322
    }
323
324
    /**
325
     * @inheritdoc
326
     */
327
    protected function doExtractMembers(ResourceInterface $resource, $members, $to, $overwrite = false)
328
    {
329
        if (null !== $to && !is_dir($to)) {
330
            throw new InvalidArgumentException(sprintf("%s is not a directory", $to));
331
        }
332
333
        $members = (array) $members;
334
335
        $builder = $this
336
            ->deflator
337
            ->create();
338
339
        if ((bool) $overwrite) {
340
            $builder->add('-o');
341
        }
342
343
        $builder
344
            ->add($resource->getResource());
345
346
        if (null !== $to) {
347
            $builder
348
                ->add('-d')
349
                ->add($to);
350
        }
351
352
        if (!$this->addBuilderFileArgument($members, $builder)) {
353
            throw new InvalidArgumentException('Invalid files');
354
        }
355
356
        $process = $builder->getProcess();
357
358
        $process->run();
359
360
        if (!$process->isSuccessful()) {
361
            throw new RuntimeException(sprintf(
362
                'Unable to execute the following command %s {output: %s}',
363
                $process->getCommandLine(),
364
                $process->getErrorOutput()
365
            ));
366
        }
367
368
        return $members;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $members returns the type array which is incompatible with the return type mandated by Gocobachi\Compressy\Adap...ter::doExtractMembers() of SplFileInfo.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
369
    }
370
}
371