UnzipTransformer::needsTransforming()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3
1
<?php
2
3
namespace TreeHouse\Feeder\Resource\Transformer;
4
5
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
6
use TreeHouse\Feeder\Exception\TransportException;
7
use TreeHouse\Feeder\Resource\FileResource;
8
use TreeHouse\Feeder\Resource\ResourceCollection;
9
use TreeHouse\Feeder\Resource\ResourceInterface;
10
use TreeHouse\Feeder\Transport\FileTransport;
11
12
class UnzipTransformer implements ResourceTransformerInterface
13
{
14
    /**
15
     * @var string
16
     */
17
    protected $target;
18
19
    /**
20
     * @var string[]
21
     */
22
    protected $files;
23
24
    /**
25
     * @param string|array $files  The filename(s) in the zip file to return
26
     * @param string       $target Target directory, defaults to the directory in which the zip is located
27
     *
28
     * @throws \InvalidArgumentException
29
     */
30 12
    public function __construct($files, $target = null)
31
    {
32 12
        if (is_string($files)) {
33 2
            $files = [$files];
34 2
        }
35
36 12
        if (!is_array($files)) {
37 2
            throw new \InvalidArgumentException(
38 2
                sprintf(
39 2
                    'Expecting a file path or array of file paths as first argument, got "%s"',
40 2
                    json_encode($files)
41 2
                )
42 2
            );
43
        }
44
45 10
        $this->files = $files;
46 10
        $this->target = $target;
47 10
    }
48
49
    /**
50
     * @inheritdoc
51
     */
52 8
    public function transform(ResourceInterface $resource, ResourceCollection $collection)
53
    {
54 8
        if ($this->needsUnzipping($resource)) {
55 6
            $this->unzip($resource);
56 6
        }
57
58 8
        $resources = [];
59 8
        foreach ($this->files as $file) {
60 8
            $targetFile = $this->getTargetFile($resource, $file);
61 8
            if (!file_exists($targetFile)) {
62
                throw new TransportException(sprintf('File "%s" was not found in the archive', $targetFile));
63
            }
64
65 8
            $transport = FileTransport::create($targetFile);
66 8
            $transport->setDestinationDir($this->getTargetDir($resource));
67 8
            $resources[] = new FileResource($transport);
68 8
        }
69
70 8
        $collection->unshiftAll($resources);
71
72 8
        return $collection->shift();
73
    }
74
75
    /**
76
     * @inheritdoc
77
     */
78 8
    public function needsTransforming(ResourceInterface $resource)
79
    {
80 8
        $resourceFile = (string) $resource->getTransport();
81
82
        // don't transform unzipped files
83 8
        foreach ($this->files as $file) {
84 8
            if ($resourceFile === $this->getTargetFile($resource, $file)) {
85 8
                return false;
86
            }
87 8
        }
88
89
        // check if file type is actually zip
90 8
        return $this->isExtractable($resource);
91
    }
92
93
    /**
94
     * @param ResourceInterface $resource
95
     *
96
     * @return bool
97
     */
98 8
    protected function needsUnzipping(ResourceInterface $resource)
99
    {
100 8
        foreach ($this->files as $file) {
101 8
            $targetFile = $this->getTargetFile($resource, $file);
102 8
            if (!file_exists($targetFile) || ($resource->getFile()->getMTime() > filemtime($targetFile))) {
103 6
                return true;
104
            }
105 2
        }
106
107 2
        return false;
108
    }
109
110
    /**
111
     * @param ResourceInterface $resource
112
     *
113
     * @return bool
114
     */
115 8
    protected function isExtractable(ResourceInterface $resource)
116
    {
117 8
        $guesser = MimeTypeGuesser::getInstance();
118
119 8
        return $guesser->guess($resource->getFile()->getPathname()) === 'application/zip';
120
    }
121
122
    /**
123
     * @param ResourceInterface $resource
124
     */
125 4
    protected function unzip(ResourceInterface $resource)
126
    {
127 4
        $zip = new \ZipArchive();
128 4
        $zip->open($resource->getFile()->getPathname());
129 4
        $zip->extractTo($this->getTargetDir($resource));
130 4
    }
131
132
    /**
133
     * @param ResourceInterface $resource
134
     *
135
     * @return string
136
     */
137 8
    protected function getTargetDir(ResourceInterface $resource)
138
    {
139 8
        return $this->target ?: $resource->getFile()->getPath();
140
    }
141
142
    /**
143
     * @param ResourceInterface $resource
144
     * @param string            $filename
145
     *
146
     * @return string
147
     */
148 8
    protected function getTargetFile(ResourceInterface $resource, $filename)
149
    {
150 8
        return sprintf('%s/%s', $this->getTargetDir($resource), $filename);
151
    }
152
}
153