Test Failed
Push — master ( 2cefea...d08b1d )
by Filippo
06:04 queued 01:17
created

ChunksManager::temporaryFiles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Jobtech\LaravelChunky;
4
5
use Illuminate\Container\Container;
6
use Illuminate\Http\UploadedFile;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Str;
9
use Jobtech\LaravelChunky\Concerns\ChunkyRequestHelpers;
10
use Jobtech\LaravelChunky\Concerns\ManagerHelpers;
11
use Jobtech\LaravelChunky\Contracts\ChunksManager as ChunksManagerContract;
12
use Jobtech\LaravelChunky\Events\ChunksMerged;
13
use Jobtech\LaravelChunky\Exceptions\ChunksIntegrityException;
14
use Jobtech\LaravelChunky\Http\Requests\AddChunkRequest;
15
use Jobtech\LaravelChunky\Jobs\MergeChunks;
16
use Jobtech\LaravelChunky\Strategies\Contracts\MergeStrategy;
17
use Jobtech\LaravelChunky\Strategies\StrategyFactory;
18
use Jobtech\LaravelChunky\Support\ChunksFilesystem;
19
20
class ChunksManager implements ChunksManagerContract
21
{
22
    use ManagerHelpers;
23
    use ChunkyRequestHelpers;
24
25
    /** @var \Jobtech\LaravelChunky\ChunkySettings */
26
    private ChunkySettings $settings;
27
28
    /** @var \Jobtech\LaravelChunky\Support\ChunksFilesystem */
29
    private $chunksFilesystem;
30
31
    public function __construct(ChunkySettings $settings)
32
    {
33
        $this->settings = $settings;
34
35
        $this->chunksFilesystem = ChunksFilesystem::instance([
36
            'disk' => $settings->chunksDisk(),
37
            'folder' => $settings->chunksFolder(),
38
        ]);
39
    }
40
41
    /**
42
     * Chunks destination folder from file name slug.
43
     *
44
     * @param string $file
45
     *
46
     * @return string
47
     */
48
    private function chunkFolderNameFor(string $file)
0 ignored issues
show
Unused Code introduced by
The method chunkFolderNameFor() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
49
    {
50
        return Str::slug($file);
51
    }
52
53
    /**
54
     * Dispatch a merge event.
55
     *
56
     * @param \Jobtech\LaravelChunky\Http\Requests\AddChunkRequest $request
57
     * @param string                                               $folder
58
     */
59
    private function dispatchMerge(AddChunkRequest $request, string $folder)
60
    {
61
        // TODO: Refactor
62
63
        if (empty($connection = $this->settings->connection())) {
64
            $this->handleMerge(
65
                $this->chunksFilesystem->fullPath($folder),
66
                $request->fileInput()->getClientOriginalName(),
67
                $request->chunkSizeInput(),
68
                $request->totalSizeInput()
69
            );
70
        } else {
71
            MergeChunks::dispatch(
72
                $this->chunksFilesystem->fullPath($folder),
73
                $request->fileInput()->getClientOriginalName(),
74
                $request->chunkSizeInput(),
75
                $request->totalSizeInput()
76
            )->onConnection($connection)
77
                ->onQueue($this->settings->queue());
78
        }
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84
    public function chunksFilesystem(): ChunksFilesystem
85
    {
86
        return $this->chunksFilesystem;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function getChunksDisk(): ?string
93
    {
94
        return $this->settings
95
            ->chunksDisk();
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function getChunksFolder(): string
102
    {
103
        return $this->settings
104
            ->chunksFolder();
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function getChunksOptions(): array
111
    {
112
        return array_merge([
113
            'disk' => $this->getChunksDisk(),
114
        ], $this->settings->additionalChunksOptions());
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function validFolder(string $folder): bool
121
    {
122
        return $this->chunksFilesystem()->exists(
123
            $this->chunksFilesystem->fullPath($folder)
124
        );
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function chunks($folder = null): Collection
131
    {
132
        return $this->chunksFilesystem()->listChunks($folder);
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function chunk($chunk)
139
    {
140
        if ($chunk instanceof Chunk) {
141
            $chunk = $chunk->getPath();
142
        }
143
144
        return $this->chunksFilesystem()
145
            ->readChunk($chunk);
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function addChunk(UploadedFile $file, int $index, string $folder): Chunk
152
    {
153
        // Check integrity
154
        if (! $this->checkChunkIntegrity($folder, $index)) {
155
            throw new ChunksIntegrityException("Uploaded chunk with index {$index} violates the integrity");
156
        }
157
158
        // Store chunk
159
        return $this->chunksFilesystem->store(
160
            Chunk::create(
161
                $file,
162
                $index,
163
                $this->getChunksOptions()
164
            ),
165
            $this->chunksFilesystem->fullPath($folder),
166
            $this->getChunksOptions()
167
        );
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173
    public function deleteChunkFolder(string $folder): bool
174
    {
175
        return $this->chunksFilesystem->delete($folder);
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181
    public function deleteAllChunks($output = null): bool
182
    {
183
        $folders = $this->chunksFilesystem()->folders();
184
185
        $progress_bar = $this->hasProgressBar($output, count($folders));
186
187
        foreach ($folders as $folder) {
188
            if (! $this->deleteChunkFolder($folder)) {
189
                return false;
190
            }
191
192
            if ($progress_bar !== null) {
193
                $progress_bar->advance();
194
            }
195
        }
196
197
        if ($progress_bar !== null) {
198
            $progress_bar->finish();
199
        }
200
201
        return true;
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    public function handle(AddChunkRequest $request, $folder = null): Chunk
208
    {
209
        // Store chunk
210
        $folder = $this->checkFolder($request, $folder);
211
        $chunk = $this->addChunk(
212
            $request->fileInput(),
213
            $request->indexInput(),
214
            $folder
215
        );
216
217
        $chunk->setLast(
218
            $this->isLastIndex($request)
219
        );
220
221
        // Check merge
222
        if ($chunk->isLast() && $this->settings->autoMerge()) {
223
            $this->dispatchMerge($request, $folder);
224
        }
225
226
        return $chunk;
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232
    public function handleMerge(string $folder, string $destination, int $chunk_size, int $total_size)
233
    {
234
        if (! $this->checkFilesIntegrity($folder, $chunk_size, $total_size)) {
235
            throw new ChunksIntegrityException('Chunks total file size doesnt match with original file size');
236
        }
237
238
        $factory = StrategyFactory::getInstance();
239
        /** @var MergeStrategy $strategy */
240
        $strategy = $factory->buildFrom($this, MergeManager::getInstance());
241
        $strategy->chunksFolder($folder);
242
        $destination = $strategy->destination($destination);
243
244
        $strategy->merge();
245
246
        event(new ChunksMerged(
247
            $strategy, $destination
248
        ));
249
250
        return $destination;
251
    }
252
253
    /**
254
     * {@inheritdoc}
255
     */
256
    public function checkChunkIntegrity(string $folder, int $index): bool
257
    {
258
        $path = $this->chunksFilesystem()->fullPath($folder);
259
        $default = $this->settings->defaultIndex();
260
261
        if (! $this->chunksFilesystem()->exists($path) && $index != $default) {
262
            return false;
263
        } elseif ($this->chunksFilesystem()->exists($path)) {
264
            if (ChunkySettings::INDEX_ZERO != $default) {
265
                $index -= $default;
266
            }
267
268
            return $this->chunksFilesystem()->chunksCount($path) == $index;
269
        } elseif ($index == $default) {
270
            if (! $this->chunksFilesystem()->makeDirectory($path)) {
271
                throw new ChunksIntegrityException("Cannot create chunks folder $path");
272
            }
273
        }
274
275
        return true;
276
    }
277
278
    /**
279
     * {@inheritdoc}
280
     */
281
    public function checkFilesIntegrity(string $folder, int $chunk_size, int $total_size): bool
282
    {
283
        $total = 0;
284
        $chunks = $this->chunks($folder);
285
286
        foreach ($chunks as $chunk) {
287
            $size = $this->chunksFilesystem->chunkSize($chunk->getPath());
288
289
            if ($size < $chunk_size && ! $chunk->isLast()) {
290
                return false;
291
            }
292
293
            $total += $size;
294
        }
295
296
        return $total >= $total_size;
297
    }
298
299
    public static function getInstance(): ChunksManager
300
    {
301
        return Container::getInstance()->make(ChunksManagerContract::class);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Illuminate\Contai...s\ChunksManager::class) returns the type Jobtech\LaravelChunky\Contracts\ChunksManager which includes types incompatible with the type-hinted return Jobtech\LaravelChunky\ChunksManager.
Loading history...
302
    }
303
}
304