ListController::processForContent()   D
last analyzed

Complexity

Conditions 20
Paths 34

Size

Total Lines 101
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 50
c 1
b 0
f 0
dl 0
loc 101
rs 4.1666
cc 20
nc 34
nop 3

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 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
        // Add search conditions from request
46
        $selectedFilter = $this->addSearchConditions($selectedFilter);
47
48
        // Get datatable columns
49
        $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

49
        /** @scrutinizer ignore-call */ 
50
        $datatableColumns = Uccello::getDatatableColumns($module, $selectedFilterId);
Loading history...
50
51
        // Get filters
52
        $filters = Filter::where('module_id', $module->id)  // Module
53
            ->where('type', 'list')                         // Type (list)
54
            ->where(function ($query) use($domain) {        // Domain
55
                $query->whereNull('domain_id')
56
                    ->orWhere('domain_id', $domain->getKey());
57
            })
58
            ->where(function ($query) {                     // User
59
                $query->where('is_public', true)
60
                    ->orWhere(function ($query) {
61
                        $query->where('is_public', false)
62
                            ->where('user_id', '=', auth()->id());
63
                    })
64
                    ->orWhere(function ($query) {
65
                        $query->where('is_public', false)
66
                            ->whereNull('user_id');
67
                    });
68
            })
69
            ->orderBy('order')
70
            ->get();
71
72
        // Order
73
        $filterOrder = (array) $selectedFilter->order;
0 ignored issues
show
Bug introduced by
The property order 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...
74
75
        // See descendants
76
        $seeDescendants = request()->session()->get('descendants');
77
78
        // Use soft deleting
79
        $usesSoftDeleting = $this->isModuleUsingSoftDeleting();
80
81
        // Check if we want to display trash data
82
        $displayTrash = $this->isDisplayingTrash();
83
84
        return $this->autoView(compact(
85
            'datatableColumns',
86
            'filters',
87
            'selectedFilter',
88
            'filterOrder',
89
            'seeDescendants',
90
            'usesSoftDeleting',
91
            'displayTrash'
92
        ));
93
    }
94
95
    /**
96
     * Display a listing of the resources.
97
     * The result is formated differently if it is a classic query or one requested by datatable.
98
     * Filter on domain if domain_id column exists.
99
     * @param  \Uccello\Core\Models\Domain|null $domain
100
     * @param  \Uccello\Core\Models\Module $module
101
     * @param  \Illuminate\Http\Request $request
102
     * @return \Illuminate\Http\Response
103
     */
104
    public function processForContent(?Domain $domain, Module $module, Request $request)
105
    {
106
        $length = (int)$request->get('length') ?? env('UCCELLO_ITEMS_PER_PAGE', 15);
107
108
        $recordId = $request->get('id');
109
        $relatedListId = $request->get('relatedlist');
110
        $action = $request->get('action');
111
        $relatedModule = null;
112
113
        if ($request->has('descendants') && $request->get('descendants') !== $request->session()->get('descendants')) {
114
            $request->session()->put('descendants', $request->get('descendants'));
115
        }
116
117
        // Pre-process
118
        $this->preProcess($domain, $module, $request, false);
119
120
        // Get model model class
121
        $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...
122
123
        // Check if the class exists
124
        if (!class_exists($modelClass)) {
125
            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...
126
        }
127
128
        // Build query
129
        $query = $this->buildContentQuery();
130
131
        // Limit the number maximum of items per page
132
        $maxItemsPerPage = env('UCCELLO_MAX_ITEMS_PER_PAGE', 100);
133
        if ($length > $maxItemsPerPage) {
134
            $length = $maxItemsPerPage;
135
        }
136
137
        // If the query is for a related list, add conditions
138
        if ($relatedListId && $action !== 'select') {
139
            // Get related list
140
            $relatedList = Relatedlist::find($relatedListId);
141
142
            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...
143
                // Related list method
144
                $method = $relatedList->method;
145
146
                // Update query
147
                $model = new $modelClass;
148
                $records = $model->$method($relatedList, $recordId, $query)->paginate($length);
149
            }
150
        } elseif ($relatedListId && $action === 'select') {
151
            // Get related list
152
            $relatedList = Relatedlist::find($relatedListId);
153
154
            if ($relatedList && $relatedList->method) {
155
                // Related list method
156
                $method = $relatedList->method;
157
                $recordIdsMethod = $method . 'RecordIds';
158
159
                // Get related records ids
160
                $model = new $modelClass;
161
                $filteredRecordIds = $model->$recordIdsMethod($relatedList, $recordId);
162
163
                // Add the record id itself to be filtered
164
                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...
165
                    $filteredRecordIds[] = (int)$recordId;
166
                }
167
168
                if ($relatedList->module_id) {
169
                    $relatedModule = ucmodule($relatedList->module_id);
170
                }
171
172
                // Make the quer
173
                $records = $query->whereNotIn($model->getKeyName(), $filteredRecordIds)->paginate($length);
0 ignored issues
show
Bug introduced by
It seems like $length can also be of type PhpOption\S and PhpOption\T; however, parameter $perPage of Illuminate\Database\Eloquent\Builder::paginate() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

173
                $records = $query->whereNotIn($model->getKeyName(), $filteredRecordIds)->paginate(/** @scrutinizer ignore-type */ $length);
Loading history...
Bug introduced by
It seems like $length can also be of type PhpOption\S and PhpOption\T; however, parameter $perPage of Illuminate\Database\Query\Builder::paginate() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

173
                $records = $query->whereNotIn($model->getKeyName(), $filteredRecordIds)->paginate(/** @scrutinizer ignore-type */ $length);
Loading history...
174
            }
