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

Completed
Push — v4dot1 ( f5ef1d...e6b5d2 )
by Cristian
20:40 queued 13:09
created

ColumnsProtectedMethods::hasColumn()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
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
     * The only REALLY MANDATORY attribute for a column is the 'name'.
12
     * Everything else, Backpack can probably guess.
13
     *
14
     * This method checks that all necessary attributes are set.
15
     * If not, it tries to guess them.
16
     *
17
     * @param  string|array $column The column definition array OR column name as string.
18
     * @return array                Proper column definition array.
19
     */
20
    protected function makeSureColumnHasNeededAttributes($column)
21
    {
22
        $column = $this->makeSureColumnHasName($column);
0 ignored issues
show
Bug introduced by
It seems like $column can also be of type string; however, Backpack\CRUD\app\Librar...makeSureColumnHasName() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
23
        $column = $this->makeSureColumnHasLabel($column);
24
        $column = $this->makeSureColumnHasType($column);
25
        $column = $this->makeSureColumnHasKey($column);
26
        $column = $this->makeSureColumnHasModel($column);
27
28
        // check if the column exists in the database (as a db column)
29
        $columnExistsInDb = $this->hasColumn($this->model->getTable(), $column['name']);
30
31
        // make sure column has tableColumn, orderable and searchLogic
32
        $column['tableColumn'] = $column['tableColumn'] ?? $columnExistsInDb;
33
        $column['orderable'] = $column['orderable'] ?? $columnExistsInDb;
34
        $column['searchLogic'] = $column['searchLogic'] ?? $columnExistsInDb;
35
36
        return $column;
37
    }
38
39
    /**
40
     * Add a column to the current operation, using the Setting API.
41
     *
42
     * @param array $column Column definition array.
43
     */
44
    protected function addColumnToOperationSettings($column)
45
    {
46
        $allColumns = $this->columns();
47
        $allColumns = Arr::add($allColumns, $column['key'], $column);
48
49
        $this->setOperationSetting('columns', $allColumns);
50
51
        // make sure the column has a priority in terms of visibility
52
        // if no priority has been defined, use the order in the array plus one
53
        if (! array_key_exists('priority', $column)) {
54
            $position_in_columns_array = (int) array_search($column['key'], array_keys($this->columns()));
55
            $allColumns[$column['key']]['priority'] = $position_in_columns_array + 1;
56
        }
57
58
        $this->setOperationSetting('columns', $allColumns);
59
    }
60
61
    /**
62
     * If the field definition array is actually a string, it means the programmer was lazy
63
     * and has only passed the name of the column. Turn that into a proper array.
64
     *
65
     * @param array $column Column definition array.
66
     * @return array         Proper array defining the column.
67
     */
68
    protected function makeSureColumnHasName($column)
69
    {
70
        if (is_string($column)) {
71
            $column = ['name' => $column];
72
        }
73
74
        if (is_array($column) && ! isset($column['name'])) {
75
            $column['name'] = 'anonymous_column_'.Str::random(5);
76
        }
77
78
        return $column;
79
    }
80
81
    /**
82
     * If a column array is missing the "label" attribute, an ugly error would be show.
83
     * So we add the field Name as a label - it's better than nothing.
84
     *
85
     * @param array     $column  Column definition array.
86
     * @return array            Proper array defining the column.
87
     */
88
    protected function makeSureColumnHasLabel($column)
89
    {
90
        if (! isset($column['label'])) {
91
            $column['label'] = mb_ucfirst($this->makeLabel($column['name']));
92
        }
93
94
        return $column;
95
    }
96
97
    /**
98
     * If a column definition is missing the type, set a default.
99
     *
100
     * @param array $column Column definition array.
101
     * @return array        Column definition array with type.
102
     */
103
    protected function makeSureColumnHasType($column)
104
    {
105
        if (! isset($column['type'])) {
106
            $column['type'] = 'text';
107
        }
108
109
        return $column;
110
    }
111
112
    /**
113
     * If a column definition is missing the key, set the default.
114
     * The key is used when storing all columns using the Settings API,
115
     * it is used as the "key" of the associative array that holds all columns.
116
     *
117
     * @param array $column Column definition array.
118
     * @return array        Column definition array with key.
119
     */
120
    protected function makeSureColumnHasKey($column)
121
    {
122
        if (! isset($column['key'])) {
123
            $column['key'] = str_replace('.', '__', $column['name']);
124
        }
125
126
        return $column;
127
    }
128
129
    /**
130
     * If an entity has been defined for the column, but no model,
131
     * determine the model from that relationship.
132
     *
133
     * @param array $column Column definition array.
134
     * @return array        Column definition array with model.
135
     */
136
    protected function makeSureColumnHasModel($column)
137
    {
138
        // if this is a relation type field and no corresponding model was specified,
139
        // get it from the relation method defined in the main model
140
        if (isset($column['entity']) && ! isset($column['model'])) {
141
            $column['model'] = $this->getRelationModel($column['entity']);
142
        }
143
144
        return $column;
145
    }
146
147
    /**
148
     * Move the most recently added column before or after the given target column. Default is before.
149
     *
150
     * @param string|array $targetColumn The target column name or array.
151
     * @param bool         $before       If true, the column will be moved before the target column, otherwise it will be moved after it.
152
     */
153
    protected function moveColumn($targetColumn, $before = true)
154
    {
155
        // TODO: this and the moveField method from the Fields trait should be refactored into a single method and moved
156
        //       into a common class
157
        $targetColumnName = is_array($targetColumn) ? $targetColumn['name'] : $targetColumn;
158
        $columnsArray = $this->columns();
159
160
        if (array_key_exists($targetColumnName, $columnsArray)) {
161
            $targetColumnPosition = $before ? array_search($targetColumnName, array_keys($columnsArray)) :
162
                array_search($targetColumnName, array_keys($columnsArray)) + 1;
163
164
            $element = array_pop($columnsArray);
165
            $beginningPart = array_slice($columnsArray, 0, $targetColumnPosition, true);
166
            $endingArrayPart = array_slice($columnsArray, $targetColumnPosition, null, true);
167
168
            $columnsArray = array_merge($beginningPart, [$element['name'] => $element], $endingArrayPart);
169
            $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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
170
        }
171
    }
172
173
    /**
174
     * Check if the column exists in the database, as a DB column.
175
     *
176
     * @param string $table
177
     * @param string $name
178
     *
179
     * @return bool
180
     */
181
    protected function hasColumn($table, $name)
182
    {
183
        static $cache = [];
184
185
        if ($this->driverIsMongoDb()) {
0 ignored issues
show
Bug introduced by
It seems like driverIsMongoDb() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
186
            return true;
187
        }
188
189
        if (isset($cache[$table])) {
190
            $columns = $cache[$table];
191
        } else {
192
            $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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
193
        }
194
195
        return in_array($name, $columns);
196
    }
197
}
198