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 — eager-load-when-edition ( 7ddd83 )
by Pedro
10:43
created

Read::getDefaultPageLength()   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 0
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 Backpack\CRUD\app\Exceptions\BackpackProRequiredException;
6
use Exception;
7
use Illuminate\Support\Str;
8
9
/**
10
 * Properties and methods used by the List operation.
11
 */
12
trait Read
13
{
14
    /**
15
     * Find and retrieve the id of the current entry.
16
     *
17
     * @return int|bool The id in the db or false.
18
     */
19
    public function getCurrentEntryId()
20
    {
21
        if ($this->entry) {
22
            return $this->entry->getKey();
23
        }
24
25
        $params = \Route::current()->parameters();
26
27
        return  // use the entity name to get the current entry
28
                // this makes sure the ID is corrent even for nested resources
29
                $this->getRequest()->input($this->entity_name) ??
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

29
                $this->/** @scrutinizer ignore-call */ 
30
                       getRequest()->input($this->entity_name) ??
Loading history...
30
                // otherwise use the next to last parameter
31
                array_values($params)[count($params) - 1] ??
32
                // otherwise return false
33
                false;
34
    }
35
36
    /**
37
     * Find and retrieve the current entry.
38
     *
39
     * @return \Illuminate\Database\Eloquent\Model|bool The row in the db or false.
40
     */
41
    public function getCurrentEntry()
42
    {
43
        $id = $this->getCurrentEntryId();
44
45
        if ($id === false) {
46
            return false;
47
        }
48
49
        return $this->getEntry($id);
50
    }
51
52
    /**
53
     * Find and retrieve an entry in the database or fail.
54
     *
55
     * @param int The id of the row in the db to fetch.
0 ignored issues
show
Bug introduced by
The type Backpack\CRUD\app\Library\CrudPanel\Traits\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
56
     * @return \Illuminate\Database\Eloquent\Model The row in the db.
57
     */
58
    public function getEntry($id)
59
    {
60
        if (! $this->entry) {
61
            $this->eagerLoadRelationships('fields');
62
            $this->entry = $this->query->findOrFail($id);
0 ignored issues
show
Bug Best Practice introduced by
The property entry does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
63
            $this->entry = $this->entry->withFakes();
64
        }
65
66
        return $this->entry;
67
    }
68
69
    /**
70
     * Find and retrieve an entry in the database or fail.
71
     * When found, make sure we set the Locale on it.
72
     *
73
     * @param int The id of the row in the db to fetch.
74
     * @return \Illuminate\Database\Eloquent\Model The row in the db.
75
     */
76
    public function getEntryWithLocale($id)
77
    {
78
        if (! $this->entry) {
79
            $this->entry = $this->getEntry($id);
0 ignored issues
show
Bug Best Practice introduced by
The property entry does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
80
        }
81
82
        if ($this->entry->translationEnabled()) {
83
            $locale = request('_locale', \App::getLocale());
84
            if (in_array($locale, array_keys($this->entry->getAvailableLocales()))) {
85
                $this->entry->setLocale($locale);
86
            }
87
        }
88
89
        return $this->entry;
90
    }
91
92
    /**
93
     * Return a Model builder instance with the current crud query applied.
94
     *
95
     * @return \Illuminate\Database\Eloquent\Builder
96
     */
97
    public function getModelWithCrudPanelQuery()
98
    {
99
        return $this->model->setQuery($this->query->getQuery());
100
    }
101
102
    /**
103
     * Find and retrieve an entry in the database or fail.
104
     *
105
     * @param int The id of the row in the db to fetch.
106
     * @return \Illuminate\Database\Eloquent\Model The row in the db.
107
     */
108
    public function getEntryWithoutFakes($id)
109
    {
110
        return $this->getModelWithCrudPanelQuery()->findOrFail($id);
111
    }
112
113
    /**
114
     * Make the query JOIN all relationships used in the columns, too,
115
     * so there will be less database queries overall.
116
     */
117
    public function autoEagerLoadRelationshipColumns()
118
    {
119
        $relationships = $this->getColumnsRelationships();
0 ignored issues
show
Bug introduced by
It seems like getColumnsRelationships() 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

119
        /** @scrutinizer ignore-call */ 
120
        $relationships = $this->getColumnsRelationships();
Loading history...
120
121
        foreach ($relationships as $relation) {
122
            if (strpos($relation, '.') !== false) {
123
                $parts = explode('.', $relation);
124
                $model = $this->model;
125
126
                // Iterate over each relation part to find the valid relations without attributes
127
                // We should eager load the relation but not the attribute
128
                foreach ($parts as $i => $part) {
129
                    try {
130
                        $model = $model->$part()->getRelated();
131
                    } catch (Exception $e) {
132
                        $relation = join('.', array_slice($parts, 0, $i));
133
                    }
134
                }
135
            }
136
            $this->with($relation);
0 ignored issues
show
Bug introduced by
It seems like with() 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

136
            $this->/** @scrutinizer ignore-call */ 
137
                   with($relation);
Loading history...
137
        }
138
    }
139
140
    public function eagerLoadRelationships(string $definitions)
141
    {
142
        $definitions = $this->{$definitions}();
143
        $relationStrings = [];
144
145
        foreach ($definitions as $definitionName => $definition) {
146
            $relationString = $definition['entity'] ?? '';
147
148
            if (strpos($relationString, '.') !== false) {
149
                $relationAttribute = $definition['attribute'] ?? null;
150
151
                if ($relationAttribute) {
152
                    $relationString = Str::endsWith($relationString, $relationAttribute) ? Str::beforeLast($relationString, '.') : $relationString;
153
                } else {
154
                    $parts = explode('.', $relationString);
155
                    $model = $this->model;
156
157
                    foreach ($parts as $i => $part) {
158
                        try {
159
                            $model = $model->$part()->getRelated();
160
                        } catch (Exception $e) {
161
                            break;
162
                        }
163
                    }
164
165
                    $relationString = implode('.', array_slice($parts, 0, $i));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $i does not seem to be defined for all execution paths leading up to this point.
Loading history...
166
                }
167
            }
168
169
            if ($relationString) {
170
                $relationStrings[] = $relationString;
171
            }
172
        }
173
       
174
        $this->with(array_unique($relationStrings));
175
    }
176
177
178
179
    /**
180
     * Get all entries from the database.
181
     *
182
     * @return array|\Illuminate\Database\Eloquent\Collection
183
     */
184
    public function getEntries()
185
    {
186
        $this->autoEagerLoadRelationshipColumns();
187
188
        $entries = $this->query->get();
189
190
        // add the fake columns for each entry
191
        foreach ($entries as $key => $entry) {
192
            $entry->addFakes($this->getFakeColumnsAsArray());
0 ignored issues
show
Bug introduced by
It seems like getFakeColumnsAsArray() 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

192
            $entry->addFakes($this->/** @scrutinizer ignore-call */ getFakeColumnsAsArray());
Loading history...
193
        }
194
195
        return $entries;
196
    }
197
198
    /**
199
     * Enable the DETAILS ROW functionality:.
200
     *
201
     * In the table view, show a plus sign next to each entry.
202
     * When clicking that plus sign, an AJAX call will bring whatever content you want from the EntityCrudController::showDetailsRow($id) and show it to the user.
203
     */
204
    public function enableDetailsRow()
205
    {
206
        if (! backpack_pro()) {
207
            throw new BackpackProRequiredException('Details row');
208
        }
209
210
        $this->setOperationSetting('detailsRow', true);
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

210
        $this->/** @scrutinizer ignore-call */ 
211
               setOperationSetting('detailsRow', true);
Loading history...
211
    }
212
213
    /**
214
     * Disable the DETAILS ROW functionality:.
215
     */
216
    public function disableDetailsRow()
217
    {
218
        $this->setOperationSetting('detailsRow', false);
219
    }
220
221
    /**
222
     * Add two more columns at the beginning of the ListEntrie table:
223
     * - one shows the checkboxes needed for bulk actions
224
     * - one is blank, in order for evenual detailsRow or expand buttons
225
     * to be in a separate column.
226
     */
227
    public function enableBulkActions()
228
    {
229
        $this->setOperationSetting('bulkActions', true);
230
    }
231
232
    /**
233
     * Remove the two columns needed for bulk actions.
234
     */
235
    public function disableBulkActions()
236
    {
237
        $this->setOperationSetting('bulkActions', false);
238
239
        $this->removeColumn('bulk_actions');
0 ignored issues
show
Bug introduced by
It seems like removeColumn() 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

239
        $this->/** @scrutinizer ignore-call */ 
240
               removeColumn('bulk_actions');
Loading history...
240
    }
241
242
    /**
243
     * Set the number of rows that should be show on the list view.
244
     */
245
    public function setDefaultPageLength($value)
246
    {
247
        $this->abortIfInvalidPageLength($value);
248
249
        $this->setOperationSetting('defaultPageLength', $value);
250
    }
251
252
    /**
253
     * Get the number of rows that should be show on the list view.
254
     *
255
     * @return int
256
     */
257
    public function getDefaultPageLength()
258
    {
259
        return $this->getOperationSetting('defaultPageLength') ?? config('backpack.crud.operations.list.defaultPageLength') ?? 25;
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

259
        return $this->/** @scrutinizer ignore-call */ getOperationSetting('defaultPageLength') ?? config('backpack.crud.operations.list.defaultPageLength') ?? 25;
Loading history...
260
    }
261
262
    /**
263
     * If a custom page length was specified as default, make sure it
264
     * also show up in the page length menu.
265
     */
266
    public function addCustomPageLengthToPageLengthMenu()
267
    {
268
        $values = $this->getOperationSetting('pageLengthMenu')[0];
269
        $labels = $this->getOperationSetting('pageLengthMenu')[1];
270
271
        if (array_search($this->getDefaultPageLength(), $values) === false) {
272
            for ($i = 0; $i < count($values); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
273
                if ($values[$i] > $this->getDefaultPageLength() || $values[$i] === -1) {
274
                    array_splice($values, $i, 0, $this->getDefaultPageLength());
275
                    array_splice($labels, $i, 0, $this->getDefaultPageLength());
276
                    break;
277
                }
278
                if ($i === count($values) - 1) {
279
                    $values[] = $this->getDefaultPageLength();
280
                    $labels[] = $this->getDefaultPageLength();
281
                    break;
282
                }
283
            }
284
        }
285
286
        $this->setOperationSetting('pageLengthMenu', [$values, $labels]);
287
    }
288
289
    /**
290
     * Specify array of available page lengths on the list view.
291
     *
292
     * @param  array|int  $menu
293
     *
294
     * https://backpackforlaravel.com/docs/4.1/crud-cheat-sheet#page-length
295
     */
296
    public function setPageLengthMenu($menu)
297
    {
298
        if (is_array($menu)) {
299
            // start checking $menu integrity
300
            if (count($menu) !== count($menu, COUNT_RECURSIVE)) {
301
                // developer defined as setPageLengthMenu([[50, 100, 300]]) or setPageLengthMenu([[50, 100, 300],['f','h','t']])
302
                // we will apply the same labels as the values to the menu if developer didn't
303
                $this->abortIfInvalidPageLength($menu[0]);
304
305
                if (! isset($menu[1]) || ! is_array($menu[1])) {
306
                    $menu[1] = $menu[0];
307
                }
308
            } else {
309
                // developer defined setPageLengthMenu([10 => 'f', 100 => 'h', 300 => 't']) OR setPageLengthMenu([50, 100, 300])
310
                $menu = $this->buildPageLengthMenuFromArray($menu);
311
            }
312
        } else {
313
            // developer added only a single value setPageLengthMenu(10)
314
            $this->abortIfInvalidPageLength($menu);
315
316
            $menu = [[$menu], [$menu]];
317
        }
318
319
        $this->setOperationSetting('pageLengthMenu', $menu);
320
    }
321
322
    /**
323
     * Builds the menu from the given array. It works out with two different types of arrays:
324
     *  [1, 2, 3] AND [1 => 'one', 2 => 'two', 3 => 'three'].
325
     *
326
     * @param  array  $menu
327
     * @return array
328
     */
329
    private function buildPageLengthMenuFromArray($menu)
330
    {
331
        // check if the values of the array are strings, in case developer defined:
332
        // setPageLengthMenu([0 => 'f', 100 => 'h', 300 => 't'])
333
        if (count(array_filter(array_values($menu), 'is_string')) > 0) {
334
            $values = array_keys($menu);
335
            $labels = array_values($menu);
336
337
            $this->abortIfInvalidPageLength($values);
338
339
            return [$values, $labels];
340
        } else {
341
            // developer defined length as setPageLengthMenu([50, 100, 300])
342
            // we will use the same values as labels
343
            $this->abortIfInvalidPageLength($menu);
344
345
            return [$menu, $menu];
346
        }
347
    }
348
349
    /**
350
     * Get page length menu for the list view.
351
     *
352
     * @return array
353
     */
354
    public function getPageLengthMenu()
355
    {
356
        // if we have a 2D array, update all the values in the right hand array to their translated values
357
        if (isset($this->getOperationSetting('pageLengthMenu')[1]) && is_array($this->getOperationSetting('pageLengthMenu')[1])) {
358
            $aux = $this->getOperationSetting('pageLengthMenu');
359
            foreach ($this->getOperationSetting('pageLengthMenu')[1] as $key => $val) {
360
                $aux[1][$key] = trans($val);
361
            }
362
            $this->setOperationSetting('pageLengthMenu', $aux);
363
        }
364
        $this->addCustomPageLengthToPageLengthMenu();
365
366
        return $this->getOperationSetting('pageLengthMenu');
367
    }
368
369
    /**
370
     * Checks if the provided PageLength segment is valid.
371
     *
372
     * @param  array|int  $value
373
     * @return void
374
     */
375
    private function abortIfInvalidPageLength($value)
376
    {
377
        if ($value === 0 || (is_array($value) && in_array(0, $value))) {
378
            abort(500, 'You should not use 0 as a key in paginator. If you are looking for "ALL" option, use -1 instead.');
379
        }
380
    }
381
382
    /*
383
    |--------------------------------------------------------------------------
384
    |                                EXPORT BUTTONS
385
    |--------------------------------------------------------------------------
386
    */
387
388
    /**
389
     * Tell the list view to show the DataTables export buttons.
390
     */
391
    public function enableExportButtons()
392
    {
393
        if (! backpack_pro()) {
394
            throw new BackpackProRequiredException('Export buttons');
395
        }
396
397
        $this->setOperationSetting('exportButtons', true);
398
        $this->setOperationSetting('showTableColumnPicker', true);
399
        $this->setOperationSetting('showExportButton', true);
400
    }
401
402
    /**
403
     * Check if export buttons are enabled for the table view.
404
     *
405
     * @return bool
406
     */
407
    public function exportButtons()
408
    {
409
        return $this->getOperationSetting('exportButtons') ?? false;
410
    }
411
}
412