175
        } else {
176
            // Paginate results
177
            $records = $query->paginate($length);
178
        }
179
180
        $records->getCollection()->transform(function ($record) use ($domain, $module, $relatedModule) {
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...
181
            foreach ($module->fields as $field) {
182
                // If a special template exists, use it. Else use the generic template
183
                $uitype = uitype($field->uitype_id);
184
                $uitypeViewName = sprintf('uitypes.list.%s', $uitype->name);
185
                $uitypeFallbackView = 'uccello::modules.default.uitypes.list.text';
186
                $uitypeViewToInclude = uccello()->view($module->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...
187
                $record->{$field->name.'_html'} = view()->make($uitypeViewToInclude, compact('domain', 'module', 'record', 'field'))->render();
188
            }
189
190
            // Add primary key name and value
191
            $record->__primaryKey = $record->getKey();
192
            $record->__primaryKeyName = $record->getKeyName();
193
194
            if ($relatedModule) {
195
                $moduleName = str_replace('-', '_', $relatedModule->name);
0 ignored issues
show
Bug introduced by
The property name 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...
196
                if ($record->$moduleName) {
197
                    $record->__relatedEntityName = $record->$moduleName->recordLabel ?? null;
198
                }
199
            }
200
201
            return $record;
202
        });
203
204
        return $records;
205
    }
206
207
    /**
208
     * Autocomplete a listing of the resources.
209
     * The result is formated differently if it is a classic query or one requested by datatable.
210
     * Filter on domain if domain_id column exists.
211
     * @param  \Uccello\Core\Models\Domain|null $domain
212
     * @param  \Uccello\Core\Models\Module $module
213
     * @param  \Illuminate\Http\Request $request
214
     * @return \Illuminate\Http\Response
215
     */
216
    public function processForAutocomplete(?Domain $domain, Module $module, Request $request)
217
    {
218
        // If we don't use multi domains, find the first one
219
        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...
220
            $domain = Domain::first();
0 ignored issues
show
Unused Code introduced by
The assignment to $domain is dead and can be removed.
Loading history...
221
        }
222
223
        // Query
224
        $q = $request->get('q');
225
        // Model class
226
        $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...
227
228
        $results = collect();
229
        if (method_exists($modelClass, 'getSearchResult') && property_exists($modelClass, 'searchableColumns')) {
230
            $searchResults = new Search();
231
            $searchResults->registerModel($modelClass, (array) (new $modelClass)->searchableColumns);
232
            $results = $searchResults->search($q)->take(config('uccello.max_results.autocomplete', 10));
233
        }
234
235
        return $results;
236
    }
237
238
    /**
239
     * Save list filter into database
240
     *
241
     * @param \Uccello\Core\Models\Domain|null $domain
242
     * @param \Uccello\Core\Models\Module $module
243
     * @param \Illuminate\Http\Request $request
244
     * @return \Illuminate\Http\Response
245
     */
246
    public function saveFilter(?Domain $domain, Module $module, Request $request)
