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 Failed
Pull Request — master (#3448)
by
unknown
15:21
created

Search::getCellView()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Carbon\Carbon;
6
use Validator;
7
8
trait Search
9
{
10
    /*
11
    |--------------------------------------------------------------------------
12
    |                                   SEARCH
13
    |--------------------------------------------------------------------------
14
    */
15
16
    /**
17
     * Add conditions to the CRUD query for a particular search term.
18
     *
19
     * @param string $searchTerm Whatever string the user types in the search bar.
20
     *
21
     * @return \Illuminate\Database\Eloquent\Builder
22
     */
23
    public function applySearchTerm($searchTerm)
24
    {
25
        return $this->query->where(function ($query) use ($searchTerm) {
26
            foreach ($this->columns() as $column) {
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

26
            foreach ($this->/** @scrutinizer ignore-call */ columns() as $column) {
Loading history...
27
                if (! isset($column['type'])) {
28
                    abort(400, 'Missing column type when trying to apply search term.');
29
                }
30
31
                $this->applySearchLogicForColumn($query, $column, $searchTerm);
32
            }
33
        });
34
    }
35
36
    /**
37
     * Apply the search logic for each CRUD column.
38
     */
39
    public function applySearchLogicForColumn($query, $column, $searchTerm)
40
    {
41
        $columnType = $column['type'];
42
43
        // if there's a particular search logic defined, apply that one
44
        if (isset($column['searchLogic'])) {
45
            $searchLogic = $column['searchLogic'];
46
47
            // if a closure was passed, execute it
48
            if (is_callable($searchLogic)) {
49
                return $searchLogic($query, $column, $searchTerm);
50
            }
51
52
            // if a string was passed, search like it was that column type
53
            if (is_string($searchLogic)) {
54
                $columnType = $searchLogic;
55
            }
56
57
            // if false was passed, don't search this column
58
            if ($searchLogic == false) {
59
                return;
60
            }
61
        }
62
63
        // sensible fallback search logic, if none was explicitly given
64
        if ($column['tableColumn']) {
65
            switch ($columnType) {
66
                case 'email':
67
                case 'text':
68
                case 'textarea':
69
                    $query->orWhere($this->getColumnWithTableNamePrefixed($query, $column['name']), 'like', '%'.$searchTerm.'%');
70
                    break;
71
72
                case 'date':
73
                case 'datetime':
74
                    $validator = Validator::make(['value' => $searchTerm], ['value' => 'date']);
75
76
                    if ($validator->fails()) {
77
                        break;
78
                    }
79
80
                    $query->orWhereDate($this->getColumnWithTableNamePrefixed($query, $column['name']), Carbon::parse($searchTerm));
81
                    break;
82
83
                case 'select':
84
                case 'select_multiple':
85
                    $query->orWhereHas($column['entity'], function ($q) use ($column, $searchTerm) {
86
                        $q->where($this->getColumnWithTableNamePrefixed($q, $column['attribute']), 'like', '%'.$searchTerm.'%');
87
                    });
88
                    break;
89
90
                default:
91
                    return;
92
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
93
            }
94
        }
95
    }
96
97
    // -------------------------
98
    // Responsive Table
99
    // -------------------------
100
101
    /**
102
     * Tell the list view to NOT show a reponsive DataTable.
103
     *
104
     * @param bool $value
105
     */
106
    public function setResponsiveTable($value = true)
107
    {
108
        $this->setOperationSetting('responsiveTable', $value);
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

108
        $this->/** @scrutinizer ignore-call */ 
109
               setOperationSetting('responsiveTable', $value);
Loading history...
109
    }
110
111
    /**
112
     * Check if responsiveness is enabled for the table view.
113
     *
114
     * @return bool
115
     */
116
    public function getResponsiveTable()
117
    {
118
        if ($this->getOperationSetting('responsiveTable') !== null) {
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

118
        if ($this->/** @scrutinizer ignore-call */ getOperationSetting('responsiveTable') !== null) {
Loading history...
119
            return $this->getOperationSetting('responsiveTable');
120
        }
121
122
        return config('backpack.crud.operations.list.responsiveTable');
123
    }
124
125
    /**
126
     * Remember to show a responsive table.
127
     */
128
    public function enableResponsiveTable()
129
    {
130
        $this->setResponsiveTable(true);
131
    }
132
133
    /**
134
     * Remember to show a table with horizontal scrolling.
135
     */
136
    public function disableResponsiveTable()
137
    {
138
        $this->setResponsiveTable(false);
139
    }
140
141
    // -------------------------
142
    // Persistent Table
143
    // -------------------------
144
145
    /**
146
     * Tell the list view to NOT store datatable information in local storage.
147
     *
148
     * @param bool $value
149
     */
150
    public function setPersistentTable($value = true)
151
    {
152
        return $this->setOperationSetting('persistentTable', $value);
153
    }
154
155
    /**
156
     * Check if saved state is enabled for the table view.
157
     *
158
     * @return bool
159
     */
160
    public function getPersistentTable()
161
    {
162
        if ($this->getOperationSetting('persistentTable') !== null) {
163
            return $this->getOperationSetting('persistentTable');
164
        }
165
166
        return config('backpack.crud.operations.list.persistentTable');
167
    }
168
169
    /**
170
     * Get duration for persistent table.
171
     *
172
     * @return bool
173
     */
174
    public function getPersistentTableDuration()
175
    {
176
        if ($this->getOperationSetting('persistentTableDuration') !== null) {
177
            return $this->getOperationSetting('persistentTableDuration');
178
        }
179
180
        return config('backpack.crud.operations.list.persistentTableDuration', false);
181
    }
182
183
    /**
184
     * Remember to show a persistent table.
185
     */
186
    public function enablePersistentTable()
187
    {
188
        return $this->setPersistentTable(true);
189
    }
190
191
    /**
192
     * Remember to show a table that doesn't store URLs and pagination in local storage.
193
     */
194
    public function disablePersistentTable()
195
    {
196
        return $this->setPersistentTable(false);
197
    }
198
199
    /**
200
     * Get the HTML of the cells in a table row, for a certain DB entry.
201
     *
202
     * @param \Illuminate\Database\Eloquent\Model $entry     A db entry of the current entity;
203
     * @param bool|int                            $rowNumber The number shown to the user as row number (index);
204
     *
205
     * @return array Array of HTML cell contents.
206
     */
207
    public function getRowViews($entry, $rowNumber = false)
208
    {
209
        $row_items = [];
210
211
        foreach ($this->columns() as $key => $column) {
212
            $row_items[] = $this->getCellView($column, $entry, $rowNumber);
213
        }
214
215
        // add the buttons as the last column
216
        if ($this->buttons()->where('stack', 'line')->count()) {
0 ignored issues
show
Bug introduced by
It seems like buttons() 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

216
        if ($this->/** @scrutinizer ignore-call */ buttons()->where('stack', 'line')->count()) {
Loading history...
217
            $row_items[] = \View::make('crud::inc.button_stack', ['stack' => 'line'])
218
                                ->with('crud', $this)
219
                                ->with('entry', $entry)
220
                                ->with('row_number', $rowNumber)
221
                                ->render();
222
        }
223
224
        // add the details_row button to the first column
225
        if ($this->getOperationSetting('detailsRow')) {
226
            $details_row_button = \View::make('crud::columns.inc.details_row_button')
227
                                           ->with('crud', $this)
228
                                           ->with('entry', $entry)
229
                                           ->with('row_number', $rowNumber)
230
                                           ->render();
231
            $row_items[0] = $details_row_button.$row_items[0];
0 ignored issues
show
Bug introduced by
Are you sure $details_row_button of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

231
            $row_items[0] = /** @scrutinizer ignore-type */ $details_row_button.$row_items[0];
Loading history...
232
        }
233
234
        return $row_items;
235
    }
236
237
    /**
238
     * Get the HTML of a cell, using the column types.
239
     *
240
     * @param array                               $column
241
     * @param \Illuminate\Database\Eloquent\Model $entry     A db entry of the current entity;
242
     * @param bool|int                            $rowNumber The number shown to the user as row number (index);
243
     *
244
     * @return string
245
     */
246
    public function getCellView($column, $entry, $rowNumber = false)
247
    {
248
        return $this->renderCellView($this->getCellViewName($column), $column, $entry, $rowNumber);
249
    }
250
251
    /**
252
     * Get the name of the view to load for the cell.
253
     *
254
     * @param array $column
255
     *
256
     * @return string
257
     */
258
    private function getCellViewName($column)
259
    {
260
        // return custom column if view_namespace attribute is set
261
        if (isset($column['view_namespace']) && isset($column['type'])) {
262
            return $column['view_namespace'].'.'.$column['type'];
263
        }
264
265
        if (isset($column['type'])) {
266
            // if the column has been overwritten return that one
267
            if (view()->exists('vendor.backpack.crud.columns.'.$column['type'])) {
268
                return 'vendor.backpack.crud.columns.'.$column['type'];
269
            }
270
271
            // return the column from the package
272
            return 'crud::columns.'.$column['type'];
273
        }
274
275
        // fallback to text column
276
        return 'crud::columns.text';
277
    }
278
279
    /**
280
     * Render the given view.
281
     *
282
     * @param string   $view
283
     * @param array    $column
284
     * @param object   $entry
285
     * @param bool|int $rowNumber The number shown to the user as row number (index)
286
     *
287
     * @return string
288
     */
289
    private function renderCellView($view, $column, $entry, $rowNumber = false)
290
    {
291
        if (! view()->exists($view)) {
292
            $view = 'crud::columns.text'; // fallback to text column
293
        }
294
295
        return \View::make($view)
0 ignored issues
show
Bug Best Practice introduced by
The expression return View::make($view)..., $rowNumber)->render() also could return the type array which is incompatible with the documented return type string.
Loading history...
296
            ->with('crud', $this)
297
            ->with('column', $column)
298
            ->with('entry', $entry)
299
            ->with('rowNumber', $rowNumber)
300
            ->render();
301
    }
302
303
    /**
304
     * Created the array to be fed to the data table.
305
     *
306
     * @param array    $entries      Eloquent results.
307
     * @param int      $totalRows
308
     * @param int      $filteredRows
309
     * @param bool|int $startIndex
310
     *
311
     * @return array
312
     */
313
    public function getEntriesAsJsonForDatatables($entries, $totalRows, $filteredRows, $startIndex = false)
314
    {
315
        $rows = [];
316
317
        foreach ($entries as $row) {
318
            $rows[] = $this->getRowViews($row, $startIndex === false ? false : ++$startIndex);
319
        }
320
321
        return [
322
            'draw'            => (isset($this->getRequest()['draw']) ? (int) $this->getRequest()['draw'] : 0),
0 ignored issues
show
Bug introduced by
It seems like getRequest() 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
            'draw'            => (isset($this->/** @scrutinizer ignore-call */ getRequest()['draw']) ? (int) $this->getRequest()['draw'] : 0),
Loading history...
323
            'recordsTotal'    => $totalRows,
324
            'recordsFiltered' => $filteredRows,
325
            'data'            => $rows,
326
        ];
327
    }
328
329
    /**
330
     * Return the column attribute (column in database) prefixed with table to use in search.
331
     *
332
     * @param \Illuminate\Database\Eloquent\Builder $query
333
     * @param array $column
334
     * @return string
335
     */
336
    public function getColumnWithTableNamePrefixed($query, $column)
337
    {
338
        return $query->getModel()->getTableWithPrefix().'.'.$column;
0 ignored issues
show
Bug introduced by
Are you sure $column of type array can be used in concatenation? ( Ignorable by Annotation )

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

338
        return $query->getModel()->getTableWithPrefix().'.'./** @scrutinizer ignore-type */ $column;
Loading history...
339
    }
340
}
341