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 — master (#3981)
by
unknown
21:29 queued 06:17
created

FieldsProtectedMethods   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 264
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 70
dl 0
loc 264
rs 8.8798
c 4
b 0
f 0
wmc 44

14 Methods

Rating   Name   Duplication   Size   Complexity  
A getFieldKey() 0 7 2
A makeSureFieldHasName() 0 11 4
A overwriteFieldNameFromEntity() 0 22 5
A makeSureFieldHasAttribute() 0 9 4
A makeSureFieldHasLabel() 0 9 3
A makeSureFieldHasModel() 0 5 1
B makeSureFieldHasEntity() 0 38 7
A addFieldToOperationSettings() 0 8 1
A makeSureFieldHasMultiple() 0 7 2
A makeSureFieldHasType() 0 7 3
A makeSureFieldHasRelationType() 0 5 1
A enableTabsIfFieldUsesThem() 0 6 3
A makeSureFieldHasPivot() 0 5 1
B overwriteFieldNameFromDotNotationToArray() 0 14 7

How to fix   Complexity   

Complex Class

Complex classes like FieldsProtectedMethods often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FieldsProtectedMethods, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Illuminate\Support\Str;
6
7
trait FieldsProtectedMethods
8
{
9
    /**
10
     * If field has entity we want to get the relation type from it.
11
     *
12
     * @param  array  $field
13
     * @return array
14
     */
15
    public function makeSureFieldHasRelationType($field)
16
    {
17
        $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

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

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

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

57
            $field['multiple'] = $field['multiple'] ?? $this->/** @scrutinizer ignore-call */ guessIfFieldHasMultipleFromRelationType($field['relation_type']);
Loading history...
58
        }
59
60
        return $field;
61
    }
62
63
    /**
64
     * In case field name is dot notation we want to convert it to a valid HTML array field name for validation purposes.
65
     *
66
     * @param  array  $field
67
     * @return array
68
     */
69
    public function overwriteFieldNameFromDotNotationToArray($field)
70
    {
71
        if (! is_array($field['name']) && strpos($field['name'], '.') !== false && isset($field['relation_type']) && in_array($field['relation_type'], ['HasOne', 'MorphOne'])) {
72
            $entity_array = explode('.', $field['name']);
73
            $name_string = '';
74
75
            foreach ($entity_array as $key => $array_entity) {
76
                $name_string .= ($key == 0) ? $array_entity : '['.$array_entity.']';
77
            }
78
79
            $field['name'] = $name_string;
80
        }
81
82
        return $field;
83
    }
84
85
    /**
86
     * If the field_definition_array array is a string, it means the programmer was lazy
87
     * and has only passed the name of the field. Turn that into a proper array.
88
     *
89
     * @param  string|array  $field  The field definition array (or string).
90
     * @return array
91
     */
92
    protected function makeSureFieldHasName($field)
93
    {
94
        if (is_string($field)) {
95
            return ['name' => $field];
96
        }
97
98
        if (is_array($field) && ! isset($field['name'])) {
99
            abort(500, 'All fields must have their name defined');
100
        }
101
102
        return $field;
103
    }
104
105
    /**
106
     * If entity is not present, but it looks like the field SHOULD be a relationship field,
107
     * try to determine the method on the model that defines the relationship, and pass it to
108
     * the field as 'entity'.
109
     *
110
     * @param  [type] $field [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
111
     * @return [type]        [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
112
     */
113
    protected function makeSureFieldHasEntity($field)
114
    {
115
        if (isset($field['entity'])) {
116
            return $field;
117
        }
118
119
        // if the name is an array it's definitely not a relationship
120
        if (is_array($field['name'])) {
121
            return $field;
122
        }
123
124
        //if the name is dot notation we are sure it's a relationship
125
        if (strpos($field['name'], '.') !== false) {
126
            $field['entity'] = $field['name'];
127
128
            return $field;
129
        }
130
131
        // if there's a method on the model with this name
132
        if (method_exists($this->model, $field['name'])) {
133
            $field['entity'] = $field['name'];
134
135
            return $field;
136
        }
137
138
        // if the name ends with _id and that method exists,
139
        // we can probably use it as an entity
140
        if (Str::endsWith($field['name'], '_id')) {
141
            $possibleMethodName = Str::replaceLast('_id', '', $field['name']);
142
143
            if (method_exists($this->model, $possibleMethodName)) {
144
                $field['entity'] = $possibleMethodName;
145
146
                return $field;
147
            }
148
        }
149
150
        return $field;
151
    }
152
153
    protected function overwriteFieldNameFromEntity($field)
154
    {
155
        // if the entity doesn't have a dot, it means we don't need to overwrite the name
156
        if (! Str::contains($field['entity'], '.')) {
157
            return $field;
158
        }
159
160
        // only 1-1 relationships are supported, if it's anything else, abort
161
        if ($field['relation_type'] != 'HasOne') {
162
            return $field;
163
        }
164
165
        if (count(explode('.', $field['entity'])) == count(explode('.', $this->getOnlyRelationEntity($field)))) {
0 ignored issues
show
Bug introduced by
It seems like getOnlyRelationEntity() 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

165
        if (count(explode('.', $field['entity'])) == count(explode('.', $this->/** @scrutinizer ignore-call */ getOnlyRelationEntity($field)))) {
Loading history...
166
            $field['name'] = implode('.', array_slice(explode('.', $field['entity']), 0, -1));
167
            $relation = $this->getRelationInstance($field);
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

167
            /** @scrutinizer ignore-call */ 
168
            $relation = $this->getRelationInstance($field);
Loading history...
168
            if (! empty($field['name'])) {
169
                $field['name'] .= '.';
170
            }
171
            $field['name'] .= $relation->getForeignKeyName();
172
        }
173
174
        return $field;
175
    }
176
177
    protected function makeSureFieldHasAttribute($field)
178
    {
179
        // if there's a model defined, but no attribute
180
        // guess an attribute using the identifiableAttribute functionality in CrudTrait
181
        if (isset($field['model']) && ! isset($field['attribute']) && method_exists($field['model'], 'identifiableAttribute')) {
182
            $field['attribute'] = call_user_func([(new $field['model']), 'identifiableAttribute']);
183
        }
184
185
        return $field;
186
    }
187
188
    /**
189
     * Set the label of a field, if it's missing, by capitalizing the name and replacing
190
     * underscores with spaces.
191
     *
192
     * @param  array  $field  Field definition array.
193
     * @return array Field definition array that contains label too.
194
     */
195
    protected function makeSureFieldHasLabel($field)
196
    {
197
        if (! isset($field['label'])) {
198
            $name = is_array($field['name']) ? $field['name'][0] : $field['name'];
199
            $name = str_replace('_id', '', $name);
200
            $field['label'] = mb_ucfirst(str_replace('_', ' ', $name));
201
        }
202
203
        return $field;
204
    }
205
206
    /**
207
     * Set the type of a field, if it's missing, by inferring it from the
208
     * db column type.
209
     *
210
     * @param  array  $field  Field definition array.
211
     * @return array Field definition array that contains type too.
212
     */
213
    protected function makeSureFieldHasType($field)
214
    {
215
        if (! isset($field['type'])) {
216
            $field['type'] = isset($field['relation_type']) ? $this->inferFieldTypeFromFieldRelation($field) : $this->inferFieldTypeFromDbColumnType($field['name']);
0 ignored issues
show
Bug introduced by
It seems like inferFieldTypeFromDbColumnType() 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

216
            $field['type'] = isset($field['relation_type']) ? $this->inferFieldTypeFromFieldRelation($field) : $this->/** @scrutinizer ignore-call */ inferFieldTypeFromDbColumnType($field['name']);
Loading history...
Bug introduced by
It seems like inferFieldTypeFromFieldRelation() 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

216
            $field['type'] = isset($field['relation_type']) ? $this->/** @scrutinizer ignore-call */ inferFieldTypeFromFieldRelation($field) : $this->inferFieldTypeFromDbColumnType($field['name']);
Loading history...
217
        }
218
219
        return $field;
220
    }
221
222
    /**
223
     * Enable the tabs functionality, if a field has a tab defined.
224
     *
225
     * @param  array  $field  Field definition array.
226
     * @return void
227
     */
228
    protected function enableTabsIfFieldUsesThem($field)
229
    {
230
        // if a tab was mentioned, we should enable it
231
        if (isset($field['tab'])) {
232
            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

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

233
                $this->/** @scrutinizer ignore-call */ 
234
                       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...
234
            }
235
        }
236
    }
237
238
    /**
239
     * Add a field to the current operation, using the Settings API.
240
     *
241
     * @param  array  $field  Field definition array.
242
     */
243
    protected function addFieldToOperationSettings($field)
244
    {
245
        $fieldKey = $this->getFieldKey($field);
246
247
        $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

247
        /** @scrutinizer ignore-call */ 
248
        $allFields = $this->getOperationSetting('fields');
Loading history...
Unused Code introduced by
The assignment to $allFields is dead and can be removed.
Loading history...
248
        $allFields = array_merge($this->fields(), [$fieldKey => $field]);
0 ignored issues
show
Bug introduced by
It seems like fields() 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

248
        $allFields = array_merge($this->/** @scrutinizer ignore-call */ fields(), [$fieldKey => $field]);
Loading history...
249
250
        $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

250
        $this->/** @scrutinizer ignore-call */ 
251
               setOperationSetting('fields', $allFields);
Loading history...
251
    }
252
253
    /**
254
     * Get the string that should be used as an array key, for the attributive array
255
     * where the fields are stored for the current operation.
256
     *
257
     * The array key for the field should be:
258
     * - name (if the name is a string)
259
     * - name1_name2_name3 (if the name is an array)
260
     *
261
     * @param  array  $field  Field definition array.
262
     * @return string The string that should be used as array key.
263
     */
264
    protected function getFieldKey($field)
265
    {
266
        if (is_array($field['name'])) {
267
            return implode('_', $field['name']);
268
        }
269
270
        return $field['name'];
271
    }
272
}
273