Passed
Push — master ( dd30a0...b64fc0 )
by Jonathan
17:19
created

ListController::buildContentQuery()   B

Complexity

Conditions 10
Paths 11

Size

Total Lines 45
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
c 1
b 0
f 0
dl 0
loc 45
rs 7.6666
cc 10
nc 11
nop 0

How to fix   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 Uccello\Core\Http\Controllers\Core;
4
5
use Schema;
6
use Illuminate\Http\Request;
7
use Spatie\Searchable\Search;
0 ignored issues
show
Bug introduced by
The type Spatie\Searchable\Search 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...
8
use Uccello\Core\Models\Domain;
9
use Uccello\Core\Models\Module;
10
use Uccello\Core\Facades\Uccello;
11
use Uccello\Core\Models\Relatedlist;
12
use Uccello\Core\Models\Filter;
13
14
class ListController extends Controller
15
{
16
    protected $viewName = 'list.main';
17
18
    /**
19
     * Check user permissions
20
     */
21
    protected function checkPermissions()
22
    {
23
        $this->middleware('uccello.permissions:retrieve');
24
    }
25
26
    /**
27
     * @inheritDoc
28
     */
29
    public function process(?Domain $domain, Module $module, Request $request)
30
    {
31
        // Pre-process
32
        $this->preProcess($domain, $module, $request);
33
34
        // Selected filter
35
        if ($request->input('filter')) {
36
            $selectedFilterId = $request->input('filter');
37
            $selectedFilter = Filter::find($selectedFilterId);
38
        }
39
40
        if (empty($selectedFilter)) { // For example if the given filter does not exist
41
            $selectedFilter = $module->filters()->where('type', 'list')->first();
42
            $selectedFilterId = $selectedFilter->id;
43
        }
44
45
        // Get datatable columns
46
        $datatableColumns = Uccello::getDatatableColumns($module, $selectedFilterId);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $selectedFilterId does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
The method getDatatableColumns() does not exist on Uccello\Core\Facades\Uccello. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

46
        /** @scrutinizer ignore-call */ 
47
        $datatableColumns = Uccello::getDatatableColumns($module, $selectedFilterId);
Loading history...
47
48
        // Get filters
49
        $filters = Filter::where('module_id', $module->id)
50
            ->where('type', 'list')
51
            ->get();
52
53
        // Order by
54
        $filterOrderBy = (array) $selectedFilter->order_by;
55
56
        return $this->autoView(compact('datatableColumns', 'filters', 'selectedFilter', 'filterOrderBy'));
57
    }
58
59
    /**
60
     * Display a listing of the resources.
61
     * The result is formated differently if it is a classic query or one requested by datatable.
62
     * Filter on domain if domain_id column exists.
63
     * @param  \Uccello\Core\Models\Domain|null $domain
64
     * @param  \Uccello\Core\Models\Module $module
65
     * @param  \Illuminate\Http\Request $request
66
     * @return \Illuminate\Http\Response
67
     */
68
    public function processForContent(?Domain $domain, Module $module, Request $request)
69
    {
70
        $length = (int)$request->get('length') ?? env('UCCELLO_ITEMS_PER_PAGE', 15);
71
72
        $recordId = $request->get('id');
73
        $relatedListId = $request->get('relatedlist');
74
        $action = $request->get('action');
75
76
        // Pre-process
77
        $this->preProcess($domain, $module, $request, false);
78
79
        // Get model model class
80
        $modelClass = $module->model_class;
0 ignored issues
show
Bug introduced by
The property model_class does not seem to exist on Uccello\Core\Models\Module. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
81
82
        // Check if the class exists
83
        if (!class_exists($modelClass)) {
84
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
85
        }
86
87
        // Build query
88
        $query = $this->buildContentQuery();
89
90
        // Limit the number maximum of items per page
91
        $maxItemsPerPage = env('UCCELLO_MAX_ITEMS_PER_PAGE', 100);
92
        if ($length > $maxItemsPerPage) {
93
            $length = $maxItemsPerPage;
94
        }
95
96
        // If the query is for a related list, add conditions
97
        if ($relatedListId && $action !== 'select') {
98
            // Get related list
99
            $relatedList = Relatedlist::find($relatedListId);
100
101
            if ($relatedList && $relatedList->method) {
0 ignored issues
show
Bug introduced by
The property method does not seem to exist on Uccello\Core\Models\Relatedlist. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
102
                // Related list method
103
                $method = $relatedList->method;
104
105
                // Update query
106
                $model = new $modelClass;
107
                $records = $model->$method($relatedList, $recordId, $query)->paginate($length);
108
            }
109
        } elseif ($relatedListId && $action === 'select') {
110
            // Get related list
111
            $relatedList = Relatedlist::find($relatedListId);
112
113
            if ($relatedList && $relatedList->method) {
114
                // Related list method
115
                $method = $relatedList->method;
116
                $recordIdsMethod = $method . 'RecordIds';
117
118
                // Get related records ids
119
                $model = new $modelClass;
120
                $filteredRecordIds = $model->$recordIdsMethod($relatedList, $recordId);
121
122
                // Add the record id itself to be filtered
123
                if ($relatedList->module_id === $relatedList->related_module_id && !empty($recordId) && !$filteredRecordIds->contains($recordId)) {
0 ignored issues
show
Bug introduced by
The property module_id does not exist on Uccello\Core\Models\Relatedlist. Did you mean module?
Loading history...
Bug introduced by
The property related_module_id does not exist on Uccello\Core\Models\Relatedlist. Did you mean module?
Loading history...
124
                    $filteredRecordIds[] = (int)$recordId;
125
                }
126
127
                // Make the quer
128
                $records = $query->whereNotIn($model->getKeyName(), $filteredRecordIds)->paginate($length);
129
            }
130
        } else {
131
            // Paginate results
132
            $records = $query->paginate($length);
133
        }
134
135
        $records->getCollection()->transform(function ($record) use ($domain, $module) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $records does not seem to be defined for all execution paths leading up to this point.
Loading history...
136
            foreach ($module->fields as $field) {
137
                // If a special template exists, use it. Else use the generic template
138
                $uitype = uitype($field->uitype_id);
139
                $uitypeViewName = sprintf('uitypes.list.%s', $uitype->name);
140
                $uitypeFallbackView = 'uccello::modules.default.uitypes.list.text';
141
                $uitypeViewToInclude = uccello()->view($uitype->package, $module, $uitypeViewName, $uitypeFallbackView);
0 ignored issues
show
Bug introduced by
Are you sure the usage of uccello() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
142
                $record->{$field->name.'_html'} = view()->make($uitypeViewToInclude, compact('domain', 'module', 'record', 'field'))->render();
143
            }
144
145
            // Add primary key name and value
146
            $record->__primaryKey = $record->getKey();
147
            $record->__primaryKeyName = $record->getKeyName();
148
149
            return $record;
150
        });
151
152
        return $records;
153
    }
