Passed
Push — master ( 420f5e...d683e4 )
by Mario
03:38
created

WorksWithFileUploads::handleMultipleFileUploads()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 24
rs 9.7666
c 0
b 0
f 0
cc 4
nc 4
nop 5
1
<?php
2
3
namespace RafflesArgentina\ResourceController\Traits;
4
5
use Lang;
6
use Storage;
7
8
use Symfony\Component\HttpFoundation\File\UploadedFile;
9
use Symfony\Component\HttpFoundation\File\Exception\UploadException;
10
11
use Illuminate\Database\Eloquent\Model;
12
use Illuminate\Database\Eloquent\Relations\Relation;
13
use Illuminate\Http\Request;
14
15
trait WorksWithFileUploads
16
{
17
    /**
18
     * Upload request files and update or create relations handling array type request data.
19
     *
20
     * @param Request     $request      The Request object.
21
     * @param Model       $model        The eloquent model.
22
     * @param string|null $relativePath The file uploads relative path.
23
     *
24
     * @return Request
25
     */
26
    public function uploadFiles(Request $request, Model $model, $relativePath = null)
27
    {
28
        if (!$relativePath) {
29
            $relativePath = $this->getDefaultRelativePath();
30
        }
31
32
        $fileBag = $request->files;
33
        foreach ($fileBag->all() as $paramName => $uploadedFiles) {
34
            $attributes = $model->getAttributes();
35
            if (array_key_exists($paramName, $attributes)) {
36
                $this->handleNonMultipleFileUploads($model, $paramName, $uploadedFiles, $relativePath);
37
            } else {
38
                $this->handleMultipleFileUploads($request, $model, $paramName, $uploadedFiles, $relativePath);
39
            }
40
        }
41
42
        return $request;
43
    }
44
45
    /**
46
     * Get the name of the file.
47
     *
48
     * @param UploadedFile $uploadedFile The UploadedFile object.
49
     *
50
     * @return string
51
     */
52
    protected function getFilename(UploadedFile $uploadedFile)
53
    {
54
        $extension = $uploadedFile->guessExtension();
55
        $filename = str_random().'.'.$extension;
56
57
        return $filename;
58
    }
59
60
    /**
61
     * Get storage path for the configured driver.
62
     *
63
     * @param string $relativePath The relative path.
64
     *
65
     * @return string
66
     */
67
    protected function getStoragePath($relativePath)
68
    {
69
        return Storage::disk()->getDriver()->getAdapter()->getPathPrefix().$relativePath;
70
    }
71
72
    /**
73
     * Move the uploaded file to specified filename and destination.
74
     *
75
     * @param UploadedFile $uploadedFile The UploadedFile object.
76
     * @param string       $filename     The name of the file.
77
     * @param string       $destination  The file destination.
78
     *
79
     * @return \Symfony\Component\HttpFoundation\File\File
80
     */
81
    protected function moveUploadedFile($uploadedFile, $filename, $destination)
82
    {
83
        return $uploadedFile->move($destination, $filename);
84
    }
85
86
    /**
87
     * Get location column.
88
     *
89
     * @return string
90
     */
91
    protected function getLocationColumn()
92
    {
93
        return 'location';
94
    }
95
96
    /**
97
     * Get default relative path.
98
     *
99
     * @return string
100
     */
101
    protected function getDefaultRelativePath()
102
    {
103
        return 'uploads/';
104
    }
105
106
    /**
107
     * Handle multiple file uploads.
108
     *
109
     * @param Request $request       The Request object.
110
     * @param Model   $model         The eloquent model.
111
     * @param string  $paramName     The name of the file param.
112
     * @param array   $uploadedFiles An array of UploadedFile objects.
113
     * @param string  $relativePath  The file uploads relative path.
114
     *
115
     * @return void
116
     */
117
    protected function handleMultipleFileUploads(Request $request, Model $model, $paramName, $uploadedFiles, $relativePath)
118
    {
119
        $this->_checkFileRelationExists($model, $paramName);
120
121
        $data = $request->attributes->all();
122
        $fileBag = $request->files;
123
        foreach ($uploadedFiles as $index => $uploadedFile) {
124
            if (!$uploadedFile->isValid()) {
125
                throw new UploadException($uploadedFile->getError());
126
            }
127
128
            $filename = $this->getFilename($uploadedFile);
129
            $storagePath = $this->getStoragePath($relativePath);
130
            $this->moveUploadedFile($uploadedFile, $filename, $storagePath);
131
132
            $location = $relativePath.$filename;
133
134
            if (count($fileBag->get($paramName)) > 1) {
135
                $data[$paramName][$index] = [$this->getLocationColumn() => $location];
136
            } else {
137
                $data[$paramName][$this->getLocationColumn()] = $location;
138
            }
139
140
            $request->merge($data);
141
        }
142
    }
143
144
    /**
145
     * Handle non-multiple file uploads.
146
     *
147
     * @param Model        $model        The eloquent model.
148
     * @param string       $paramName    The name of the file param.
149
     * @param UploadedFile $uploadedFile The UploadedFile object.
150
     * @param string       $relativePath The file uploads relative path.
151
     *
152
     * @return void
153
     */
154
    protected function handleNonMultipleFileUploads(Model $model, $paramName, $uploadedFile, $relativePath)
155
    {
156
        if (!$uploadedFile->isValid()) {
157
            throw new UploadException($uploadedFile->getError());
158
        }
159
160
        $filename = $this->getFilename($uploadedFile);
161
        $destination = $this->getStoragePath($relativePath);
162
        $this->moveUploadedFile($uploadedFile, $filename, $destination);
163
164
        $location = $relativePath.$filename;
165
166
        $model->{$paramName} = $location;
167
        $model->save();
168
    }
169
170
    /**
171
     * Throw an exception if request file is not named after an existent relation.
172
     *
173
     * @param Model  $model        The eloquent model.
174
     * @param string $relationName The eloquent relation name.
175
     *
176
     * @throws UploadException
177
     *
178
     * @return void
179
     */
180
    private function _checkFileRelationExists(Model $model, $relationName)
181
    {
182
        if ((!method_exists($model, $relationName) && !$model->{$relationName}() instanceof Relation)) {
183
            if (Lang::has('resource-controller.filerelationinexistent')) {
184
                $message = trans('resource-controller.filerelationinexistent', ['relationName' => $relationName]);
185
            } else {
186
                $message = "Request file '{$relationName}' is not named after an existent relation.";
187
            }
188
            throw new UploadException($message);
189
        }
190
    }
191
}
192