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

ColumnsProtectedMethods::makeSureColumnHasKey()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
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
use Illuminate\Support\Str;
8
9
trait ColumnsProtectedMethods
10
{
11
    /**
12
     * Add a column to the current operation, using the Setting API.
13
     *
14
     * @param  array  $column  Column definition array.
15
     */
16
    protected function addColumnToOperationSettings($column)
17
    {
18
        $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

18
        /** @scrutinizer ignore-call */ 
19
        $allColumns = $this->columns();
Loading history...
19
        $allColumns = Arr::add($allColumns, $column['key'], $column);
20
21
        $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

21
        $this->/** @scrutinizer ignore-call */ 
22
               setOperationSetting('columns', $allColumns);
Loading history...
22
    }
23
24
    /**
25
     * If a column priority has not been defined, provide a default one.
26
     *
27
     * @param  array  $column  Column definition array.
28
     * @return array Proper array defining the column.
29
     */
30
    protected function makeSureColumnHasPriority($column)
31
    {
32
        $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

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

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

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

198
                $column['entity'] = $this->/** @scrutinizer ignore-call */ modelMethodIsRelationship($this->model, $possibleMethodName) ? $column['name'] : false;
Loading history...
199
200
                if ($column['entity']) {
201
                    // if the user setup the attribute in relation string, we are not going to infer that attribute from model
202
                    // instead we get the defined attribute by the user.
203
                    if ($this->isAttributeInRelationString($column)) {
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

203
                    if ($this->/** @scrutinizer ignore-call */ isAttributeInRelationString($column)) {
Loading history...
204
                        $column['attribute'] = $column['attribute'] ?? Str::afterLast($column['entity'], '.');
205
                    }
206
                }
207
208
                return $column;
209
            }
210
        }
211
212
        // if there's a method on the model with this name
213
        if (method_exists($this->model, $column['name']) || $this->model->isRelation($column['name'])) {
214
            // check model method for possibility of being a relationship
215
            $column['entity'] = $this->modelMethodIsRelationship($this->model, $column['name']);
216
217
            return $column;
218
        }
219
220
        // if the name ends with _id and that method exists,
221
        // we can probably use it as an entity
222
        if (Str::endsWith($column['name'], '_id')) {
223
            $possibleMethodName = Str::replaceLast('_id', '', $column['name']);
224
225
            if (method_exists($this->model, $possibleMethodName)) {
226
                // check model method for possibility of being a relationship
227
                $column['entity'] = $this->modelMethodIsRelationship($this->model, $possibleMethodName);
228
229
                return $column;
230
            }
231
        }
232
233
        return $column;
234
    }
235
236
    /**
237
     * Infer the attribute for the column when needed.
238
     *
239
     * @param  array  $column
240
     * @return void
241
     */
242
    protected function makeSureColumnHasAttribute(array $column)
243
    {
244
        return $this->makeSureFieldHasAttribute($column);
0 ignored issues
show
Bug introduced by
It seems like makeSureFieldHasAttribute() 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

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

275
            $column['relation_type'] = $column['relation_type'] ?? $this->/** @scrutinizer ignore-call */ inferRelationTypeFromRelationship($column);
Loading history...
276
        }
277
278
        return $column;
279
    }
280
281
    /**
282
     * Move the most recently added column before or after the given target column. Default is before.
283
     *
284
     * @param  string|array  $targetColumn  The target column name or array.
285
     * @param  bool  $before  If true, the column will be moved before the target column, otherwise it will be moved after it.
286
     */
287
    protected function moveColumn($targetColumn, $before = true)
288
    {
289
        // TODO: this and the moveField method from the Fields trait should be refactored into a single method and moved
290
        //       into a common class
291
        $targetColumnName = is_array($targetColumn) ? $targetColumn['name'] : $targetColumn;
292
        $columnsArray = $this->columns();
293
294
        if (array_key_exists($targetColumnName, $columnsArray)) {
295
            $targetColumnPosition = $before ? array_search($targetColumnName, array_keys($columnsArray)) :
296
                array_search($targetColumnName, array_keys($columnsArray)) + 1;
297
298
            $element = array_pop($columnsArray);
299
300
            if ($element['priority'] === count($columnsArray)) {
301
                // the priority was most likely auto-set as it corresponds to the column array count
302
                // update the priority to the target column position
303
                $element['priority'] = $targetColumnPosition;
304
            }
305
306
            $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

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

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

325
        if (! $this->/** @scrutinizer ignore-call */ driverIsSql()) {
Loading history...
326
            return true;
327
        }
328
329
        if (isset($cache[$table])) {
330
            $columns = $cache[$table];
331
        } else {
332
            $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

332
            $columns = $cache[$table] = $this->/** @scrutinizer ignore-call */ getSchema()->getColumnListing($table);
Loading history...
333
        }
334
335
        return in_array($name, $columns);
336
    }
337
338
    /**
339
     * Prepare the column attributes and add it to operation settings.
340
     */
341
    private function prepareAttributesAndAddColumn(array|string $column): CrudColumn
342
    {
343
        $column = $this->makeSureColumnHasNeededAttributes($column);
0 ignored issues
show
Bug introduced by
The method makeSureColumnHasNeededAttributes() does not exist on Backpack\CRUD\app\Librar...ColumnsProtectedMethods. Did you maybe mean makeSureColumnHasAttribute()? ( Ignorable by Annotation )

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

343
        /** @scrutinizer ignore-call */ 
344
        $column = $this->makeSureColumnHasNeededAttributes($column);

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...
344
        $this->addColumnToOperationSettings($column);
345
346
        $column = (new CrudColumn($column['name']))->callRegisteredAttributeMacros();
347
348
        return $column;
349
    }
350
}
351