154
155
    /**
156
     * Autocomplete a listing of the resources.
157
     * The result is formated differently if it is a classic query or one requested by datatable.
158
     * Filter on domain if domain_id column exists.
159
     * @param  \Uccello\Core\Models\Domain|null $domain
160
     * @param  \Uccello\Core\Models\Module $module
161
     * @param  \Illuminate\Http\Request $request
162
     * @return \Illuminate\Http\Response
163
     */
164
    public function processForAutocomplete(?Domain $domain, Module $module, Request $request)
165
    {
166
        // If we don't use multi domains, find the first one
167
        if (!uccello()->useMultiDomains()) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of uccello() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
168
            $domain = Domain::first();
0 ignored issues
show
Unused Code introduced by
The assignment to $domain is dead and can be removed.
Loading history...
169
        }
170
171
        // Query
172
        $q = $request->get('q');
173
        // Model class
174
        $modelClass = $module->model_class;
0 ignored issues
show
Bug introduced by
The property model_class does not seem to exist on Uccello\Core\Models\Module. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
175
176
        $results = collect();
177
        if (method_exists($modelClass, 'getSearchResult') && property_exists($modelClass, 'searchableColumns')) {
178
            $searchResults = new Search();
179
            $searchResults->registerModel($modelClass, (array) (new $modelClass)->searchableColumns);
180
            $results = $searchResults->search($q)->take(config('uccello.max_results.autocomplete', 10));
181
        }
182
183
        return $results;
184
    }
185
186
    /**
187
     * Save list filter into database
188
     *
189
     * @param \Uccello\Core\Models\Domain|null $domain
190
     * @param \Uccello\Core\Models\Module $module
191
     * @param \Illuminate\Http\Request $request
192
     * @return \Illuminate\Http\Response
193
     */
194
    public function saveFilter(?Domain $domain, Module $module, Request $request)
