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 — field-column-type ( 6ba61a...c0f245 )
by
unknown
13:45
created

Columns   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 416
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 96
c 3
b 0
f 0
dl 0
loc 416
rs 7.92
wmc 51

26 Methods

Rating   Name   Duplication   Size   Complexity  
A beforeColumn() 0 3 1
A makeFirstColumn() 0 8 2
A addColumns() 0 5 3
A afterColumn() 0 3 1
A columns() 0 3 1
A setColumns() 0 26 6
A countColumnsWithoutActions() 0 5 2
A column() 0 3 1
A addColumn() 0 6 1
A findColumnById() 0 5 1
A removeColumnAttribute() 0 7 1
A getActionsColumnPriority() 0 3 1
A setColumnLabel() 0 3 1
A hasColumnWhere() 0 7 2
A modifyColumn() 0 3 1
A removeAllColumns() 0 3 1
A removeColumns() 0 5 3
A firstColumnWhere() 0 4 2
A removeColumn() 0 5 1
A addDefaultTypeToColumn() 0 9 2
A setActionsColumnPriority() 0 5 1
A setColumnDetails() 0 11 3
A setColumnsDetails() 0 4 2
A makeSureColumnHasNeededAttributes() 0 30 6
A orderColumns() 0 15 4
A getColumnsRelationships() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like Columns 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 Columns, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Backpack\CRUD\app\Library\CrudPanel\CrudColumn;
6
use Illuminate\Support\Arr;
7
8
trait Columns
9
{
10
    use ColumnsProtectedMethods;
11
12
    // ------------
13
    // COLUMNS
14
    // ------------
15
16
    /**
17
     * Get the CRUD columns for the current operation.
18
     *
19
     * @return array CRUD columns.
20
     */
21
    public function columns()
22
    {
23
        return $this->getOperationSetting('columns') ?? [];
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

23
        return $this->/** @scrutinizer ignore-call */ getOperationSetting('columns') ?? [];
Loading history...
24
    }
25
26
    /**
27
     * Add a bunch of column names and their details to the CRUD object.
28
     *
29
     * @param  array|string  $columns
30
     */
31
    public function setColumns($columns)
32
    {
33
        // clear any columns already set
34
        $this->removeAllColumns();
35
36
        // if array, add a column for each of the items
37
        if (is_array($columns) && count($columns)) {
38
            foreach ($columns as $key => $column) {
39
                // if label and other details have been defined in the array
40
                if (is_array($column)) {
41
                    $this->addColumn($column);
42
                } else {
43
                    $this->addColumn([
44
                        'name'  => $column,
45
                        'label' => mb_ucfirst($column),
46
                        'type'  => 'text',
47
                    ]);
48
                }
49
            }
50
        }
51
52
        if (is_string($columns)) {
53
            $this->addColumn([
54
                'name'  => $columns,
55
                'label' => mb_ucfirst($columns),
56
                'type'  => 'text',
57
            ]);
58
        }
59
    }
60
61
    /**
62
     * Add a column at the end of to the CRUD object's "columns" array.
63
     *
64
     * @param  array|string  $column
65
     * @return self
66
     */
67
    public function addColumn($column)
68
    {
69
        $column = $this->makeSureColumnHasNeededAttributes($column);
70
        $this->addColumnToOperationSettings($column);
71
72
        return $this;
73
    }
74
75
    /**
76
     * Add multiple columns at the end of the CRUD object's "columns" array.
77
     *
78
     * @param  array  $columns
79
     */
80
    public function addColumns($columns)
81
    {
82
        if (count($columns)) {
83
            foreach ($columns as $key => $column) {
84
                $this->addColumn($column);
85
            }
86
        }
87
    }
88
89
    /**
90
     * Move the most recently added column after the given target column.
91
     *
92
     * @param  string|array  $targetColumn  The target column name or array.
93
     */
94
    public function afterColumn($targetColumn)
95
    {
96
        $this->moveColumn($targetColumn, false);
97
    }
98
99
    /**
100
     * Move the most recently added column before the given target column.
101
     *
102
     * @param  string|array  $targetColumn  The target column name or array.
103
     */
104
    public function beforeColumn($targetColumn)
105
    {
106
        $this->moveColumn($targetColumn);
107
    }
108
109
    /**
110
     * Move this column to be first in the columns list.
111
     *
112
     * @return bool|null
113
     */
114
    public function makeFirstColumn()
115
    {
116
        if (! $this->columns()) {
117
            return false;
118
        }
119
120
        $firstColumn = array_keys(array_slice($this->columns(), 0, 1))[0];
121
        $this->beforeColumn($firstColumn);
122
    }
123
124
    /**
125
     * Add the default column type to the given Column, inferring the type from the database column type.
126
     *
127
     * @param  array  $column
128
     * @return array|bool
129
     */
130
    public function addDefaultTypeToColumn($column)
131
    {
132
        if (array_key_exists('name', (array) $column)) {
133
            $default_type = $this->inferFieldTypeFromDbColumnType($column['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

133
            /** @scrutinizer ignore-call */ 
134
            $default_type = $this->inferFieldTypeFromDbColumnType($column['name']);
Loading history...
134
135
            return array_merge(['type' => $default_type], $column);
136
        }
137
138
        return false;
139
    }
140
141
    /**
142
     * Remove a column from the CRUD panel by name.
143
     *
144
     * @param  string  $columnKey  The column key.
145
     */
146
    public function removeColumn($columnKey)
147
    {
148
        $columnsArray = $this->columns();
149
        Arr::forget($columnsArray, $columnKey);
150
        $this->setOperationSetting('columns', $columnsArray);
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

150
        $this->/** @scrutinizer ignore-call */ 
151
               setOperationSetting('columns', $columnsArray);
Loading history...
151
    }
152
153
    /**
154
     * Remove multiple columns from the CRUD panel by name.
155
     *
156
     * @param  array  $columns  Array of column names.
157
     */
158
    public function removeColumns($columns)
159
    {
160
        if (! empty($columns)) {
161
            foreach ($columns as $columnKey) {
162
                $this->removeColumn($columnKey);
163
            }
164
        }
165
    }
166
167
    /**
168
     * Remove all columns from the CRUD panel.
169
     */
170
    public function removeAllColumns()
171
    {
172
        $this->setOperationSetting('columns', []);
173
    }
174
175
    /**
176
     * Remove an attribute from one column's definition array.
177
     *
178
     * @param  string  $column  The name of the column.
179
     * @param  string  $attribute  The name of the attribute being removed.
180
     */
181
    public function removeColumnAttribute($column, $attribute)
182
    {
183
        $columns = $this->columns();
184
185
        unset($columns[$column][$attribute]);
186
187
        $this->setOperationSetting('columns', $columns);
188
    }
189
190
    /**
191
     * Change attributes for multiple columns.
192
     *
193
     * @param  array  $columns
194
     * @param  array  $attributes
195
     */
196
    public function setColumnsDetails($columns, $attributes)
197
    {
198
        foreach ($columns as $columnKey) {
199
            $this->setColumnDetails($columnKey, $attributes);
200
        }
201
    }
202
203
    /**
204
     * Change attributes for a certain column.
205
     *
206
     * @param  string  $columnKey  Column key.
207
     * @param  array  $attributesAndValues
208
     */
209
    public function setColumnDetails($columnKey, $attributesAndValues)
210
    {
211
        $columnsArray = $this->columns();
212
213
        if (isset($columnsArray[$columnKey])) {
214
            foreach ($attributesAndValues as $attributeName => $attributeValue) {
215
                $columnsArray[$columnKey][$attributeName] = $attributeValue;
216
            }
217
        }
218
219
        $this->setOperationSetting('columns', $columnsArray);
220
    }
221
222
    /**
223
     * Alias for setColumnDetails().
224
     * Provides a consistent syntax with Fields, Buttons, Filters modify functionality.
225
     *
226
     * @param  string  $column  Column name.
227
     * @param  array  $attributes
228
     */
229
    public function modifyColumn($column, $attributes)
230
    {
231
        $this->setColumnDetails($column, $attributes);
232
    }
233
234
    /**
235
     * Set label for a specific column.
236
     *
237
     * @param  string  $column
238
     * @param  string  $label
239
     */
240
    public function setColumnLabel($column, $label)
241
    {
242
        $this->setColumnDetails($column, ['label' => $label]);
243
    }
244
245
    /**
246
     * Get the relationships used in the CRUD columns.
247
     *
248
     * @return array Relationship names
249
     */
250
    public function getColumnsRelationships()
251
    {
252
        $columns = $this->columns();
253
254
        return collect($columns)->pluck('entity')->reject(function ($value, $key) {
0 ignored issues
show
Bug introduced by
$columns of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
        return collect(/** @scrutinizer ignore-type */ $columns)->pluck('entity')->reject(function ($value, $key) {
Loading history...
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

254
        return collect($columns)->pluck('entity')->reject(function ($value, /** @scrutinizer ignore-unused */ $key) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
255
            return ! $value;
256
        })->toArray();
257
    }
258
259
    /**
260
     * Order the CRUD columns. If certain columns are missing from the given order array, they will be pushed to the
261
     * new columns array in the original order.
262
     *
263
     * @param  array  $order  An array of column names in the desired order.
264
     */
265
    public function orderColumns($order)
266
    {
267
        $orderedColumns = [];
268
        foreach ($order as $columnName) {
269
            if (array_key_exists($columnName, $this->columns())) {
270
                $orderedColumns[$columnName] = $this->columns()[$columnName];
271
            }
272
        }
273
274
        if (empty($orderedColumns)) {
275
            return;
276
        }
277
278
        $remaining = array_diff_key($this->columns(), $orderedColumns);
279
        $this->setOperationSetting('columns', array_merge($orderedColumns, $remaining));
280
    }
281
282
    /**
283
     * Get a column by the id, from the associative array.
284
     *
285
     * @param  int  $column_number  Placement inside the columns array.
286
     * @return array Column details.
287
     */
288
    public function findColumnById($column_number)
289
    {
290
        $result = array_slice($this->columns(), $column_number, 1);
291
292
        return reset($result);
293
    }
294
295
    /**
296
     * Get the visibility priority for the actions column
297
     * in the CRUD table view.
298
     *
299
     * @return int The priority, from 1 to infinity. Lower is better.
300
     */
301
    public function getActionsColumnPriority()
302
    {
303
        return (int) $this->getOperationSetting('actionsColumnPriority') ?? 1;
304
    }
305
306
    /**
307
     * Set a certain priority for the actions column
308
     * in the CRUD table view. Usually set to 10000 in order to hide it.
309
     *
310
     * @param  int  $number  The priority, from 1 to infinity. Lower is better.
311
     * @return self
312
     */
313
    public function setActionsColumnPriority($number)
314
    {
315
        $this->setOperationSetting('actionsColumnPriority', (int) $number);
316
317
        return $this;
318
    }
319
320
    /**
321
     * Check if a column exists, by any given attribute.
322
     *
323
     * @param  string  $attribute  Attribute name on that column definition array.
324
     * @param  string  $value  Value of that attribute on that column definition array.
325
     * @return bool
326
     */
327
    public function hasColumnWhere($attribute, $value)
328
    {
329
        $match = Arr::first($this->columns(), function ($column, $columnKey) use ($attribute, $value) {
0 ignored issues
show
Unused Code introduced by
The parameter $columnKey is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

329
        $match = Arr::first($this->columns(), function ($column, /** @scrutinizer ignore-unused */ $columnKey) use ($attribute, $value) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
330
            return isset($column[$attribute]) && $column[$attribute] == $value;
331
        });
332
333
        return (bool) $match;
334
    }
335
336
    /**
337
     * Get the first column where a given attribute has the given value.
338
     *
339
     * @param  string  $attribute  Attribute name on that column definition array.
340
     * @param  string  $value  Value of that attribute on that column definition array.
341
     * @return bool
342
     */
343
    public function firstColumnWhere($attribute, $value)
344
    {
345
        return Arr::first($this->columns(), function ($column, $columnKey) use ($attribute, $value) {
0 ignored issues
show
Unused Code introduced by
The parameter $columnKey is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

345
        return Arr::first($this->columns(), function ($column, /** @scrutinizer ignore-unused */ $columnKey) use ($attribute, $value) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
346
            return isset($column[$attribute]) && $column[$attribute] == $value;
347
        });
348
    }
349
350
    /**
351
     * The only REALLY MANDATORY attribute for a column is the 'name'.
352
     * Everything else, Backpack can probably guess.
353
     *
354
     * This method checks that all necessary attributes are set.
355
     * If not, it tries to guess them.
356
     *
357
     * @param  string|array  $column  The column definition array OR column name as string.
358
     * @return array Proper column definition array.
359
     */
360
    public function makeSureColumnHasNeededAttributes($column)
361
    {
362
        $column = $this->makeSureColumnHasName($column);
0 ignored issues
show
Bug introduced by
It seems like $column can also be of type string; however, parameter $column of Backpack\CRUD\app\Librar...makeSureColumnHasName() does only seem to accept array, 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

362
        $column = $this->makeSureColumnHasName(/** @scrutinizer ignore-type */ $column);
Loading history...
363
        $column = $this->makeSureColumnHasKey($column);
364
        $column = $this->makeSureColumnHasLabel($column);
365
        $column = $this->makeSureColumnHasEntity($column);
366
        $column = $this->makeSureColumnHasModel($column);
367
        $column = $this->makeSureColumnHasRelationType($column);
368
        $column = $this->makeSureColumnHasType($column);
369
        $column = $this->makeSureColumnHasPriority($column);
370
371
        if (isset($column['entity']) && $column['entity'] !== false) {
372
            $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

372
            /** @scrutinizer ignore-call */ 
373
            $column['relation_type'] = $this->inferRelationTypeFromRelationship($column);
Loading history...
373
        }
374
375
        // if there's a model defined, but no attribute
376
        // guess an attribute using the identifiableAttribute functionality in CrudTrait
377
        if (isset($column['model']) && ! isset($column['attribute']) && method_exists($column['model'], 'identifiableAttribute')) {
378
            $column['attribute'] = (new $column['model'])->identifiableAttribute();
379
        }
380
381
        // check if the column exists in the database (as a db column)
382
        $column_exists_in_db = $this->hasDatabaseColumn($this->model->getTable(), $column['name']);
383
384
        // make sure column has tableColumn, orderable and searchLogic
385
        $column['tableColumn'] = $column['tableColumn'] ?? $column_exists_in_db;
386
        $column['orderable'] = $column['orderable'] ?? $column_exists_in_db;
387
        $column['searchLogic'] = $column['searchLogic'] ?? $column_exists_in_db;
388
389
        return $column;
390
    }
391
392
    /**
393
     * Count the number of columns added so far.
394
     *
395
     * It will not take into account the action
396
     * columns (columns with buttons, checkbox).
397
     *
398
     * @return int
399
     */
400
    public function countColumnsWithoutActions()
401
    {
402
        return collect($this->columns())->filter(function ($column, $key) {
0 ignored issues
show
Bug introduced by
$this->columns() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

402
        return collect(/** @scrutinizer ignore-type */ $this->columns())->filter(function ($column, $key) {
Loading history...
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

402
        return collect($this->columns())->filter(function ($column, /** @scrutinizer ignore-unused */ $key) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
403
            return ! isset($column['hasActions']) || $column['hasActions'] == false;
404
        })->count();
405
    }
406
407
    /**
408
     * Create and return a CrudColumn object for that column name.
409
     *
410
     * Enables developers to use a fluent syntax to declare their columns,
411
     * in addition to the existing options:
412
     * - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
413
     * - CRUD::column('price')->type('number');
414
     *
415
     * And if the developer uses the CrudColumn object as Column in their CrudController:
416
     * - Column::name('price')->type('number');
417
     *
418
     * @param  string  $name  The name of the column in the db, or model attribute.
419
     * @return CrudColumn
420
     */
421
    public function column($name)
422
    {
423
        return new CrudColumn($name);
424
    }
425
}
426