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

makeSureSubfieldsHaveNecessaryAttributes()   F
last analyzed

Complexity

Conditions 20
Paths 673

Size

Total Lines 96
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
cc 20
eloc 53
c 3
b 2
f 0
nc 673
nop 1
dl 0
loc 96
rs 0.4541

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', ['developer-error-exception']);
112
        }
113
114
        if (is_string($field)) {
115
            return ['name' => Str::replace(' ', '', $field)];
116
        }
117
118
        if (is_array($field) && ! isset($field['name'])) {
119
            abort(500, 'All fields must have their name defined', ['developer-error-exception']);
120
        }
121
122
        if (is_array($field['name'])) {
123
            abort(500, 'Field name can\'t be an array. It should be a string. Error in field: '.json_encode($field['name']), ['developer-error-exception']);
124
        }
125
126
        $field['name'] = Str::replace(' ', '', $field['name']);
127
128
        return $field;
129
    }
130
131
    /**
132
     * If entity is not present, but it looks like the field SHOULD be a relationship field,
133
     * try to determine the method on the model that defines the relationship, and pass it to
134
     * the field as 'entity'.
135
     *
136
     * @param  array  $field
137
     * @return array
138
     */
139
    protected function makeSureFieldHasEntity($field)
140
    {
141
        $model = isset($field['baseModel']) ? (new $field['baseModel']) : $this->model;
142
143
        if (isset($field['entity'])) {
144
            return $field;
145
        }
146
147
        // by default, entity is false if we cannot link it with guessing functions to a relation
148
        $field['entity'] = false;
149
150
        //if the name is dot notation we are sure it's a relationship
151
        if (strpos($field['name'], '.') !== false) {
152
            $possibleMethodName = Str::of($field['name'])->before('.')->value();
153
            // check model method for possibility of being a relationship
154
            $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

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

188
            if ($this->/** @scrutinizer ignore-call */ isAttributeInRelationString($field)) {
Loading history...
189
                $field['attribute'] = $field['attribute'] ?? Str::afterLast($field['entity'], '.');
190
191
                return $field;
192
            }
193
        }
194
        // if there's a model defined, but no attribute
195
        // guess an attribute using the identifiableAttribute functionality in CrudTrait
196
        if (isset($field['model']) && ! isset($field['attribute']) && method_exists($field['model'], 'identifiableAttribute')) {
197
            $field['attribute'] = (new $field['model']())->identifiableAttribute();
198
        }
199
200
        return $field;
201
    }
202
203
    /**
204
     * Set the label of a field, if it's missing, by capitalizing the name and replacing
205
     * underscores with spaces.
206
     *
207
     * @param  array  $field  Field definition array.
208
     * @return array Field definition array that contains label too.
209
     */
210
    protected function makeSureFieldHasLabel($field)
211
    {
212
        if (! isset($field['label'])) {
213
            $name = str_replace(',', ' ', $field['name']);
214
            $name = str_replace('_id', '', $name);
215
            $field['label'] = mb_ucfirst(str_replace('_', ' ', $name));
216
        }
217
218
        return $field;
219
    }
220
221
    /**
222
     * Set the type of a field, if it's missing, by inferring it from the
223
     * db column type.
224
     *
225
     * @param  array  $field  Field definition array.
226
     * @return array Field definition array that contains type too.
227
     */
228
    protected function makeSureFieldHasType($field)
229
    {
230
        if (! isset($field['type'])) {
231
            $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

231
            $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...
232
        }
233
234
        return $field;
235
    }
236
237
    protected function inferFieldTypeFromRelationType($relationType)
238
    {
239
        if (backpack_pro()) {
240
            return 'relationship';
241
        }
242
243
        switch ($relationType) {
244
            case 'BelongsTo':
245
                return 'select';
246
            case 'BelongsToMany':
247
            case 'MorphToMany':
248
                return 'select_multiple';
249
            default:
250
                return 'text';
251
        }
252
    }
253
254
    /**
255
     * If a field has subfields, go through each subfield and guess
256
     * its attribute, filling in whatever is missing.
257
     *
258
     * @param  array  $field  Field definition array.
259
     * @return array The improved definition of that field (a better 'subfields' array)
260
     */
261
    protected function makeSureSubfieldsHaveNecessaryAttributes($field)
