Passed
Push — master ( 6248da...8ce640 )
by László
02:40
created

ResumableJsHandler::saveChunk()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4.054

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 17
cts 20
cp 0.85
rs 9.36
c 0
b 0
f 0
cc 4
nc 4
nop 4
crap 4.054
1
<?php
2
3
namespace CodingSocks\UploadHandler\Driver;
4
5
use Closure;
6
use CodingSocks\UploadHandler\Helper\ChunkHelpers;
7
use CodingSocks\UploadHandler\Identifier\Identifier;
8
use CodingSocks\UploadHandler\Range\ResumableJsRange;
9
use CodingSocks\UploadHandler\Response\PercentageJsonResponse;
10
use CodingSocks\UploadHandler\StorageConfig;
11
use Illuminate\Http\JsonResponse;
12
use Illuminate\Http\Request;
13
use Illuminate\Http\UploadedFile;
14
use InvalidArgumentException;
15
use Symfony\Component\HttpFoundation\Response;
16
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
17
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
18
19
class ResumableJsHandler extends BaseHandler
20
{
21 1
    use ChunkHelpers;
22
23
    /**
24
     * @var string
25
     */
26
    private $fileParam;
27
28
    /**
29
     * @var \CodingSocks\UploadHandler\Identifier\Identifier
30
     */
31
    private $identifier;
32
33
    /**
34
     * @var string
35
     */
36
    private $uploadMethod;
37
38
    /**
39
     * @var string
40
     */
41
    private $testMethod;
42
43
    /**
44
     * @var string
45
     */
46
    private $parameterNamespace;
47
48
    /**
49
     * @var string[]
50
     */
51
    private $parameterNames;
52
53
    /**
54
     * ResumableJsDriver constructor.
55
     *
56
     * @param array $config
57
     * @param \CodingSocks\UploadHandler\Identifier\Identifier $identifier
58
     */
59 79
    public function __construct($config, Identifier $identifier)
60
    {
61 79
        $this->fileParam = $config['param'];
62 79
        $this->identifier = $identifier;
63
64 79
        $this->uploadMethod = $config['upload-method'];
65 79
        $this->testMethod = $config['test-method'];
66
67 79
        $this->parameterNamespace = $config['parameter-namespace'];
68 79
        $this->parameterNames = $config['parameter-names'];
69 79
    }
70
71
    /**
72
     * @inheritDoc
73
     */
74 73
    public function handle(Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
75
    {
76 73
        if ($this->isRequestMethodIn($request, [$this->testMethod])) {
77 6
            return $this->resume($request, $config);
78
        }
79
80 67
        if ($this->isRequestMethodIn($request, [$this->uploadMethod])) {
81 43
            return $this->save($request, $config, $fileUploaded);
82
        }
83
84 24
        throw new MethodNotAllowedHttpException([
85 24
            $this->uploadMethod,
86 24
            $this->testMethod,
87
        ]);
88
    }
89
90
    /**
91
     * @param \Illuminate\Http\Request $request
92
     * @param \CodingSocks\UploadHandler\StorageConfig $config
93
     *
94
     * @return \Symfony\Component\HttpFoundation\Response
95
     */
96 6
    public function resume(Request $request, StorageConfig $config): Response
97
    {
98 6
        $this->validateChunkRequest($request);
99
100
        try {
101 6
            $range = new ResumableJsRange(
102 6
                $request->query,
103 6
                $this->buildParameterName('chunk-number'),
104 6
                $this->buildParameterName('total-chunks'),
105 6
                $this->buildParameterName('chunk-size'),
106 6
                $this->buildParameterName('total-size')
107
            );
108
        } catch (InvalidArgumentException $e) {
109
            throw new BadRequestHttpException($e->getMessage(), $e);
110
        }
111
112 6
        $uid = $this->identifier->generateIdentifier($request->query($this->buildParameterName('identifier')));
0 ignored issues
show
Bug introduced by
It seems like $request->query($this->b...eterName('identifier')) targeting Illuminate\Http\Concerns...ractsWithInput::query() can also be of type array or null; however, CodingSocks\UploadHandle...r::generateIdentifier() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
113 6
        $chunkname = $this->buildChunkname($range);
114
115 6
        if (! $this->chunkExists($config, $uid, $chunkname)) {
116 3
            return new Response('', Response::HTTP_NO_CONTENT);
117
        }
118
119 3
        return new JsonResponse(['OK']);
120
    }
121
122
    /**
123
     * @param \Illuminate\Http\Request $request
124
     * @param \CodingSocks\UploadHandler\StorageConfig $config
125
     * @param \Closure|null $fileUploaded
126
     *
127
     * @return \Symfony\Component\HttpFoundation\Response
128
     */
129 43
    public function save(Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
130
    {
131 43
        $file = $request->file($this->fileParam);
132
133 43
        $this->validateUploadedFile($file);
0 ignored issues
show
Bug introduced by
It seems like $file defined by $request->file($this->fileParam) on line 131 can also be of type array; however, CodingSocks\UploadHandle...:validateUploadedFile() does only seem to accept null|object<Illuminate\Http\UploadedFile>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
134
135 37
        $this->validateChunkRequest($request);
136
137 12
        return $this->saveChunk($file, $request, $config, $fileUploaded);
0 ignored issues
show
Bug introduced by
It seems like $file defined by $request->file($this->fileParam) on line 131 can also be of type array or null; however, CodingSocks\UploadHandle...eJsHandler::saveChunk() does only seem to accept object<Illuminate\Http\UploadedFile>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
138
    }
139
140
    /**
141
     * @param \Illuminate\Http\Request $request
142
     */
143 43
    private function validateChunkRequest(Request $request): void
144
    {
145 43
        $validation = [];
146
147 43
        foreach ($this->parameterNames as $key => $_) {
148 43
            $validation[$this->buildParameterName($key)] = 'required';
149
        }
150
151 43
        $request->validate($validation);
0 ignored issues
show
Bug introduced by
The call to validate() misses a required argument $...$params.

This check looks for function calls that miss required arguments.

Loading history...
152 18
    }
153
154
    /**
155
     * @param \Illuminate\Http\UploadedFile $file
156
     * @param \Illuminate\Http\Request $request
157
     * @param \CodingSocks\UploadHandler\StorageConfig $config
158
     * @param \Closure|null $fileUploaded
159
     *
160
     * @return \Symfony\Component\HttpFoundation\Response
161
     */
162 12
    private function saveChunk(UploadedFile $file, Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
163
    {
164
        try {
165 12
            $range = new ResumableJsRange(
166 12
                $request,
167 12
                $this->buildParameterName('chunk-number'),
168 12
                $this->buildParameterName('total-chunks'),
169 12
                $this->buildParameterName('chunk-size'),
170 12
                $this->buildParameterName('total-size')
171
            );
172
        } catch (InvalidArgumentException $e) {
173
            throw new BadRequestHttpException($e->getMessage(), $e);
174
        }
175
176 12
        $weakId = $request->post($this->buildParameterName('identifier'));
177 12
        $uid = $this->identifier->generateIdentifier($weakId);
0 ignored issues
show
Bug introduced by
It seems like $weakId defined by $request->post($this->bu...eterName('identifier')) on line 176 can also be of type array or null; however, CodingSocks\UploadHandle...r::generateIdentifier() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
178
179 12
        $chunks = $this->storeChunk($config, $range, $file, $uid);
180
181 12
        if (!$range->isFinished($chunks)) {
182 6
            return new PercentageJsonResponse($range->getPercentage($chunks));
183
        }
184
185 6
        $targetFilename = $file->hashName();
186
187 6
        $path = $this->mergeChunks($config, $chunks, $targetFilename);
188
189 6
        if ($config->sweep()) {
190
            $this->deleteChunkDirectory($config, $uid);
191
        }
192
193 6
        $this->triggerFileUploadedEvent($config->getDisk(), $path, $fileUploaded);
194
195 6
        return new PercentageJsonResponse(100);
196
    }
197
198
    /**
199
     * @param $key string
200
     *
201
     * @return string
202
     */
203 43
    private function buildParameterName(string $key): string
204
    {
205 43
        if (! array_key_exists($key, $this->parameterNames)) {
206
            throw new InvalidArgumentException(sprintf('`%s` is an invalid key for parameter name', $key));
207
        }
208
209 43
        return $this->parameterNamespace . $this->parameterNames[$key];
210
    }
211
}
212