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
Pull Request — main (#5275)
by
unknown
37:59 queued 23:18
created

makeSureSubfieldsHaveNecessaryAttributes()   C

Complexity

Conditions 15
Paths 169

Size

Total Lines 60
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 35
nc 169
nop 1
dl 0
loc 60
rs 5.3416
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Str;
7
8
trait FieldsProtectedMethods
9
{
10
    /**
11
     * If field has entity we want to get the relation type from it.
12
     *
13
     * @param  array  $field
14
     * @return array
15
     */
16
    public function makeSureFieldHasRelationType($field)
17
    {
18
        $field['relation_type'] = $field['relation_type'] ?? $this->inferRelationTypeFromRelationship($field);
0 ignored issues
show
Bug introduced by
It seems like inferRelationTypeFromRelationship() 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

18
        $field['relation_type'] = $field['relation_type'] ?? $this->/** @scrutinizer ignore-call */ inferRelationTypeFromRelationship($field);
Loading history...
19
20
        return $field;
21
    }
22
23
    /**
24
     * If field has entity we want to make sure it also has a model for that relation.
25
     *
26
     * @param  array  $field
27
     * @return array
28
     */
29
    public function makeSureFieldHasModel($field)
30
    {
31
        $field['model'] = $field['model'] ?? $this->inferFieldModelFromRelationship($field);
0 ignored issues
show
Bug introduced by
It seems like inferFieldModelFromRelationship() 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

31
        $field['model'] = $field['model'] ?? $this->/** @scrutinizer ignore-call */ inferFieldModelFromRelationship($field);
Loading history...
32
33
        return $field;
34
    }
35
36
    /**
37
     * Based on relation type we can guess if pivot is set.
38
     *
39
     * @param  array  $field
40
     * @return array
41
     */
42
    public function makeSureFieldHasPivot($field)
43
    {
44
        $field['pivot'] = $field['pivot'] ?? $this->guessIfFieldHasPivotFromRelationType($field['relation_type']);
0 ignored issues
show
Bug introduced by
It seems like guessIfFieldHasPivotFromRelationType() 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

44
        $field['pivot'] = $field['pivot'] ?? $this->/** @scrutinizer ignore-call */ guessIfFieldHasPivotFromRelationType($field['relation_type']);
Loading history...
45
46
        return $field;
47
    }
48
49
    /**
50
     * Based on relation type we can try to guess if it is a multiple field.
51
     *
52
     * @param  array  $field
53
     * @return array
54
     */
55
    public function makeSureFieldHasMultiple($field)
56
    {
57
        if (isset($field['relation_type'])) {
58
            $field['multiple'] = $field['multiple'] ?? $this->guessIfFieldHasMultipleFromRelationType($field['relation_type']);
0 ignored issues
show
Bug introduced by
It seems like guessIfFieldHasMultipleFromRelationType() 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

58
            $field['multiple'] = $field['multiple'] ?? $this->/** @scrutinizer ignore-call */ guessIfFieldHasMultipleFromRelationType($field['relation_type']);
Loading history...
59
        }
60
61
        return $field;
62
    }
63
64
    /**
65
     * In case field name is dot notation we want to convert it to a valid HTML array field name for validation purposes.
66
     *
67
     * @param  array  $field
68
     * @return array
69
     */
70
    public function overwriteFieldNameFromDotNotationToArray($field)
71
    {
72
        if (strpos($field['name'], '.') !== false) {
73
            $entity_array = explode('.', $field['name']);
74
            $name_string = '';
75
76
            foreach ($entity_array as $key => $array_entity) {
77
                $name_string .= ($key == 0) ? $array_entity : '['.$array_entity.']';
78
            }
79
80
            $field['name'] = $name_string;
81
        }
82
83
        return $field;
84
    }
85
86
    /**
87
     * Run the field name overwrite in multiple fields.
88
     *
89
     * @param  array  $fields
90
     * @return array
91
     */
92
    public function overwriteFieldNamesFromDotNotationToArray($fields)
93
    {
94
        foreach ($fields as $key => $field) {
95
            $fields[$key] = $this->overwriteFieldNameFromDotNotationToArray($field);
96
        }
97
98
        return $fields;
99
    }
100
101
    /**
102
     * If the field_definition_array array is a string, it means the programmer was lazy
103
     * and has only passed the name of the field. Turn that into a proper array.
104
     *
105
     * @param  string|array  $field  The field definition array (or string).
106
     * @return array
107
     */
108
    protected function makeSureFieldHasName($field)
109
    {
110
        if (empty($field)) {
111
            abort(500, 'Field name can\'t be empty');
112
        }
113
114
        if (is_string($field)) {
115
            return ['name' => $field];
116
        }
117
118
        if (is_array($field) && ! isset($field['name'])) {
119
            abort(500, 'All fields must have their name defined');
120
        }
121
122
        return $field;
123
    }
124
125
    /**
126
     * If entity is not present, but it looks like the field SHOULD be a relationship field,
127
     * try to determine the method on the model that defines the relationship, and pass it to
128
     * the field as 'entity'.
129
     *
130
     * @param  array  $field
131
     * @return array
132
     */
133
    protected function makeSureFieldHasEntity($field)
134
    {
135
        $model = isset($field['baseModel']) ? (new $field['baseModel']) : $this->model;
136
137
        if (isset($field['entity'])) {
138
            return $field;
139
        }
140
141
        // by default, entity is false if we cannot link it with guessing functions to a relation
142
        $field['entity'] = false;
143
144
        //if the name is dot notation we are sure it's a relationship
145
        if (strpos($field['name'], '.') !== false) {
146
            $possibleMethodName = Str::of($field['name'])->before('.');
147
            // check model method for possibility of being a relationship
148
            $field['entity'] = $this->modelMethodIsRelationship($model, $possibleMethodName) ? $field['name'] : false;
0 ignored issues
show
Bug introduced by
It seems like modelMethodIsRelationship() 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

148
            $field['entity'] = $this->/** @scrutinizer ignore-call */ modelMethodIsRelationship($model, $possibleMethodName) ? $field['name'] : false;
Loading history...
149
150
            return $field;
151
        }
152
153
        // if there's a method on the model with this name
154
        if (method_exists($model, $field['name'])) {
155
            // check model method for possibility of being a relationship
156
            $field['entity'] = $this->modelMethodIsRelationship($model, $field['name']);
157
158
            return $field;
159
        }
160
161
        // if the name ends with _id and that method exists,
162
        // we can probably use it as an entity
163
        if (Str::endsWith($field['name'], '_id')) {
164
            $possibleMethodName = Str::replaceLast('_id', '', $field['name']);
165
166
            if (method_exists($model, $possibleMethodName)) {
167
                // check model method for possibility of being a relationship
168
                $field['entity'] = $this->modelMethodIsRelationship($model, $possibleMethodName);
169
170
                return $field;
171
            }
172
        }
173
174
        return $field;
175
    }
176
177
    protected function makeSureFieldHasAttribute($field)
178
    {
179
        if (isset($field['entity']) && $field['entity']) {
180
            // if the user setup the attribute in relation string, we are not going to infer that attribute from model
181
            // instead we get the defined attribute by the user.
182
            if ($this->isAttributeInRelationString($field)) {
0 ignored issues
show
Bug introduced by
It seems like isAttributeInRelationString() 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

182
            if ($this->/** @scrutinizer ignore-call */ isAttributeInRelationString($field)) {
Loading history...
183
                $field['attribute'] = $field['attribute'] ?? Str::afterLast($field['entity'], '.');
184
185
                return $field;
186
            }
187
        }
188
        // if there's a model defined, but no attribute
189
        // guess an attribute using the identifiableAttribute functionality in CrudTrait
190
        if (isset($field['model']) && ! isset($field['attribute']) && method_exists($field['model'], 'identifiableAttribute')) {
191
            $field['attribute'] = (new $field['model']())->identifiableAttribute();
192
        }
193
194
        return $field;
195
    }
196
197
    /**
198
     * Set the label of a field, if it's missing, by capitalizing the name and replacing
199
     * underscores with spaces.
200
     *
201
     * @param  array  $field  Field definition array.
202
     * @return array Field definition array that contains label too.
203
     */
204
    protected function makeSureFieldHasLabel($field)
205
    {
206
        if (! isset($field['label'])) {
207
            $name = str_replace(',', ' ', $field['name']);
208
            $name = str_replace('_id', '', $name);
209
            $field['label'] = mb_ucfirst(str_replace('_', ' ', $name));
210
        }
211
212
        return $field;
213
    }
214
215
    /**
216
     * Set the type of a field, if it's missing, by inferring it from the
217
     * db column type.
218
     *
219
     * @param  array  $field  Field definition array.
220
     * @return array Field definition array that contains type too.
221
     */
222
    protected function makeSureFieldHasType($field)
223
    {
224
        if (! isset($field['type'])) {
225
            $field['type'] = isset($field['relation_type']) ? $this->inferFieldTypeFromRelationType($field['relation_type']) : $this->inferFieldTypeFromDbColumnType($field['name']);
0 ignored issues
show
Bug introduced by
The method inferFieldTypeFromDbColumnType() does not exist on Backpack\CRUD\app\Librar...\FieldsProtectedMethods. Did you maybe mean inferFieldTypeFromRelationType()? ( Ignorable by Annotation )

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

225
            $field['type'] = isset($field['relation_type']) ? $this->inferFieldTypeFromRelationType($field['relation_type']) : $this->/** @scrutinizer ignore-call */ inferFieldTypeFromDbColumnType($field['name']);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
226
        }
227
228
        return $field;
229
    }
230
231
    protected function inferFieldTypeFromRelationType($relationType)
232
    {
233
        if (backpack_pro()) {
234
            return 'relationship';
235
        }
236
237
        switch ($relationType) {
238
            case 'BelongsTo':
239
                return 'select';
240
            case 'BelongsToMany':
241
            case 'MorphToMany':
242
                return 'select_multiple';
243
            default:
244
                return 'text';
245
        }
246
    }
247
248
    /**
249
     * If a field has subfields, go through each subfield and guess
250
     * its attribute, filling in whatever is missing.
251
     *
252
     * @param  array  $field  Field definition array.
253
     * @return array The improved definition of that field (a better 'subfields' array)
254
     */
255
    protected function makeSureSubfieldsHaveNecessaryAttributes($field)
256
    {
257
        if (! isset($field['subfields'])) {
258
            return $field;
259
        }
260
261
        foreach ($field['subfields'] as $key => $subfield) {
262
            if (empty($subfield) || ! isset($subfield['name'])) {
263
                abort(500, 'Subfield name can\'t be empty');
264
            }
265
266
            // make sure the field definition is an array
267
            if (is_string($subfield)) {
268
                $subfield = ['name' => $subfield];
269
            }
270
271
            $subfield['parentFieldName'] = $field['name'];
272
273
            if (! isset($field['model'])) {
274
                // we're inside a simple 'repeatable' with no model/relationship, so
275
                // we assume all subfields are supposed to be text fields
276
                $subfield['type'] = $subfield['type'] ?? 'text';
277
                $subfield['entity'] = $subfield['entity'] ?? false;
278
            } else {
279
                // we should use 'model' as the `baseModel` for all subfields, so that when
280
                // we look if `category()` relationship exists on the model, we look on
281
                // the model this repeatable represents, not the main CRUD model
282
                $currentEntity = $subfield['baseEntity'] ?? $field['entity'];
283
                $subfield['baseModel'] = $subfield['baseModel'] ?? $field['model'];
284
                $subfield['baseEntity'] = isset($field['baseEntity']) ? $field['baseEntity'].'.'.$currentEntity : $currentEntity;
285
                $subfield['baseFieldName'] = is_array($subfield['name']) ? implode(',', $subfield['name']) : $subfield['name'];
286
                $subfield['baseFieldName'] = Str::afterLast($subfield['baseFieldName'], '.');
287
            }
288
289
            $field['subfields'][$key] = $this->makeSureFieldHasNecessaryAttributes($subfield);
0 ignored issues
show
Bug introduced by
The method makeSureFieldHasNecessaryAttributes() does not exist on Backpack\CRUD\app\Librar...\FieldsProtectedMethods. Did you maybe mean makeSureFieldHasAttribute()? ( Ignorable by Annotation )

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

289
            /** @scrutinizer ignore-call */ 
290
            $field['subfields'][$key] = $this->makeSureFieldHasNecessaryAttributes($subfield);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
290
        }
291
292
        // when field has any of `many` relations we need to append either the pivot selector for the `ToMany` or the
293
        // local key for the `many` relations. Other relations don't need any special treatment when used as subfields.
294
        if (isset($field['relation_type'])) {
295
            switch ($field['relation_type']) {
296
                case 'MorphToMany':
297
                case 'BelongsToMany':
298
                    $pivotSelectorField = static::getPivotFieldStructure($field);
299
                    $this->setupFieldValidation($pivotSelectorField, $field['name']);
0 ignored issues
show
Bug introduced by
It seems like setupFieldValidation() 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

299
                    $this->/** @scrutinizer ignore-call */ 
300
                           setupFieldValidation($pivotSelectorField, $field['name']);
Loading history...
300
                    $field['subfields'] = Arr::prepend($field['subfields'], $pivotSelectorField);
301
                    break;
302
                case 'MorphMany':
303
                case 'HasMany':
304
                    $entity = isset($field['baseEntity']) ? $field['baseEntity'].'.'.$field['entity'] : $field['entity'];
305
                    $relationInstance = $this->getRelationInstance(['entity' => $entity]);
0 ignored issues
show
Bug introduced by
It seems like getRelationInstance() 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

305
                    /** @scrutinizer ignore-call */ 
306
                    $relationInstance = $this->getRelationInstance(['entity' => $entity]);
Loading history...
306
                    $field['subfields'] = Arr::prepend($field['subfields'], [
307
                        'name' => $relationInstance->getRelated()->getKeyName(),
308
                        'type' => 'hidden',
309
                    ]);
310
                    break;
311
            }
312
        }
313
314
        return $field;
315
    }
316
317
    /**
318
     * Enable the tabs functionality, if a field has a tab defined.
319
     *
320
     * @param  array  $field  Field definition array.
321
     * @return void
322
     */
323
    protected function enableTabsIfFieldUsesThem($field)
324
    {
325
        // if a tab was mentioned, we should enable it
326
        if (isset($field['tab'])) {
327
            if (! $this->tabsEnabled()) {
0 ignored issues
show
Bug introduced by
It seems like tabsEnabled() 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

327
            if (! $this->/** @scrutinizer ignore-call */ tabsEnabled()) {
Loading history...
328
                $this->enableTabs();
0 ignored issues
show
Bug introduced by
The method enableTabs() does not exist on Backpack\CRUD\app\Librar...\FieldsProtectedMethods. Did you maybe mean enableTabsIfFieldUsesThem()? ( Ignorable by Annotation )

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

328
                $this->/** @scrutinizer ignore-call */ 
329
                       enableTabs();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
329
            }
330
        }
331
    }
332
333
    /**
334
     * Add a field to the current operation, using the Settings API.
335
     *
336
     * @param  array  $field  Field definition array.
337
     */
338
    protected function addFieldToOperationSettings($field)
339
    {
340
        $allFields = $this->getOperationSetting('fields');
0 ignored issues
show
Unused Code introduced by
The assignment to $allFields is dead and can be removed.
Loading history...
Bug introduced by
It seems like getOperationSetting() 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

340
        /** @scrutinizer ignore-call */ 
341
        $allFields = $this->getOperationSetting('fields');
Loading history...
341
        $allFields = array_merge($this->getCleanStateFields(), [$field['name'] => $field]);
0 ignored issues
show
Bug introduced by
It seems like getCleanStateFields() 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

341
        $allFields = array_merge($this->/** @scrutinizer ignore-call */ getCleanStateFields(), [$field['name'] => $field]);
Loading history...
342
343
        $this->setOperationSetting('fields', $allFields);
0 ignored issues
show
Bug introduced by
It seems like setOperationSetting() 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

343
        $this->/** @scrutinizer ignore-call */ 
344
               setOperationSetting('fields', $allFields);
Loading history...
344
    }
345
346
    /**
347
     * Get the string that should be used as an array key, for the attributive array
348
     * where the fields are stored for the current operation.
349
     *
350
     * @deprecated v6
351
     */
352
    protected function getFieldKey(array $field): string
353
    {
354
        return $field['name'];
355
    }
356
}
357