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 — make-sure-no-white-spaces-on-c... ( 570fad )
by Pedro
13:16
created

FieldsProtectedMethods::trimWhitespacesFromName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
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' => $this->trimWhitespacesFromName($field)];
116
        }
117
118
        if (is_array($field) && ! isset($field['name'])) {
119
            abort(500, 'All fields must have their name defined');
120
        }
121
122
        $field['name'] = $this->trimWhitespacesFromName($field['name']);
123
        
124
        return $field;
125
    }
126
127
    /**
128
     * If entity is not present, but it looks like the field SHOULD be a relationship field,
129
     * try to determine the method on the model that defines the relationship, and pass it to
130
     * the field as 'entity'.
131
     *
132
     * @param  array  $field
133
     * @return array
134
     */
135
    protected function makeSureFieldHasEntity($field)
136
    {
137
        $model = isset($field['baseModel']) ? (new $field['baseModel']) : $this->model;
138
139
        if (isset($field['entity'])) {
140
            return $field;
141
        }
142
143
        // by default, entity is false if we cannot link it with guessing functions to a relation
144
        $field['entity'] = false;
145
146
        //if the name is dot notation we are sure it's a relationship
147
        if (strpos($field['name'], '.') !== false) {
148
            $possibleMethodName = Str::of($field['name'])->before('.');
149
            // check model method for possibility of being a relationship
150
            $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

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

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

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

291
            /** @scrutinizer ignore-call */ 
292
            $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...
292
        }
293
294
        // when field has any of `many` relations we need to append either the pivot selector for the `ToMany` or the
295
        // local key for the `many` relations. Other relations don't need any special treatment when used as subfields.
296
        if (isset($field['relation_type'])) {
297
            switch ($field['relation_type']) {
298
                case 'MorphToMany':
299
                case 'BelongsToMany':
300
                    $pivotSelectorField = static::getPivotFieldStructure($field);
301
302
                    $pivot = Arr::where($field['subfields'], function ($item) use ($pivotSelectorField) {
303
                        return $item['name'] === $pivotSelectorField['name'];
304
                    });
305
306
                    if (! empty($pivot)) {
307
                        break;
308
                    }
309
310
                    $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

310
                    $this->/** @scrutinizer ignore-call */ 
311
                           setupFieldValidation($pivotSelectorField, $field['name']);
Loading history...
311
                    $field['subfields'] = Arr::prepend($field['subfields'], $pivotSelectorField);
312
313
                    break;
314
                case 'MorphMany':
315
                case 'HasMany':
316
                    $entity = isset($field['baseEntity']) ? $field['baseEntity'].'.'.$field['entity'] : $field['entity'];
317
                    $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

317
                    /** @scrutinizer ignore-call */ 
318
                    $relationInstance = $this->getRelationInstance(['entity' => $entity]);
Loading history...
318
319
                    $localKeyField = Arr::where($field['subfields'], function ($item) use ($relationInstance) {
320
                        return $item['name'] === $relationInstance->getRelated()->getKeyName();
321
                    });
322
323
                    if (! empty($localKeyField)) {
324
                        break;
325
                    }
326
327
                    $field['subfields'] = Arr::prepend($field['subfields'], [
328
                        'name' => $relationInstance->getRelated()->getKeyName(),
329
                        'type' => 'hidden',
330
                    ]);
331
                    break;
332
            }
333
        }
334
335
        return $field;
336
    }
337
338
    /**
339
     * Enable the tabs functionality, if a field has a tab defined.
340
     *
341
     * @param  array  $field  Field definition array.
342
     * @return void
343
     */
344
    protected function enableTabsIfFieldUsesThem($field)
345
    {
346
        // if a tab was mentioned, we should enable it
347
        if (isset($field['tab'])) {
348
            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

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

349
                $this->/** @scrutinizer ignore-call */ 
350
                       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...
350
            }
351
        }
352
    }
353
354
    /**
355
     * Add a field to the current operation, using the Settings API.
356
     *
357
     * @param  array  $field  Field definition array.
358
     */
359
    protected function addFieldToOperationSettings($field)
360
    {
361
        $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

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

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

364
        $this->/** @scrutinizer ignore-call */ 
365
               setOperationSetting('fields', $allFields);
Loading history...
365
    }
366
367
    /**
368
     * Get the string that should be used as an array key, for the attributive array
369
     * where the fields are stored for the current operation.
370
     *
371
     * @deprecated v6
372
     */
373
    protected function getFieldKey(array $field): string
374
    {
375
        return $field['name'];
376
    }
377
378
    /**
379
     * Makes sure that all name parts don't have white spaces.
380
     */
381
    private function trimWhitespacesFromName(string $name) : string
382
    {
383
        return implode(',', array_map(fn($item) => trim($item), explode(',', $name)));
384
    }
385
}
386