262
    {
263
        if (! isset($field['subfields']) || ! is_array($field['subfields'])) {
264
            return $field;
265
        }
266
267
        if (! is_multidimensional_array($field['subfields'], true)) {
268
            abort(500, 'Subfields of «'.$field['name'].'» are malformed. Make sure you provide an array of subfields.', ['developer-error-exception']);
269
        }
270
271
        foreach ($field['subfields'] as $key => $subfield) {
272
            if (empty($subfield) || ! isset($subfield['name'])) {
273
                abort(500, 'A subfield of «'.$field['name'].'» is malformed. Subfield attribute name can\'t be empty.', ['developer-error-exception']);
274
            }
275
276
            // make sure the field definition is an array
277
            if (is_string($subfield)) {
278
                $subfield = ['name' => $subfield];
279
            }
280
281
            $subfield['name'] = Str::replace(' ', '', $subfield['name']);
282
283
            $subfield['parentFieldName'] = $field['name'];
284
285
            if (! isset($field['model'])) {
286
                // we're inside a simple 'repeatable' with no model/relationship, so
287
                // we assume all subfields are supposed to be text fields
288
                $subfield['type'] = $subfield['type'] ?? 'text';
289
                $subfield['entity'] = $subfield['entity'] ?? false;
290
            } else {
291
                // we should use 'model' as the `baseModel` for all subfields, so that when
292
                // we look if `category()` relationship exists on the model, we look on
293
                // the model this repeatable represents, not the main CRUD model
294
                $currentEntity = $subfield['baseEntity'] ?? $field['entity'];
295
                $subfield['baseModel'] = $subfield['baseModel'] ?? $field['model'];
296
                $subfield['baseEntity'] = isset($field['baseEntity']) ? $field['baseEntity'].'.'.$currentEntity : $currentEntity;
297
                $subfield['baseFieldName'] = is_array($subfield['name']) ? implode(',', $subfield['name']) : $subfield['name'];
298
                $subfield['baseFieldName'] = Str::afterLast($subfield['baseFieldName'], '.');
299
            }
300
301
            $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

301
            /** @scrutinizer ignore-call */ 
302
            $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...
302
        }
303
304
        // when field has any of `many` relations we need to append either the pivot selector for the `ToMany` or the
305
        // local key for the `many` relations. Other relations don't need any special treatment when used as subfields.
306
        if (isset($field['relation_type'])) {
307
            switch ($field['relation_type']) {
308
                case 'MorphToMany':
309
                case 'BelongsToMany':
310
                    $pivotSelectorField = static::getPivotFieldStructure($field);
311
312
                    $pivot = Arr::where($field['subfields'], function ($item) use ($pivotSelectorField) {
313
                        return $item['name'] === $pivotSelectorField['name'];
314
                    });
315
316
                    if (! empty($pivot)) {
317
                        break;
318
                    }
319
320
                    if ($field['allow_duplicate_pivots'] ?? false) {
321
                        $pivotSelectorField['allow_duplicate_pivots'] = true;
322
                        $field['subfields'] = Arr::prepend($field['subfields'], [
323
                            'name' => $field['pivot_key_name'] ?? 'id',
324
                            'type' => 'hidden',
325
                            'wrapper' => [
326
                                'class' => 'd-none',
327
                            ],
328
                        ]);
329
                    }
330
331
                    $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

331
                    $this->/** @scrutinizer ignore-call */ 
332
                           setupFieldValidation($pivotSelectorField, $field['name']);
Loading history...
332
                    $field['subfields'] = Arr::prepend($field['subfields'], $pivotSelectorField);
333
334
                    break;
335
                case 'MorphMany':
336
                case 'HasMany':
337
                    $entity = isset($field['baseEntity']) ? $field['baseEntity'].'.'.$field['entity'] : $field['entity'];
338
                    $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

338
                    /** @scrutinizer ignore-call */ 
339
                    $relationInstance = $this->getRelationInstance(['entity' => $entity]);
Loading history...
339
340
                    $localKeyField = Arr::where($field['subfields'], function ($item) use ($relationInstance) {
341
                        return $item['name'] === $relationInstance->getRelated()->getKeyName();
342
                    });
343
344
                    if (! empty($localKeyField)) {
345
                        break;
346
                    }
347
348
                    $field['subfields'] = Arr::prepend($field['subfields'], [
349
                        'name' => $relationInstance->getRelated()->getKeyName(),
350
                        'type' => 'hidden',
351
                    ]);
352
                    break;
353
            }
354
        }
355
356
        return $field;
357
    }
358
359
    /**
360
     * Enable the tabs functionality, if a field has a tab defined.
361
     *
362
     * @param  array  $field  Field definition array.
363
     * @return void
364
     */
365
    protected function enableTabsIfFieldUsesThem($field)
366
    {
367
        // if a tab was mentioned, we should enable it
368
        if (isset($field['tab'])) {
369
            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

369
            if (! $this->/** @scrutinizer ignore-call */ tabsEnabled()) {
Loading history...
370
                $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

370
                $this->/** @scrutinizer ignore-call */ 
371
                       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...
371
            }
372
        }
373
    }
374
375
    /**
376
     * Add a field to the current operation, using the Settings API.
377
     *
378
     * @param  array  $field  Field definition array.
379
     */
380
    protected function addFieldToOperationSettings($field)
381
    {
382
        $allFields = $this->getOperationSetting('fields');
0 ignored issues
show
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

382
        /** @scrutinizer ignore-call */ 
383
        $allFields = $this->getOperationSetting('fields');
Loading history...
Unused Code introduced by
The assignment to $allFields is dead and can be removed.
Loading history...
383
        $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

383
        $allFields = array_merge($this->/** @scrutinizer ignore-call */ getCleanStateFields(), [$field['name'] => $field]);
Loading history...
384
385
        $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

385
        $this->/** @scrutinizer ignore-call */ 
386
               setOperationSetting('fields', $allFields);
Loading history...
386
    }
387
388
    /**
389
     * Get the string that should be used as an array key, for the attributive array
390
     * where the fields are stored for the current operation.
391
     *
392
     * @deprecated v6
393
     */
394
    protected function getFieldKey(array $field): string
395
    {
396
        return $field['name'];
397
    }
398
}
399