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 — master (#4161)
by
unknown
15:22
created

ColumnsProtectedMethods::makeSureColumnHasType()   D

Complexity

Conditions 24
Paths 74

Size

Total Lines 60
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 24
eloc 42
c 3
b 1
f 0
nc 74
nop 1
dl 0
loc 60
rs 4.1666

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 ColumnsProtectedMethods
9
{
10
    /**
11
     * Add a column to the current operation, using the Setting API.
12
     *
13
     * @param  array  $column  Column definition array.
14
     */
15
    protected function addColumnToOperationSettings($column)
16
    {
17
        $allColumns = $this->columns();
0 ignored issues
show
Bug introduced by
It seems like columns() 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
        /** @scrutinizer ignore-call */ 
18
        $allColumns = $this->columns();
Loading history...
18
        $allColumns = Arr::add($allColumns, $column['key'], $column);
19
20
        $this->setOperationSetting('columns', $allColumns);
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

20
        $this->/** @scrutinizer ignore-call */ 
21
               setOperationSetting('columns', $allColumns);
Loading history...
21
    }
22
23
    /**
24
     * If a column priority has not been defined, provide a default one.
25
     *
26
     * @param  array  $column  Column definition array.
27
     * @return array Proper array defining the column.
28
     */
29
    protected function makeSureColumnHasPriority($column)
30
    {
31
        $columns_count = $this->countColumnsWithoutActions();
0 ignored issues
show
Bug introduced by
It seems like countColumnsWithoutActions() 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
        /** @scrutinizer ignore-call */ 
32
        $columns_count = $this->countColumnsWithoutActions();
Loading history...
32
        $assumed_priority = $columns_count ? $columns_count : 0;
33
34
        $column['priority'] = $column['priority'] ?? $assumed_priority;
35
36
        return $column;
37
    }
38
39
    /**
40
     * If the field definition array is actually a string, it means the programmer was lazy
41
     * and has only passed the name of the column. Turn that into a proper array.
42
     *
43
     * @param  array  $column  Column definition array.
44
     * @return array Proper array defining the column.
45
     */
46
    protected function makeSureColumnHasName($column)
47
    {
48
        if (is_string($column)) {
0 ignored issues
show
introduced by
The condition is_string($column) is always false.
Loading history...
49
            $column = ['name' => $column];
50
        }
51
52
        if (is_array($column) && ! isset($column['name'])) {
53
            $column['name'] = 'anonymous_column_'.Str::random(5);
54
        }
55
56
        return $column;
57
    }
58
59
    /**
60
     * If a column array is missing the "label" attribute, an ugly error would be show.
61
     * So we add the field Name as a label - it's better than nothing.
62
     *
63
     * @param  array  $column  Column definition array.
64
     * @return array Proper array defining the column.
65
     */
66
    protected function makeSureColumnHasLabel($column)
67
    {
68
        if (! isset($column['label'])) {
69
            $column['label'] = mb_ucfirst($this->makeLabel($column['name']));
0 ignored issues
show
Bug introduced by
It seems like makeLabel() 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

69
            $column['label'] = mb_ucfirst($this->/** @scrutinizer ignore-call */ makeLabel($column['name']));
Loading history...
70
        }
71
72
        return $column;
73
    }
74
75
    /**
76
     * If a column definition is missing the type, set a default.
77
     *
78
     * @param  array  $column  Column definition array.
79
     * @return array Column definition array with type.
80
     */
81
    protected function makeSureColumnHasType($column)
82
    {
83
        // Do not alter type if it has been set by developer
84
        if (isset($column['type'])) {
85
            return $column;
86
        }
87
88
        // Set text as default column type
89
        $column['type'] = 'text';
90
91
        if (method_exists($this->model, 'translationEnabledForModel') && $this->model->translationEnabledForModel() && array_key_exists($column['name'], $this->model->getTranslations())) {
92
            return $column;
93
        }
94
95
        $could_be_relation = Arr::get($column, 'entity', false) !== false;
96
97
        if ($could_be_relation) {
98
            $column['type'] = $this->inferFieldTypeFromRelationType($column['relation_type']);
0 ignored issues
show
Bug introduced by
It seems like inferFieldTypeFromRelationType() 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

98
            /** @scrutinizer ignore-call */ 
99
            $column['type'] = $this->inferFieldTypeFromRelationType($column['relation_type']);
Loading history...
99
        }
100
101
        if (in_array($column['name'], $this->model->getDates())) {
102
            $column['type'] = 'datetime';
103
        }
104
105
        if ($this->model->hasCast($column['name'])) {
106
            $attributeType = $this->model->getCasts()[$column['name']];
107
108
            switch ($attributeType) {
109
                case 'array':
110
                case 'encrypted:array':
111
                case 'collection':
112
                case 'encrypted:collection':
113
                    $column['type'] = 'array';
114
                    break;
115
                case 'json':
116
                case 'object':
117
                    $column['type'] = 'json';
118
                    break;
119
                case 'bool':
120
                case 'boolean':
121
                    $column['type'] = 'check';
122
                    break;
123
                case 'date':
124
                    $column['type'] = 'date';
125
                    break;
126
                case 'datetime':
127
                    $column['type'] = 'datetime';
128
                    break;
129
                case 'double':
130
                case 'float':
131
                case 'int':
132
                case 'integer':
133
                case 'real':
134
                case 'timestamp':
135
                    $column['type'] = 'number';
136
                    break;
137
            }
138
        }
139
140
        return $column;
141
    }
142
143
    /**
144
     * If a column definition is missing the key, set the default.
145
     * The key is used when storing all columns using the Settings API,
146
     * it is used as the "key" of the associative array that holds all columns.
147
     *
148
     * @param  array  $column  Column definition array.
149
     * @return array Column definition array with key.
150
     */
151
    protected function makeSureColumnHasKey($column)
152
    {
153
        if (! isset($column['key'])) {
154
            $column['key'] = str_replace('.', '__', $column['name']);
155
        }
156
157
        return $column;
158
    }
159
160
    /**
161
     * If a column definition is missing the wrapper element, set the default (empty).
162
     * The wrapper is the HTML element that wrappes around the column text.
163
     * By defining this array a developer can wrap the text into an anchor (link),
164
     * span, div or whatever they want.
165
     *
166
     * @param  array  $column  Column definition array.
167
     * @return array Column definition array with wrapper.
168
     */
169
    protected function makeSureColumnHasWrapper($column)
170
    {
171
        if (! isset($column['wrapper'])) {
172
            $column['wrapper'] = [];
173
        }
174
175
        return $column;
176
    }
177
178
    protected function makeSureColumnHasEntity($column)
179
    {
180
        if (isset($column['entity'])) {
181
            return $column;
182
        }
183
184
        // if the name is an array it's definitely not a relationship
185
        if (is_array($column['name'])) {
186
            return $column;
187
        }
188
189
        // if the name is dot notation it might be a relationship
190
        if (strpos($column['name'], '.') !== false) {
191
            $possibleMethodName = Str::before($column['name'], '.');
192
193
            // if the first part of the string exists as method,
194
            // it is a relationship
195
            if (method_exists($this->model, $possibleMethodName)) {
196
197
                // if it has parameters it's not a relation method.
198
                $column['entity'] = $this->modelMethodHasParameters($this->model, $possibleMethodName) ? false : $column['name'];
0 ignored issues
show
Bug introduced by
It seems like modelMethodHasParameters() 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

198
                $column['entity'] = $this->/** @scrutinizer ignore-call */ modelMethodHasParameters($this->model, $possibleMethodName) ? false : $column['name'];
Loading history...
199
200
                $parts = explode('.', $column['entity']);
201
202
                $attribute_in_relation = false;
203
204
                $model = $this->model;
205
206
                // here we are going to iterate through all relation parts to check
207
                // if the attribute is present in the relation string.
208
                foreach ($parts as $i => $part) {
209
                    try {
210
                        $model = $model->$part()->getRelated();
211
                    } catch (\Exception $e) {
212
                        $attribute_in_relation = true;
213
                    }
214
                }
215
                // if the user setup the attribute in relation string, we are not going to infer that attribute from model
216
                // instead we get the defined attribute by the user.
217
                if ($attribute_in_relation) {
218
                    $column['attribute'] = $column['attribute'] ?? end($parts);
219
                }
220
221
                return $column;
222
            }
223
        }
224
225
        // if there's a method on the model with this name
226
        if (method_exists($this->model, $column['name'])) {
227
228
            // if it has parameters it's not a relation method.
229
            $column['entity'] = $this->modelMethodHasParameters($this->model, $column['name']) ? false : $column['name'];
230
231
            return $column;
232
        }
233
234
        // if the name ends with _id and that method exists,
235
        // we can probably use it as an entity
236
        if (Str::endsWith($column['name'], '_id')) {
237
            $possibleMethodName = Str::replaceLast('_id', '', $column['name']);
238
239
            if (method_exists($this->model, $possibleMethodName)) {
240
241
                // if it has parameters it's not a relation method.
242
                $column['entity'] = $this->modelMethodHasParameters($this->model, $possibleMethodName) ? false : $possibleMethodName;
243
244
                return $column;
245
            }
246
        }
247
248
        return $column;
249
    }
250
251
    /**
252
     * If an entity has been defined for the column, but no model,
253
     * determine the model from that relationship.
254
     *
255
     * @param  array  $column  Column definition array.
256
     * @return array Column definition array with model.
257
     */
258
    protected function makeSureColumnHasModel($column)
259
    {
260
        // if this is a relation type field and no corresponding model was specified,
261
        // get it from the relation method defined in the main model
262
        if (isset($column['entity']) && $column['entity'] !== false && ! isset($column['model'])) {
263
            $column['model'] = $this->getRelationModel($column['entity']);
0 ignored issues
show
Bug introduced by
It seems like getRelationModel() 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

263
            /** @scrutinizer ignore-call */ 
264
            $column['model'] = $this->getRelationModel($column['entity']);
Loading history...
264
        }
265
266
        return $column;
267
    }
268
269
    /**
270
     * If an entity has been defined for the column, but no relation type,
271
     * determine the relation type from that relationship.
272
     *
273
     * @param  array  $column  Column definition array.
274
     * @return array Column definition array with model.
275
     */
276
    protected function makeSureColumnHasRelationType($column)
277
    {
278
        if (isset($column['entity']) && $column['entity'] !== false) {
279
            $column['relation_type'] = $column['relation_type'] ?? $this->inferRelationTypeFromRelationship($column);
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

279
            $column['relation_type'] = $column['relation_type'] ?? $this->/** @scrutinizer ignore-call */ inferRelationTypeFromRelationship($column);
Loading history...
280
        }
281
282
        return $column;
283
    }
284
285
    /**
286
     * Move the most recently added column before or after the given target column. Default is before.
287
     *
288
     * @param  string|array  $targetColumn  The target column name or array.
289
     * @param  bool  $before  If true, the column will be moved before the target column, otherwise it will be moved after it.
290
     */
291
    protected function moveColumn($targetColumn, $before = true)
292
    {
293
        // TODO: this and the moveField method from the Fields trait should be refactored into a single method and moved
294
        //       into a common class
295
        $targetColumnName = is_array($targetColumn) ? $targetColumn['name'] : $targetColumn;
296
        $columnsArray = $this->columns();
297
298
        if (array_key_exists($targetColumnName, $columnsArray)) {
299
            $targetColumnPosition = $before ? array_search($targetColumnName, array_keys($columnsArray)) :
300
                array_search($targetColumnName, array_keys($columnsArray)) + 1;
301
302
            $element = array_pop($columnsArray);
303
            $beginningPart = array_slice($columnsArray, 0, $targetColumnPosition, true);
0 ignored issues
show
Bug introduced by
It seems like $targetColumnPosition can also be of type string; however, parameter $length of array_slice() does only seem to accept integer|null, 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

303
            $beginningPart = array_slice($columnsArray, 0, /** @scrutinizer ignore-type */ $targetColumnPosition, true);
Loading history...
304
            $endingArrayPart = array_slice($columnsArray, $targetColumnPosition, null, true);
0 ignored issues
show
Bug introduced by
It seems like $targetColumnPosition can also be of type string; however, parameter $offset of array_slice() does only seem to accept integer, 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

304
            $endingArrayPart = array_slice($columnsArray, /** @scrutinizer ignore-type */ $targetColumnPosition, null, true);
Loading history...
305
306
            $columnsArray = array_merge($beginningPart, [$element['name'] => $element], $endingArrayPart);
307
            $this->setOperationSetting('columns', $columnsArray);
308
        }
309
    }
310
311
    /**
312
     * Check if the column exists in the database, as a DB column.
313
     *
314
     * @param  string  $table
315
     * @param  string  $name
316
     * @return bool
317
     */
318
    protected function hasDatabaseColumn($table, $name)
319
    {
320
        static $cache = [];
321
322
        if (! $this->driverIsSql()) {
0 ignored issues
show
Bug introduced by
It seems like driverIsSql() 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

322
        if (! $this->/** @scrutinizer ignore-call */ driverIsSql()) {
Loading history...
323
            return true;
324
        }
325
326
        if (isset($cache[$table])) {
327
            $columns = $cache[$table];
328
        } else {
329
            $columns = $cache[$table] = $this->getSchema()->getColumnListing($table);
0 ignored issues
show
Bug introduced by
It seems like getSchema() 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

329
            $columns = $cache[$table] = $this->/** @scrutinizer ignore-call */ getSchema()->getColumnListing($table);
Loading history...
330
        }
331
332
        return in_array($name, $columns);
333
    }
334
}
335