Test Failed
Pull Request — master (#24)
by Filippo
12:43
created

ChunksManager::getMergeFolder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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