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

Test Setup Failed
Pull Request — main (#5725)
by Pedro
25:49 queued 10:59
created

UploadersRepository::getFieldUploaderInstance()   B

Complexity

Conditions 7
Paths 18

Size

Total Lines 36
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 19
c 0
b 0
f 0
nc 18
nop 1
dl 0
loc 36
rs 8.8333
1
<?php
2
3
namespace Backpack\CRUD\app\Library\Uploaders\Support;
4
5
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
6
use Backpack\CRUD\app\Library\Uploaders\Support\Interfaces\UploaderInterface;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Str;
9
10
final class UploadersRepository
11
{
12
    /**
13
     * The array of uploaders classes for field types.
14
     */
15
    private array $uploaderClasses;
16
17
    /**
18
     * Uploaders registered in a repeatable group.
19
     */
20
    private array $repeatableUploaders = [];
21
22
    /**
23
     * Uploaders that have already been handled (events registered) for each field/column instance.
24
     */
25
    private array $handledUploaders = [];
26
27
    public function __construct()
28
    {
29
        $this->uploaderClasses = config('backpack.crud.uploaders', []);
30
    }
31
32
    /**
33
     * Mark the given uploader as handled.
34
     */
35
    public function markAsHandled(string $objectName): void
36
    {
37
        if (! in_array($objectName, $this->handledUploaders)) {
38
            $this->handledUploaders[] = $objectName;
39
        }
40
    }
41
42
    /**
43
     * Check if the given uploader for field/column have been handled.
44
     */
45
    public function isUploadHandled(string $objectName): bool
46
    {
47
        return in_array($objectName, $this->handledUploaders);
48
    }
49
50
    /**
51
     * Check if there are uploads for the give object(field/column) type.
52
     */
53
    public function hasUploadFor(string $objectType, string $group): bool
54
    {
55
        return array_key_exists($objectType, $this->uploaderClasses[$group] ?? []);
56
    }
57
58
    /**
59
     * Return the uploader for the given object type.
60
     */
61
    public function getUploadFor(string $objectType, string $group): string
62
    {
63
        if (! $this->hasUploadFor($objectType, $group)) {
64
            throw new \Exception('There is no uploader defined for the given field type.');
65
        }
66
67
        return $this->uploaderClasses[$group][$objectType];
68
    }
69
70
    /**
71
     * return the registered groups names AKA macros. eg: withFiles, withMedia.
72
     */
73
    public function getUploadersGroupsNames(): array
74
    {
75
        return array_keys($this->uploaderClasses);
76
    }
77
78
    /**
79
     * Register new uploaders or override existing ones.
80
     */
81
    public function addUploaderClasses(array $uploaders, string $group): void
82
    {
83
        // ensure all uploaders implement the UploaderInterface
84
        foreach ($uploaders as $uploader) {
85
            if (! is_a($uploader, UploaderInterface::class, true)) {
86
                throw new \Exception('The uploader class must implement the UploaderInterface.');
87
            }
88
        }
89
        $this->uploaderClasses[$group] = array_merge($this->getGroupUploadersClasses($group), $uploaders);
90
    }
91
92
    /**
93
     * Return the uploaders classes for the given group.
94
     */
95
    private function getGroupUploadersClasses(string $group): array
96
    {
97
        return $this->uploaderClasses[$group] ?? [];
98
    }
99
100
    /**
101
     * Register the specified uploader for the given upload name.
102
     */
103
    public function registerRepeatableUploader(string $uploadName, UploaderInterface $uploader): void
104
    {
105
        if (! array_key_exists($uploadName, $this->repeatableUploaders) || ! in_array($uploader, $this->repeatableUploaders[$uploadName])) {
106
            $this->repeatableUploaders[$uploadName][] = $uploader;
107
        }
108
    }
109
110
    /**
111
     * Check if there are uploaders registered for the given upload name.
112
     */
113
    public function hasRepeatableUploadersFor(string $uploadName): bool
114
    {
115
        return array_key_exists($uploadName, $this->repeatableUploaders);
116
    }
117
118
    /**
119
     * Get the repeatable uploaders for the given upload name.
120
     */
121
    public function getRepeatableUploadersFor(string $uploadName): array
122
    {
123
        return $this->repeatableUploaders[$uploadName] ?? [];
124
    }
125
126
    /**
127
     * Check if the specified upload is registered for the given repeatable uploads.
128
     */
129
    public function isUploadRegistered(string $uploadName, UploaderInterface $upload): bool
130
    {
131
        return $this->hasRepeatableUploadersFor($uploadName) && in_array($upload->getName(), $this->getRegisteredUploadNames($uploadName));
132
    }
133
134
    /**
135
     * Return the registered uploaders names for the given repeatable upload name.
136
     */
137
    public function getRegisteredUploadNames(string $uploadName): array
138
    {
139
        return array_map(function ($uploader) {
140
            return $uploader->getName();
141
        }, $this->getRepeatableUploadersFor($uploadName));
142
    }
143
144
    /**
145
     * Get the uploaders classes for the given group of uploaders.
146
     */
147
    public function getAjaxUploadTypes(string $uploaderMacro = 'withFiles'): array
148
    {
149
        $ajaxFieldTypes = [];
150
        foreach ($this->uploaderClasses[$uploaderMacro] as $fieldType => $uploader) {
151
            if (is_a($uploader, 'Backpack\Pro\Uploads\BackpackAjaxUploader', true)) {
152
                $ajaxFieldTypes[] = $fieldType;
153
            }
154
        }
155
156
        return $ajaxFieldTypes;
157
    }
158
159
    /**
160
     * Get an ajax uploader instance for a given input name.
161
     */
162
    public function getFieldUploaderInstance(string $requestInputName): UploaderInterface
163
    {
164
        if (strpos($requestInputName, '#') !== false) {
165
            $repeatableContainerName = Str::before($requestInputName, '#');
166
            $requestInputName = Str::after($requestInputName, '#');
167
168
            $uploaders = $this->getRepeatableUploadersFor($repeatableContainerName);
169
170
            $uploader = Arr::first($uploaders, function ($uploader) use ($requestInputName) {
171
                return $uploader->getName() === $requestInputName;
172
            });
173
174
            if (! $uploader) {
175
                abort(500, 'Could not find the field in the repeatable uploaders.');
176
            }
177
178
            return $uploader;
179
        }
180
181
        if (empty($crudObject = CRUD::fields()[$requestInputName] ?? [])) {
0 ignored issues
show
Bug introduced by
The method fields() 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

181
        if (empty($crudObject = CRUD::/** @scrutinizer ignore-call */ fields()[$requestInputName] ?? [])) {
Loading history...
182
            abort(500, 'Could not find the field in the CRUD fields.');
183
        }
184
185
        if (! $uploaderMacro = $this->getUploadCrudObjectMacroType($crudObject)) {
186
            abort(500, 'There is no uploader defined for the given field type.');
187
        }
188
189
        if (! $this->isValidUploadField($crudObject, $uploaderMacro)) {
190
            abort(500, 'Invalid field for upload.');
191
        }
192
193
        $uploaderConfiguration = $crudObject[$uploaderMacro] ?? [];
194
        $uploaderConfiguration = ! is_array($uploaderConfiguration) ? [] : $uploaderConfiguration;
195
        $uploaderClass = $this->getUploadFor($crudObject['type'], $uploaderMacro);
0 ignored issues
show
Bug introduced by
It seems like $uploaderMacro can also be of type null; however, parameter $group of Backpack\CRUD\app\Librar...ository::getUploadFor() 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

195
        $uploaderClass = $this->getUploadFor($crudObject['type'], /** @scrutinizer ignore-type */ $uploaderMacro);
Loading history...
196
197
        return new $uploaderClass(['name' => $requestInputName], $uploaderConfiguration);
198
    }
199
200
    /**
201
     * Get the upload field macro type for the given object.
202
     */
203
    private function getUploadCrudObjectMacroType(array $crudObject): string|null
204
    {
205
        $uploadersGroups = $this->getUploadersGroupsNames();
206
207
        foreach ($uploadersGroups as $uploaderMacro) {
208
            if (isset($crudObject[$uploaderMacro])) {
209
                return $uploaderMacro;
210
            }
211
        }
212
213
        return null;
214
    }
215
216
    private function isValidUploadField($crudObject, $uploaderMacro)
217
    {
218
        if (Str::contains($crudObject['name'], '#')) {
219
            $container = Str::before($crudObject['name'], '#');
220
            $field = array_filter(CRUD::fields()[$container]['subfields'] ?? [], function ($item) use ($crudObject, $uploaderMacro) {
221
                return $item['name'] === $crudObject['name'] && in_array($item['type'], $this->getAjaxUploadTypes($uploaderMacro));
222
            });
223
224
            return ! empty($field);
225
        }
226
227
        return in_array($crudObject['type'], $this->getAjaxUploadTypes($uploaderMacro));
228
    }
229
}
230