195
    {
196
        $saveOrder = $request->input('save_order');
197
        $savePageLength = $request->input('save_page_length');
198
199
        // Optional data
200
        $data = [];
201
        if ($savePageLength) {
202
            $data["length"] = $request->input('page_length');
203
        }
204
205
        $filter = Filter::firstOrNew([
206
            'domain_id' => $domain->id,
207
            'module_id' => $module->id,
208
            'user_id' => auth()->id(),
209
            'name' => $request->input('name'),
210
            'type' => $request->input('type')
211
        ]);
212
        $filter->columns = $request->input('columns');
0 ignored issues
show
Bug introduced by
The property columns does not seem to exist on Uccello\Core\Models\Filter. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
213
        $filter->conditions = $request->input('conditions') ?? null;
0 ignored issues
show
Bug introduced by
The property conditions does not seem to exist on Uccello\Core\Models\Filter. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
214
        $filter->order_by = $saveOrder ? $request->input('order') : null;
0 ignored issues
show
Bug introduced by
The property order_by does not seem to exist on Uccello\Core\Models\Filter. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
215
        $filter->is_default = $request->input('default');
0 ignored issues
show
Bug introduced by
The property is_default does not seem to exist on Uccello\Core\Models\Filter. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
216
        $filter->is_public = $request->input('public');
0 ignored issues
show
Bug introduced by
The property is_public does not seem to exist on Uccello\Core\Models\Filter. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
217
        $filter->data = !empty($data) ? $data : null;
0 ignored issues
show
Bug introduced by
The property data does not seem to exist on Uccello\Core\Models\Filter. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
218
        $filter->save();
219
220
        return $filter;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $filter returns the type Uccello\Core\Models\Filter which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
221
    }
222
223
    /**
224
     * Retrieve a filter by its id and delete it
225
     *
226
     * @param \Uccello\Core\Models\Domain|null $domain
227
     * @param \Uccello\Core\Models\Module $module
228
     * @param \Illuminate\Http\Request $request
229
     * @return \Illuminate\Http\Response
230
     */
231
    public function deleteFilter(?Domain $domain, Module $module, Request $request)
232
    {
233
        // Retrieve filter by id
234
        $filterId = $request->input('id');
235
        $filter = Filter::find($filterId);
236
237
        if ($filter) {
238
            if ($filter->readOnly) {
239
                // Response
240
                $success = false;
241
                $message = uctrans('error.filter.read_only', $module);
242
            } else {
243
                // Delete
244
                $filter->delete();
245
246
                // Response
247
                $success = true;
248
                $message = uctrans('success.filter.deleted', $module);
249
            }
250
        } else {
251
            // Response
252
            $success = false;
253
            $message = uctrans('error.filter.not_found', $module);
254
        }
255
256
        return [
257
            'success' => $success,
258
            'message' => $message
259
        ];
260
    }
261
262
    /**
263
     * Build query for retrieving content
264
     *
265
     * @return \Illuminate\Database\Eloquent\Builder;
266
     */
267
    protected function buildContentQuery()
268
    {
269
        $order = $this->request->get('order');
270
        $columns = $this->request->get('columns');
271
272
        $domain = $this->domain;
0 ignored issues
show
Unused Code introduced by
The assignment to $domain is dead and can be removed.
Loading history...
273
        $module = $this->module;
274
275
        // Get model model class
276
        $modelClass = $module->model_class;
0 ignored issues
show
Bug introduced by
The property model_class does not seem to exist on Uccello\Core\Models\Module. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
277
278
        // Check if the class exists
279
        if (!class_exists($modelClass) || !method_exists($modelClass, 'scopeInDomain')) {
280
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
281
        }
282
283
        // Filter on domain if column exists
284
        $query = $modelClass::inDomain($this->domain, $this->request->get('descendants'));
285
286
        // Search by column
287
        foreach ($columns as $fieldName => $column) {
288
            if (!empty($column[ "search" ])) {
289
                $searchValue = $column[ "search" ];
290
            } else {
291
                $searchValue = null;
292
            }
293
294
            // Get field by name and search by field column
295
            $field = $module->getField($fieldName);
296
            if (isset($searchValue) && !is_null($field)) {
297
                $uitype = uitype($field->uitype_id);
0 ignored issues
show
Bug introduced by
The property uitype_id does not exist on Uccello\Core\Models\Field. Did you mean uitype?
Loading history...
298
                $query = $uitype->addConditionToSearchQuery($query, $field, $searchValue);
299
            }
300
        }
301
302
        // Order results
303
        if (!empty($order)) {
304
            foreach ($order as $fieldColumn => $value) {
305
                if (!is_null($field)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $field seems to be defined by a foreach iteration on line 287. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
306
                    $query = $query->orderBy($fieldColumn, $value);
307
                }
308
            }
309
        }
310
311
        return $query;
312
    }
313
}
314