-
-
Notifications
You must be signed in to change notification settings - Fork 179
/
Copy pathParallelSave.php
147 lines (123 loc) · 4.45 KB
/
ParallelSave.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<?php
namespace Pion\Laravel\ChunkUpload\Save;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Str;
use Pion\Laravel\ChunkUpload\ChunkFile;
use Pion\Laravel\ChunkUpload\Config\AbstractConfig;
use Pion\Laravel\ChunkUpload\Exceptions\ChunkSaveException;
use Pion\Laravel\ChunkUpload\Exceptions\MissingChunkFilesException;
use Pion\Laravel\ChunkUpload\FileMerger;
use Pion\Laravel\ChunkUpload\Handler\AbstractHandler;
use Pion\Laravel\ChunkUpload\Handler\Traits\HandleParallelUploadTrait;
use Pion\Laravel\ChunkUpload\Storage\ChunkStorage;
/**
* Class ParallelSave.
*
* @method HandleParallelUploadTrait|AbstractHandler handler()
*/
class ParallelSave extends ChunkSave
{
/**
* Stored on construct - the file is moved and isValid will return false.
*
* @var bool
*/
protected $isFileValid;
/**
* @var array
*/
protected $foundChunks = [];
/**
* ParallelSave constructor.
*
* @param UploadedFile $file the uploaded file (chunk file)
* @param AbstractHandler|HandleParallelUploadTrait $handler the handler that detected the correct save method
* @param ChunkStorage $chunkStorage the chunk storage
* @param AbstractConfig $config the config manager
*
* @throws ChunkSaveException
*/
public function __construct(
UploadedFile $file,
AbstractHandler $handler,
ChunkStorage $chunkStorage,
AbstractConfig $config
) {
// Get current file validation - the file instance is changed
$this->isFileValid = $file->isValid();
// Handle the file upload
parent::__construct($file, $handler, $chunkStorage, $config);
}
public function isValid()
{
return $this->isFileValid;
}
/**
* Moves the uploaded chunk file to separate chunk file for merging.
*
* @param string $file Relative path to chunk
*
* @return $this
*/
protected function handleChunkFile($file)
{
// Move the uploaded file to chunk folder
$this->file->move($this->getChunkDirectory(true), $this->chunkFileName);
// Found current number of chunks to determine if we have all chunks (we cant use the
// index because order of chunks are different.
$this->foundChunks = $this->getSavedChunksFiles()->all();
$percentage = floor((count($this->foundChunks)) / $this->handler()->getTotalChunks() * 100);
// We need to update the handler with correct percentage
$this->handler()->setPercentageDone($percentage);
$this->isLastChunk = $percentage >= 100;
return $this;
}
/**
* Searches for all chunk files.
*
* @return \Illuminate\Support\Collection
*/
protected function getSavedChunksFiles()
{
$chunkFileName = preg_replace(
"/\.[\d]+\.".ChunkStorage::CHUNK_EXTENSION.'$/', '', $this->handler()->getChunkFileName()
);
return $this->chunkStorage->files(function ($file) use ($chunkFileName) {
return false === Str::contains($file, $chunkFileName);
});
}
/**
* @throws MissingChunkFilesException
* @throws ChunkSaveException
*/
protected function buildFullFileFromChunks()
{
$chunkFiles = $this->foundChunks;
if (0 === count($chunkFiles)) {
throw new MissingChunkFilesException();
}
// Sort the chunk order
natcasesort($chunkFiles);
// Get chunk files that matches the current chunk file name, also sort the chunk
// files.
$rootDirectory = $this->getChunkDirectory(true);
$finalFilePath = $rootDirectory.'./'.$this->handler()->createChunkFileName();
// Delete the file if exists
if (file_exists($finalFilePath)) {
@unlink($finalFilePath);
}
$fileMerger = new FileMerger($finalFilePath);
// Append each chunk file
foreach ($chunkFiles as $filePath) {
// Build the chunk file
$chunkFile = new ChunkFile($filePath, null, $this->chunkStorage());
// Append the data
$fileMerger->appendFile($chunkFile->getAbsolutePath());
// Delete the chunk file
$chunkFile->delete();
}
$fileMerger->close();
// Build the chunk file instance
$this->fullChunkFile = $this->createFullChunkFile($finalFilePath);
}
}