247
    {
248
        $saveOrder = $request->input('save_order');
249
        $savePageLength = $request->input('save_page_length');
250
251
        // Optional data
252
        $data = [];
253
        if ($savePageLength) {
254
            $data["length"] = $request->input('page_length');
255
        }
256
257
        $filter = Filter::firstOrNew([
258
            'domain_id' => $domain->id,
259
            'module_id' => $module->id,
260
            'user_id' => auth()->id(),
261
            'name' => $request->input('name'),
262
            'type' => $request->input('type')
263
        ]);
264
        $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...
265
        $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...
266
        $filter->order = $saveOrder ? $request->input('order') : null;
0 ignored issues
show
Bug introduced by
The property order 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...
267
        $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...
268
        $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...
269
        $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...
270
        $filter->save();
271
272
        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...
273
    }
274
275
    /**
276
     * Retrieve a filter by its id and delete it
277
     *
278
     * @param \Uccello\Core\Models\Domain|null $domain
279
     * @param \Uccello\Core\Models\Module $module
280
     * @param \Illuminate\Http\Request $request
281
     * @return \Illuminate\Http\Response
282
     */
283
    public function deleteFilter(?Domain $domain, Module $module, Request $request)
284
    {
285
        // Retrieve filter by id
286
        $filterId = $request->input('id');
287
        $filter = Filter::find($filterId);
288
289
        if ($filter) {
290
            if ($filter->readOnly) {
291
                // Response
292
                $success = false;
293
                $message = uctrans('error.filter.read_only', $module);
294
            } else {
295
                // Delete
296
                $filter->delete();
297
298
                // Response
299
                $success = true;
300
                $message = uctrans('success.filter.deleted', $module);
301
            }
302
        } else {
303
            // Response
304
            $success = false;
305
            $message = uctrans('error.filter.not_found', $module);
306
        }
307
308
        return [
309
            'success' => $success,
310
            'message' => $message
311
        ];
312
    }
313
314
    /**
315
     * Check if the model class link to the module is using soft deleting.
316
     *
317
     * @return boolean
318
     */
319
    protected function isModuleUsingSoftDeleting()
320
    {
321
        $modelClass = $this->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...
322
        $model = new $modelClass;
323
324
        return method_exists($model, 'getDeletedAtColumn');
325
    }
326
327
    /**
328
     * Check if we want to display trash data
329
     *
330
     * @return boolean
331
     */
332
    protected function isDisplayingTrash()
333
    {
334
        return $this->isModuleUsingSoftDeleting() && $this->request->get('filter') === 'trash';
335
    }
336
337
    /**
338
     * Add to a filter all search conditions from defined in request
339
     *
340
     * @param \Uccello\Core\Models\Filter $filter
341
     * @return \Uccello\Core\Models\Filter
342
     */
343
    protected function addSearchConditions($filter)
344
    {
345
        if ($this->request->has('search')) {
346
            $conditions = [];
347
            foreach ((array) $this->request->search as $fieldName => $value) {
348
                $conditions[$fieldName] = $value;
349
            }
350
351
            if ($conditions) {
352
                $filter->conditions = [
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...
353
                    'search' => $conditions
354
                ];
355
            }
356
        }
357
358
        return $filter;
359
    }
360
361
    /**
362
     * Build query for retrieving content
363
     *
364
     * @return \Illuminate\Database\Eloquent\Builder;
365
     */
366
    protected function buildContentQuery()
367
    {
368
        $filter = [
369
            'order' => $this->request->get('order'),
370
            'columns' => $this->request->get('columns'),
371
        ];
372
373
        // Get model model class
374
        $modelClass = $this->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...
375
376
        // Check if the class exists
377
        if (!class_exists($modelClass) || !method_exists($modelClass, 'scopeInDomain')) {
378
            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...
379
        }
380
381
        //Filter with additionnal rules (uitype entity for exemple)
382
        if ($this->request->has('additional_rules') && $this->request->get('additional_rules')) {
383
            $rules = json_decode($this->request->get('additional_rules'));
384
385
            if ($rules) {
386
                foreach ($rules as $column => $rule) {
387
                    $filter['columns'][$column]['search'] = $rule;
388
                }
389
            }
390
        }
391
392
        // Filter on domain if column exists
393
        $query = $modelClass::inDomain($this->domain, $this->request->session()->get('descendants'))
394
                            ->filterBy($filter);
395
396
        // Display trash if filter is selected
397
        if ($this->isDisplayingTrash()) {
398
            $query = $query->onlyTrashed();
399
        }
400
401
        return $query;
402
    }
403
}
404