Passed
Pull Request — master (#9)
by Filippo
10:22
created

ChunksManager::handle()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
nc 2
nop 2
dl 0
loc 16
rs 9.9666
c 1
b 0
f 0
1
<?php
2
3
namespace Jobtech\LaravelChunky;
4
5
use Illuminate\Contracts\Filesystem\Factory;
6
use Illuminate\Contracts\Filesystem\Filesystem;
7
use Illuminate\Http\UploadedFile;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Str;
10
use Jobtech\LaravelChunky\Concerns\ChunksHelpers;
11
use Jobtech\LaravelChunky\Concerns\ChunkyRequestHelpers;
12
use Jobtech\LaravelChunky\Contracts\ChunksManager as ChunksManagerContract;
13
use Jobtech\LaravelChunky\Exceptions\ChunksIntegrityException;
14
use Jobtech\LaravelChunky\Http\Requests\AddChunkRequest;
15
use Jobtech\LaravelChunky\Jobs\MergeChunks;
16
use Symfony\Component\HttpFoundation\File\File;
17
18
class ChunksManager implements ChunksManagerContract
19
{
20
    use ChunksHelpers;
0 ignored issues
show
Bug introduced by
The trait Jobtech\LaravelChunky\Concerns\ChunksHelpers requires the property $output which is not provided by Jobtech\LaravelChunky\ChunksManager.
Loading history...
21
    use ChunkyRequestHelpers;
22
23
    /**
24
     * @var \Illuminate\Contracts\Filesystem\Factory
25
     */
26
    private $filesystem;
27
28
    /**
29
     * @var \Jobtech\LaravelChunky\ChunkySettings
30
     */
31
    private $settings;
32
33
    public function __construct(Factory $filesystem, ChunkySettings $settings)
34
    {
35
        $this->filesystem = $filesystem;
36
        $this->settings = $settings;
37
    }
38
39
    /**
40
     * Build the full path for chunks' folder.
41
     *
42
     * @param string $folder
43
     *
44
     * @return string
45
     */
46
    private function fullPath(string $folder): string
47
    {
48
        return $this->getChunksFolder().$folder;
49
    }
50
51
    /**
52
     * Build the merge destination path.
53
     *
54
     * @param \Illuminate\Http\UploadedFile $file
55
     *
56
     * @return string
57
     */
58
    private function destinationPath(UploadedFile $file): string
59
    {
60
        return $this->getMergeFolder().$file->getFilename();
61
    }
62
63
    /**
64
     * Build chunks destination folder from file name.
65
     *
66
     * @param string $file
67
     *
68
     * @return string
69
     */
70
    private function buildChunkFolderFor(string $file)
0 ignored issues
show
Unused Code introduced by
The method buildChunkFolderFor() 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...
71
    {
72
        return Str::slug($file);
73
    }
74
75
    /**
76
     * Dispatch a synchronous or asynchronous merge job depending on the settings.
77
     *
78
     * @param \Jobtech\LaravelChunky\Http\Requests\AddChunkRequest $request
79
     * @param string                                               $folder
80
     */
81
    private function dispatchMerge(AddChunkRequest $request, string $folder)
82
    {
83
        if (empty($connection = $this->settings->connection())) {
84
            MergeChunks::dispatchNow(
85
                $request,
86
                $folder,
87
                $this->destinationPath($request->fileInput())
88
            );
89
        } else {
90
            MergeChunks::dispatch(
91
                $request,
92
                $folder,
93
                $this->destinationPath($request->fileInput())
94
            )->onConnection($connection)
95
                ->onQueue($this->settings->queue());
96
        }
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function chunksFilesystem(): Filesystem
103
    {
104
        return $this->filesystem->disk(
105
            $this->getChunksDisk()
106
        );
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function mergeFilesystem(): Filesystem
113
    {
114
        return $this->filesystem->disk(
115
            $this->getMergeDisk()
116
        );
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122
    public function getChunksDisk(): ?string
123
    {
124
        return $this->settings
125
            ->chunksDisk();
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function getMergeDisk(): ?string
132
    {
133
        return $this->settings
134
            ->mergeDisk();
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function getChunksFolder(): string
141
    {
142
        return $this->settings
143
            ->chunksFolder();
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149
    public function getMergeFolder(): string
150
    {
151
        return $this->settings
152
            ->mergeFolder();
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function getChunksOptions(): array
159
    {
160
        return array_merge([
161
            'disk' => $this->getChunksDisk(),
162
        ], $this->settings->additionalChunksOptions());
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function getMergeOptions(): array
169
    {
170
        return array_merge([
171
            'disk' => $this->getMergeDisk(),
172
        ], $this->settings->additionalMergeOptions());
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     */
178
    public function chunks(string $folder): Collection
179
    {
180
        return collect($this->chunksFilesystem()->files($folder))
181
            ->map(function ($path) use ($folder) {
182
                $filename = str_replace($folder.DIRECTORY_SEPARATOR, '', $path);
183
                $exploded_name = explode('_', $filename);
184
                $index = array_shift($exploded_name);
185
186
                return [
187
                    'index' => intval($index),
188
                    'path'  => $path,
189
                ];
190
            })->sortBy(function ($item) {
191
                return $item['index'];
192
            });
193
    }
194
195
    /**
196
     * {@inheritdoc}
197
     */
198
    public function checkChunkIntegrity(string $folder, int $index): bool
199
    {
200
        $path = $this->fullPath($folder);
201
        $default = $this->settings->defaultIndex();
202
203
        if (! $this->chunksFilesystem()->exists($path) && $index != $default) {
204
            return false;
205
        } elseif ($this->chunksFilesystem()->exists($path)) {
206
            if (ChunkySettings::INDEX_ZERO != $default) {
207
                $index -= $default;
208
            }
209
210
            return count($this->chunksFilesystem()->files($path)) == $index;
211
        } elseif ($index == $default) {
212
            if (! $this->chunksFilesystem()->makeDirectory($path)) {
213
                throw new ChunksIntegrityException("Cannot create chunks folder $path");
214
            }
215
        }
216
217
        return true;
218
    }
219
220
    /**
221
     * {@inheritdoc}
222
     */
223
    public function addChunk(UploadedFile $file, int $index, string $folder): Chunk
224
    {
225
        // Check integrity
226
        if (! $this->checkChunkIntegrity($folder, $index)) {
227
            throw new ChunksIntegrityException("Uploaded chunk with index {$index} violates the integrity");
228
        }
229
230
        // Store chunk
231
        return Chunk::storeFrom(
232
            $file,
233
            $this->fullPath($folder),
234
            $index,
235
            $this->getChunksOptions()
236
        );
237
    }
238
239
    /**
240
     * Handles an add chunks request.
241
     *
242
     * @param \Jobtech\LaravelChunky\Http\Requests\AddChunkRequest $request
243
     * @param string|null                                          $folder
244
     *
245
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
246
     *
247
     * @return \Jobtech\LaravelChunky\Chunk
248
     */
249
    public function handle(AddChunkRequest $request, $folder = null): Chunk
250
    {
251
        $folder = $this->checkFolder($request, $folder);
252
        $chunk = $this->addChunk(
253
            $request->fileInput(),
254
            $request->indexInput(),
255
            $folder
256
        );
257
258
        if ($this->isLastIndex($request) && $this->settings->autoMerge()) {
259
            $chunk->setLast(true);
260
261
            $this->dispatchMerge($request, $this->fullPath($folder));
262
        }
263
264
        return $chunk;
265
    }
266
}
267