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 (#4002)
by
unknown
24:42 queued 09:36
created

ColumnsProtectedMethods::makeSureColumnHasType()   D

Complexity

Conditions 21
Paths 73

Size

Total Lines 56
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

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

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

259
            /** @scrutinizer ignore-call */ 
260
            $column['model'] = $this->getRelationModel($column['entity']);
Loading history...
260
        }
261
262
        return $column;
263
    }
264
265
    /**
266
     * Move the most recently added column before or after the given target column. Default is before.
267
     *
268
     * @param  string|array  $targetColumn  The target column name or array.
269
     * @param  bool  $before  If true, the column will be moved before the target column, otherwise it will be moved after it.
270
     */
271
    protected function moveColumn($targetColumn, $before = true)
272
    {
273
        // TODO: this and the moveField method from the Fields trait should be refactored into a single method and moved
274
        //       into a common class
275
        $targetColumnName = is_array($targetColumn) ? $targetColumn['name'] : $targetColumn;
276
        $columnsArray = $this->columns();
277
278
        if (array_key_exists($targetColumnName, $columnsArray)) {
279
            $targetColumnPosition = $before ? array_search($targetColumnName, array_keys($columnsArray)) :
280
                array_search($targetColumnName, array_keys($columnsArray)) + 1;
281
282
            $element = array_pop($columnsArray);
283
            $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

283
            $beginningPart = array_slice($columnsArray, 0, /** @scrutinizer ignore-type */ $targetColumnPosition, true);
Loading history...
284
            $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

284
            $endingArrayPart = array_slice($columnsArray, /** @scrutinizer ignore-type */ $targetColumnPosition, null, true);
Loading history...
285
286
            $columnsArray = array_merge($beginningPart, [$element['name'] => $element], $endingArrayPart);
287
            $this->setOperationSetting('columns', $columnsArray);
288
        }
289
    }
290
291
    /**
292
     * Check if the column exists in the database, as a DB column.
293
     *
294
     * @param  string  $table
295
     * @param  string  $name
296
     * @return bool
297
     */
298
    protected function hasDatabaseColumn($table, $name)
299
    {
300
        static $cache = [];
301
302
        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

302
        if (! $this->/** @scrutinizer ignore-call */ driverIsSql()) {
Loading history...
303
            return true;
304
        }
305
306
        if (isset($cache[$table])) {
307
            $columns = $cache[$table];
308
        } else {
309
            $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

309
            $columns = $cache[$table] = $this->/** @scrutinizer ignore-call */ getSchema()->getColumnListing($table);
Loading history...
310
        }
311
312
        return in_array($name, $columns);
313
    }
314
}
315