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 — master ( 09870c...982029 )
by Cristian
77:39 queued 64:42
created

FetchOperation::fetch()   D

Complexity

Conditions 18
Paths 129

Size

Total Lines 84
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 13
Bugs 6 Features 3
Metric Value
cc 18
eloc 44
c 13
b 6
f 3
nc 129
nop 1
dl 0
loc 84
rs 4.625

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Backpack\CRUD\app\Http\Controllers\Operations;
4
5
use Illuminate\Support\Facades\Route;
6
use Illuminate\Support\Str;
7
8
trait FetchOperation
9
{
10
    /**
11
     * Define which routes are needed for this operation.
12
     *
13
     * @param string $segment    Name of the current entity (singular). Used as first URL segment.
14
     * @param string $routeName  Prefix of the route name.
15
     * @param string $controller Name of the current CrudController.
16
     */
17
    protected function setupFetchOperationRoutes($segment, $routeName, $controller)
18
    {
19
        // get all method names on the current model that start with "fetch" (ex: fetchCategory)
20
        // if a method that looks like that is present, it means we need to add the routes that fetch that entity
21
        preg_match_all('/(?<=^|;)fetch([^;]+?)(;|$)/', implode(';', get_class_methods($this)), $matches);
22
23
        if (count($matches[1])) {
24
            foreach ($matches[1] as $methodName) {
25
                Route::post($segment.'/fetch/'.Str::kebab($methodName), [
26
                    'uses'      => $controller.'@fetch'.$methodName,
27
                    'operation' => 'FetchOperation',
28
                ]);
29
            }
30
        }
31
    }
32
33
    /**
34
     * Gets items from database and returns to selects.
35
     *
36
     * @param string|array $arg
37
     * @return \Illuminate\Http\JsonResponse|Illuminate\Database\Eloquent\Collection|Illuminate\Pagination\LengthAwarePaginator
0 ignored issues
show
Bug introduced by
The type Backpack\CRUD\app\Http\C...on\LengthAwarePaginator was not found. Did you mean Illuminate\Pagination\LengthAwarePaginator? If so, make sure to prefix the type with \.
Loading history...
Bug introduced by
The type Backpack\CRUD\app\Http\C...ase\Eloquent\Collection was not found. Did you mean Illuminate\Database\Eloquent\Collection? If so, make sure to prefix the type with \.
Loading history...
38
     */
39
    private function fetch($arg)
40
    {
41
        // get the actual words that were used to search for an item (the search term / search string)
42
        $search_string = request()->input('q') ?? false;
43
44
        // if the Class was passed as the sole argument, use that as the configured Model
45
        // otherwise assume the arguments are actually the configuration array
46
        $config = [];
47
48
        if (! is_array($arg)) {
49
            if (! class_exists($arg)) {
50
                return response()->json(['error' => 'Class: '.$arg.' does not exists'], 500);
51
            }
52
            $config['model'] = $arg;
53
        } else {
54
            $config = $arg;
55
        }
56
57
        $model_instance = new $config['model'];
58
        // set configuration defaults
59
        $config['paginate'] = isset($config['paginate']) ? $config['paginate'] : 10;
60
        $config['searchable_attributes'] = $config['searchable_attributes'] ?? $model_instance->identifiableAttribute();
61
        $config['query'] = isset($config['query']) && is_callable($config['query']) ? $config['query']($model_instance) : $model_instance; // if a closure that has been passed as "query", use the closure - otherwise use the model
62
63
        // FetchOperation is aware of an optional parameter 'keys' that will fetch you the entity/entities that match the provided keys
64
        if (request()->has('keys')) {
65
            $array_keys = request()->get('keys');
66
            if (is_array($array_keys)) {
67
                return $model_instance->whereIn($model_instance->getKeyName(), $array_keys)->get();
68
            } else {
69
                return $model_instance->where($model_instance->getKeyName(), $array_keys)->get();
70
            }
71
        }
72
73
        // FetchOperation sends an empty query to retrieve the default entry for select when field is not nullable.
74
        // Also sends an empty query in case we want to load all entities to emulate non-ajax fields
75
        // when using InlineCreate.
76
77
        if ($search_string === false) {
78
            return ($config['paginate'] !== false) ?
79
            $config['query']->paginate($config['paginate']) :
80
            $config['query']->get();
81
        }
82
83
        $textColumnTypes = ['string', 'json_string', 'text', 'longText', 'json_array'];
84
85
        // if the query builder brings any where clause already defined by the user we must
86
        // ensure that the where prevails and we should only use our search as a complement to the query constraints.
87
        // e.g user want only the active products, so in fetch he would return something like:
88
        // .... 'query' => function($model) { return $model->where('active', 1); }
89
        // So it reads: SELECT ... WHERE active = 1 AND (XXX = x OR YYY = y) and not SELECT ... WHERE active = 1 AND XXX = x OR YYY = y;
90
91
        if (! empty($config['query']->getQuery()->wheres)) {
92
            $config['query'] = $config['query']->where(function ($query) use ($model_instance, $config, $search_string, $textColumnTypes) {
93
                foreach ((array) $config['searchable_attributes'] as $k => $searchColumn) {
94
                    $operation = ($k == 0) ? 'where' : 'orWhere';
95
                    $columnType = $model_instance->getColumnType($searchColumn);
96
97
                    if (in_array($columnType, $textColumnTypes)) {
98
                        $tempQuery = $query->{$operation}($searchColumn, 'LIKE', '%'.$search_string.'%');
99
                    } else {
100
                        $tempQuery = $query->{$operation}($searchColumn, $search_string);
101
                    }
102
                }
103
104
                return $tempQuery;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tempQuery seems to be defined by a foreach iteration on line 93. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
105
            });
106
        } else {
107
            foreach ((array) $config['searchable_attributes'] as $k => $searchColumn) {
108
                $operation = ($k == 0) ? 'where' : 'orWhere';
109
                $columnType = $model_instance->getColumnType($searchColumn);
110
111
                if (in_array($columnType, $textColumnTypes)) {
112
                    $config['query'] = $config['query']->{$operation}($searchColumn, 'LIKE', '%'.$search_string.'%');
113
                } else {
114
                    $config['query'] = $config['query']->{$operation}($searchColumn, $search_string);
115
                }
116
            }
117
        }
118
119
        // return the results with or without pagination
120
        return ($config['paginate'] !== false) ?
121
                    $config['query']->paginate($config['paginate']) :
122
                    $config['query']->get();
123
    }
124
}
125