Passed
Pull Request — master (#71)
by László
07:10
created

BlueimpBaseHandler::save()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.1158

Importance

Changes 0
Metric Value
dl 0
loc 36
ccs 15
cts 18
cp 0.8333
rs 9.0328
c 0
b 0
f 0
nc 8
cc 5
nop 3
crap 5.1158
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\ContentRange;
9
use CodingSocks\UploadHandler\Response\PercentageJsonResponse;
10
use CodingSocks\UploadHandler\StorageConfig;
11
use Illuminate\Http\JsonResponse;
12
use Illuminate\Http\Request;
13
use Illuminate\Support\Arr;
14
use Illuminate\Support\Facades\Storage;
15
use Illuminate\Support\Str;
16
use InvalidArgumentException;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
19
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
20
21
class BlueimpBaseHandler extends BaseHandler
22
{
23 1
    use ChunkHelpers;
24
25
    /**
26
     * @var string
27
     */
28
    private $fileParam;
29
30
    /**
31
     * @var \CodingSocks\UploadHandler\Identifier\Identifier
32
     */
33
    private $identifier;
34
35
    /**
36
     * BlueimpDriver constructor.
37
     *
38
     * @param array $config
39
     * @param \CodingSocks\UploadHandler\Identifier\Identifier $identifier
40
     */
41 13
    public function __construct($config, Identifier $identifier)
42
    {
43 13
        $this->fileParam = $config['param'];
44 13
        $this->identifier = $identifier;
45 13
    }
46
47
    /**
48
     * {@inheritDoc}
49
     */
50 11
    public function handle(Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
51
    {
52 11
        if ($this->isRequestMethodIn($request, [Request::METHOD_HEAD, Request::METHOD_OPTIONS])) {
53 1
            return $this->info();
54
        }
55
56 10
        if ($this->isRequestMethodIn($request, [Request::METHOD_GET])) {
57 3
            return $this->download($request, $config);
58
        }
59
60 7
        if ($this->isRequestMethodIn($request, [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH])) {
61 6
            return $this->save($request, $config, $fileUploaded);
62
        }
63
64 1
        if ($this->isRequestMethodIn($request, [Request::METHOD_DELETE])) {
65 1
            return $this->delete($request, $config);
66
        }
67
68
        throw new MethodNotAllowedHttpException([
69
            Request::METHOD_HEAD,
70
            Request::METHOD_OPTIONS,
71
            Request::METHOD_GET,
72
            Request::METHOD_POST,
73
            Request::METHOD_PUT,
74
            Request::METHOD_PATCH,
75
            Request::METHOD_DELETE,
76
        ]);
77
    }
78
79
    /**
80
     * @return \Symfony\Component\HttpFoundation\Response
81
     */
82 1
    public function info(): Response
83
    {
84 1
        return new JsonResponse([], Response::HTTP_OK, [
85 1
            'Pragma' => 'no-cache',
86
            'Cache-Control' => 'no-store, no-cache, must-revalidate',
87
            'Content-Disposition' => 'inline; filename="files.json"',
88
            'X-Content-Type-Options' => 'nosniff',
89
            'Vary' => 'Accept',
90
        ]);
91
    }
92
93
    /**
94
     * @param \Illuminate\Http\Request $request
95
     * @param \CodingSocks\UploadHandler\StorageConfig $config
96
     *
97
     * @return \Symfony\Component\HttpFoundation\Response
98
     */
99 3
    public function download(Request $request, StorageConfig $config): Response
100
    {
101 3
        $download = $request->query('download', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
102 3
        if ($download !== false) {
103 2
            $uid = $request->query($this->fileParam);
104
105 2
            return $this->fileResponse($uid, $config);
0 ignored issues
show
Bug introduced by
It seems like $uid defined by $request->query($this->fileParam) on line 103 can also be of type array or null; however, CodingSocks\UploadHandle...Handler::fileResponse() 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...
106
        }
107
108 1
        $request->validate([
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...
109 1
            $this->fileParam => 'required',
110 1
            'totalSize' => 'required',
111
        ]);
112
113 1
        $originalFilename = $request->query($this->fileParam);
114 1
        $totalSize = $request->query('totalSize');
115 1
        $uid = $this->identifier->generateFileIdentifier($totalSize, $originalFilename);
0 ignored issues
show
Documentation introduced by
$totalSize is of type string|array|null, but the function expects a double.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $originalFilename defined by $request->query($this->fileParam) on line 113 can also be of type array or null; however, CodingSocks\UploadHandle...enerateFileIdentifier() 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...
116
117 1
        if (!$this->chunkExists($config, $uid)) {
118
            return new JsonResponse([
119
                'file' => null,
120
            ]);
121
        }
122
123 1
        $chunk = Arr::last($this->chunks($config, $uid));
124 1
        $size = explode('-', basename($chunk))[1] + 1;
125
126 1
        return new JsonResponse([
127
            'file' => [
128 1
                'name' => $originalFilename,
129 1
                'size' => $size,
130
            ],
131
        ]);
132
    }
133
134
    /**
135
     * @param \Illuminate\Http\Request $request
136
     * @param \CodingSocks\UploadHandler\StorageConfig $config
137
     * @param \Closure|null $fileUploaded
138
     *
139
     * @return \Symfony\Component\HttpFoundation\Response
140
     */
141 6
    public function save(Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
142
    {
143 6
        $file = $request->file($this->fileParam);
144
145 6
        if (null === $file) {
146 1
            $file = Arr::first($request->file(Str::plural($this->fileParam), []));
0 ignored issues
show
Documentation introduced by
$request->file(\Illumina...s->fileParam), array()) is of type object<Illuminate\Http\UploadedFile>|array|null, but the function expects a object<Illuminate\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
147
        }
148
149 6
        $this->validateUploadedFile($file);
150
151
        try {
152 4
            $range = new ContentRange($request->headers);
153
        } catch (InvalidArgumentException $e) {
154
            throw new BadRequestHttpException($e->getMessage(), $e);
155
        }
156
157 4
        $uid = $this->identifier->generateFileIdentifier($range->getTotal(), $file->getClientOriginalName());
158
159 4
        $chunks = $this->storeChunk($config, $range, $file, $uid);
160
161 4
        if (!$range->isLast()) {
162 2
            return new PercentageJsonResponse($range->getPercentage());
163
        }
164
165 2
        $targetFilename = $file->hashName();
166
167 2
        $path = $this->mergeChunks($config, $chunks, $targetFilename);
168
169 2
        if ($config->sweep()) {
170
            $this->deleteChunkDirectory($config, $uid);
171
        }
172
173 2
        $this->triggerFileUploadedEvent($config->getDisk(), $path, $fileUploaded);
174
175 2
        return new PercentageJsonResponse(100);
176
    }
177
178
    /**
179
     * @param \Illuminate\Http\Request $request
180
     * @param \CodingSocks\UploadHandler\StorageConfig $config
181
     *
182
     * @return \Symfony\Component\HttpFoundation\Response
183
     */
184 1 View Code Duplication
    public function delete(Request $request, StorageConfig $config): Response
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
185
    {
186 1
        $filename = $request->post($this->fileParam);
187 1
        $path = $config->getMergedDirectory() . '/' . $filename;
188 1
        Storage::disk($config->getDisk())->delete($path);
189
190 1
        return new Response();
191
    }
192
}
193