Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — crud-uploads ( f5e93a...469ece )
by Pedro
11:36
created

HandleRepeatableUploads::retrieveRepeatableFiles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\Uploaders\Support\Traits;
4
5
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\Storage;
9
10
trait HandleRepeatableUploads
11
{
12
    /**
13
     * Indicates if this uploader instance is inside a repeatable container.
14
     *
15
     * @var bool
16
     */
17
    public $isRepeatable = false;
18
19
    /**
20
     * When inside a repeatable container, indicates the container name.
21
     *
22
     * @var string|null
23
     */
24
    public $repeatableContainerName = null;
25
26
    /**
27
     * A function that uploaders can implement if the uploader is also supported in repeatable containers.
28
     *
29
     * @param  Model  $entry
30
     * @param  mixed  $values
31
     * @return mixed
32
     */
33
    public function uploadRepeatableFile(Model $entry, $values = null)
0 ignored issues
show
Unused Code introduced by
The parameter $entry is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
    public function uploadRepeatableFile(/** @scrutinizer ignore-unused */ Model $entry, $values = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $values is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
    public function uploadRepeatableFile(Model $entry, /** @scrutinizer ignore-unused */ $values = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
34
    {
35
    }
36
37
    /**
38
     * Set the repeatable attribute to true in the uploader and the
39
     * corresponding container name.
40
     *
41
     * @param  string  $repeatableContainerName
42
     * @return self
43
     */
44
    public function repeats(string $repeatableContainerName): self
45
    {
46
        $this->isRepeatable = true;
47
48
        $this->repeatableContainerName = $repeatableContainerName;
49
50
        return $this;
51
    }
52
53
    /**
54
     * Returns the repeatable container name.
55
     *
56
     * @return void
57
     */
58
    public function getRepeatableContainerName()
59
    {
60
        return $this->repeatableContainerName;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->repeatableContainerName also could return the type string which is incompatible with the documented return type void.
Loading history...
61
    }
62
63
    /**
64
     * Prepares the repeatable values from request and send them to the corresponding saving process.
65
     *
66
     * @param  Model  $entry
67
     * @return Model
68
     */
69
    private function handleRepeatableFiles(Model $entry)
70
    {
71
        $values = collect(CRUD::getRequest()->get($this->repeatableContainerName));
0 ignored issues
show
Bug introduced by
The method getRequest() does not exist on Backpack\CRUD\app\Librar...udPanel\CrudPanelFacade. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

71
        $values = collect(CRUD::/** @scrutinizer ignore-call */ getRequest()->get($this->repeatableContainerName));
Loading history...
72
        $files = collect(CRUD::getRequest()->file($this->repeatableContainerName));
73
        $value = $this->mergeValuesRecursive($values, $files);
74
75
        if ($this->isRelationship) {
76
            return $this->uploadRelationshipFiles($entry, $value);
77
        }
78
79
        $entry->{$this->repeatableContainerName} = json_encode($this->processRepeatableUploads($entry, $value));
80
81
        return $entry;
82
    }
83
84
    /**
85
     * Uploads the files for a relationship managed with repeatable interface.
86
     *
87
     * @param  Model  $entry
88
     * @param  mixed  $value
89
     * @return Model
90
     */
91
    private function uploadRelationshipFiles(Model $entry, mixed $value)
92
    {
93
        $modelCount = CRUD::get('uploaded_'.$this->repeatableContainerName.'_count');
0 ignored issues
show
Bug introduced by
The method get() does not exist on Backpack\CRUD\app\Librar...udPanel\CrudPanelFacade. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
        /** @scrutinizer ignore-call */ 
94
        $modelCount = CRUD::get('uploaded_'.$this->repeatableContainerName.'_count');
Loading history...
94
        $value = $value->slice($modelCount, 1)->toArray();
95
96
        foreach (app('UploadersRepository')->getRepeatableUploadersFor($this->repeatableContainerName) as $uploader) {
97
            if (array_key_exists($modelCount, $value) && isset($value[$modelCount][$uploader->getName()])) {
98
                $entry->{$uploader->getName()} = $uploader->uploadFile($entry, $value[$modelCount][$uploader->getName()]);
99
            }
100
        }
101
102
        return $entry;
103
    }
104
105
    /**
106
     * Handle the repeatable files uploads.
107
     *
108
     * @param  Model  $entry
109
     * @param  mixed  $value
110
     * @return mixed
111
     */
112
    private function processRepeatableUploads(Model $entry, $value)
113
    {
114
        foreach (app('UploadersRepository')->getRepeatableUploadersFor($this->repeatableContainerName) as $uploader) {
115
            $uploadedValues = $uploader->uploadRepeatableFile($entry, $value->pluck($uploader->getName())->toArray());
116
117
            $value = $value->map(function ($item, $key) use ($uploadedValues, $uploader) {
118
                $item[$uploader->getName()] = $uploadedValues[$key] ?? null;
119
120
                return $item;
121
            });
122
        }
123
124
        return $value;
125
    }
126
127
    /**
128
     * Return the uploader stored values when in a repeatable container.
129
     *
130
     * @param  Model  $entry
131
     * @return array
132
     */
133
    protected function getPreviousRepeatableValues(Model $entry)
134
    {
135
        $previousValues = json_decode($entry->getOriginal($this->repeatableContainerName), true);
0 ignored issues
show
Bug introduced by
It seems like $entry->getOriginal($thi...epeatableContainerName) can also be of type array; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

135
        $previousValues = json_decode(/** @scrutinizer ignore-type */ $entry->getOriginal($this->repeatableContainerName), true);
Loading history...
136
        if (! empty($previousValues)) {
137
            $previousValues = array_column($previousValues, $this->getName());
0 ignored issues
show
Bug introduced by
It seems like getName() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

137
            $previousValues = array_column($previousValues, $this->/** @scrutinizer ignore-call */ getName());
Loading history...
138
        }
139
140
        return $previousValues ?? [];
141
    }
142
143
    /**
144
     * Repeatable items send _order_ parameter in the request.
145
     * This olds the order of the items in the repeatable container.
146
     *
147
     * @return array
148
     */
149
    protected function getFileOrderFromRequest()
150
    {
151
        $items = CRUD::getRequest()->input('_order_'.$this->repeatableContainerName) ?? [];
152
153
        array_walk($items, function (&$key, $value) {
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

153
        array_walk($items, function (&$key, /** @scrutinizer ignore-unused */ $value) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
            $requestValue = $key[$this->getName()] ?? null;
155
            $key = $this->isMultiple ? (is_string($requestValue) ? explode(',', $requestValue) : $requestValue) : $requestValue;
156
        });
157
158
        return $items;
159
    }
160
161
    /**
162
     * Retrieve the repeatable container files.
163
     *
164
     * @param  Model  $entry
165
     * @return void
166
     */
167
    private function retrieveRepeatableFiles(Model $entry)
168
    {
169
        if ($this->isRelationship) {
170
            return $this->retrieveFile($entry);
0 ignored issues
show
Bug introduced by
It seems like retrieveFile() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

170
            return $this->/** @scrutinizer ignore-call */ retrieveFile($entry);
Loading history...
171
        }
172
173
        return $entry;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entry returns the type Illuminate\Database\Eloquent\Model which is incompatible with the documented return type void.
Loading history...
174
    }
175
176
    /**
177
     * Deletes the repeatable container files.
178
     *
179
     * @param  Model  $entry
180
     * @return void
181
     */
182
    private function deleteRepeatableFiles(Model $entry)
183
    {
184
        if ($this->isRelationship) {
185
            $this->deleteFiles($entry);
0 ignored issues
show
Bug introduced by
It seems like deleteFiles() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

185
            $this->/** @scrutinizer ignore-call */ 
186
                   deleteFiles($entry);
Loading history...
186
187
            return;
188
        }
189
190
        $repeatableValues = collect($entry->{$this->getName()});
191
        foreach (app('UploadersRepository')->getRepeatableUploadersFor($this->repeatableContainerName) as $upload) {
192
            if (! $upload->shouldDeleteFiles()) {
193
                continue;
194
            }
195
            $values = $repeatableValues->pluck($upload->getName())->toArray();
196
            foreach ($values as $value) {
197
                if (! $value) {
198
                    continue;
199
                }
200
                if (is_array($value)) {
201
                    foreach ($value as $subvalue) {
202
                        Storage::disk($upload->getDisk())->delete($upload->getPath().$subvalue);
203
                    }
204
205
                    continue;
206
                }
207
                Storage::disk($upload->getDisk())->delete($upload->getPath().$value);
208
            }
209
        }
210
    }
211
212
    /**
213
     * Given two multidimensional arrays, merge them recursively.
214
     *
215
     * @param  array|Collection  $array1
216
     * @param  array|Collection  $array2
217
     * @return array|Collection
218
     */
219
    private function mergeValuesRecursive($array1, $array2)
220
    {
221
        $merged = $array1;
222
        foreach ($array2 as $key => &$value) {
223
            if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
224
                $merged[$key] = $this->mergeValuesRecursive($merged[$key], $value);
225
            } else {
226
                $merged[$key] = $value;
227
            }
228
        }
229
230
        return $merged;
231
    }
232
}
233