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 (#4161)
by
unknown
15:22
created

Search::getCellViewName()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 30
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 12
nc 6
nop 1
dl 0
loc 30
rs 8.8333
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
     * @return \Illuminate\Database\Eloquent\Builder
21
     */
22
    public function applySearchTerm($searchTerm)
23
    {
24
        return $this->query->where(function ($query) use ($searchTerm) {
25
            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

25
            foreach ($this->/** @scrutinizer ignore-call */ columns() as $column) {
Loading history...
26
                if (! isset($column['type'])) {
27
                    abort(400, 'Missing column type when trying to apply search term.');
28
                }
29
30
                $this->applySearchLogicForColumn($query, $column, $searchTerm);
31
            }
32
        });
33
    }
34
35
    /**
36
     * Apply the search logic for each CRUD column.
37
     */
38
    public function applySearchLogicForColumn($query, $column, $searchTerm)
39
    {
40
        $columnType = $column['type'];
41
42
        // if there's a particular search logic defined, apply that one
43
        if (isset($column['searchLogic'])) {
44
            $searchLogic = $column['searchLogic'];
45
46
            // if a closure was passed, execute it
47
            if (is_callable($searchLogic)) {
48
                return $searchLogic($query, $column, $searchTerm);
49
            }
50
51
            // if a string was passed, search like it was that column type
52
            if (is_string($searchLogic)) {
53
                $columnType = $searchLogic;
54
            }
55
56
            // if false was passed, don't search this column
57
            if ($searchLogic == false) {
58
                return;
59
            }
60
        }
61
62
        // sensible fallback search logic, if none was explicitly given
63
        if ($column['tableColumn']) {
64
            switch ($columnType) {
65
                case 'email':
66
                case 'text':
67
                case 'textarea':
68
                    $query->orWhere($this->getColumnWithTableNamePrefixed($query, $column['name']), 'like', '%'.$searchTerm.'%');
69
                    break;
70
71
                case 'date':
72
                case 'datetime':
73
                    $validator = Validator::make(['value' => $searchTerm], ['value' => 'date']);
74
75
                    if ($validator->fails()) {
76
                        break;
77
                    }
78
79
                    $query->orWhereDate($this->getColumnWithTableNamePrefixed($query, $column['name']), Carbon::parse($searchTerm));
80
                    break;
81
82
                case 'select':
83
                case 'select_multiple':
84
                    $query->orWhereHas($column['entity'], function ($q) use ($column, $searchTerm) {
85
                        $q->where($this->getColumnWithTableNamePrefixed($q, $column['attribute']), 'like', '%'.$searchTerm.'%');
86
                    });
87
                    break;
88
89
                default:
90
                    return;
91
                    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...
92
            }
93
        }
94
    }
95
96
    // -------------------------
97
    // Responsive Table
98
    // -------------------------
99
100
    /**
101
     * Tell the list view to NOT show a reponsive DataTable.
102
     *
103
     * @param  bool  $value
104
     */
105
    public function setResponsiveTable($value = true)
106
    {
107
        $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

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

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

214
        if ($this->/** @scrutinizer ignore-call */ buttons()->where('stack', 'line')->count()) {
Loading history...
215
            $row_items[] = \View::make('crud::inc.button_stack', ['stack' => 'line'])
216
                                ->with('crud', $this)
217
                                ->with('entry', $entry)
218
                                ->with('row_number', $rowNumber)
219
                                ->render();
220
        }
221
222
        // add the bulk actions checkbox to the first column
223
        if ($this->getOperationSetting('bulkActions')) {
224
            $bulk_actions_checkbox = \View::make('crud::columns.inc.bulk_actions_checkbox', ['entry' => $entry])->render();
225
            $row_items[0] = $bulk_actions_checkbox.$row_items[0];
226
        }
227
228
        // add the details_row button to the first column
229
        if ($this->getOperationSetting('detailsRow')) {
230
            $details_row_button = \View::make('crud::columns.inc.details_row_button')
231
                                           ->with('crud', $this)
232
                                           ->with('entry', $entry)
233
                                           ->with('row_number', $rowNumber)
234
                                           ->render();
235
            $row_items[0] = $details_row_button.$row_items[0];
236
        }
237
238
        return $row_items;
239
    }
240
241
    /**
242
     * Get the HTML of a cell, using the column types.
243
     *
244
     * @param  array  $column
245
     * @param  \Illuminate\Database\Eloquent\Model  $entry  A db entry of the current entity;
246
     * @param  bool|int  $rowNumber  The number shown to the user as row number (index);
247
     * @return string
248
     */
249
    public function getCellView($column, $entry, $rowNumber = false)
250
    {
251
        return $this->renderCellView($this->getCellViewName($column), $column, $entry, $rowNumber);
252
    }
253
254
    /**
255
     * Get the name of the view to load for the cell.
256
     *
257
     * @param  array  $column
258
     * @return string
259
     */
260
    private function getCellViewName($column)
261
    {
262
        // return custom column if view_namespace attribute is set
263
        if (isset($column['view_namespace']) && isset($column['type'])) {
264
            return $column['view_namespace'].'.'.$column['type'];
265
        }
266
267
        if (isset($column['type'])) {
268
            // create a list of paths to column blade views
269
            // including the configured view_namespaces
270
            $columnPaths = array_map(function ($item) use ($column) {
271
                return $item.'.'.$column['type'];
272
            }, config('backpack.crud.view_namespaces.columns'));
273
274
            // but always fall back to the stock 'text' column
275
            // if a view doesn't exist
276
            if (! in_array('crud::columns.text', $columnPaths)) {
277
                $columnPaths[] = 'crud::columns.text';
278
            }
279
280
            // return the first column blade file that exists
281
            foreach ($columnPaths as $path) {
282
                if (view()->exists($path)) {
283
                    return $path;
284
                }
285
            }
286
        }
287
288
        // fallback to text column
289
        return 'crud::columns.text';
290
    }
291
292
    /**
293
     * Render the given view.
294
     *
295
     * @param  string  $view
296
     * @param  array  $column
297
     * @param  object  $entry
298
     * @param  bool|int  $rowNumber  The number shown to the user as row number (index)
299
     * @return string
300
     */
301
    private function renderCellView($view, $column, $entry, $rowNumber = false)
302
    {
303
        if (! view()->exists($view)) {
304
            $view = 'crud::columns.text'; // fallback to text column
305
        }
306
307
        return \View::make($view)
308
            ->with('crud', $this)
309
            ->with('column', $column)
310
            ->with('entry', $entry)
311
            ->with('rowNumber', $rowNumber)
312
            ->render();
313
    }
314
315
    /**
316
     * Created the array to be fed to the data table.
317
     *
318
     * @param  array  $entries  Eloquent results.
319
     * @param  int  $totalRows
320
     * @param  int  $filteredRows
321
     * @param  bool|int  $startIndex
322
     * @return array
323
     */
324
    public function getEntriesAsJsonForDatatables($entries, $totalRows, $filteredRows, $startIndex = false)
325
    {
326
        $rows = [];
327
328
        foreach ($entries as $row) {
329
            $rows[] = $this->getRowViews($row, $startIndex === false ? false : ++$startIndex);
330
        }
331
332
        return [
333
            '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

333
            'draw'            => (isset($this->/** @scrutinizer ignore-call */ getRequest()['draw']) ? (int) $this->getRequest()['draw'] : 0),
Loading history...
334
            'recordsTotal'    => $totalRows,
335
            'recordsFiltered' => $filteredRows,
336
            'data'            => $rows,
337
        ];
338
    }
339
340
    /**
341
     * Return the column attribute (column in database) prefixed with table to use in search.
342
     *
343
     * @param  \Illuminate\Database\Eloquent\Builder  $query
344
     * @param  string  $column
345
     * @return string
346
     */
347
    public function getColumnWithTableNamePrefixed($query, $column)
348
    {
349
        return $query->getModel()->getTable().'.'.$column;
350
    }
351
}
352