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 — main ( 3714d7...b58f97 )
by Pedro
44:24 queued 29:28
created

Reorder::updateTreeOrder()   C

Complexity

Conditions 13
Paths 1

Size

Total Lines 75
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 13
Bugs 6 Features 1
Metric Value
cc 13
eloc 39
c 13
b 6
f 1
nc 1
nop 1
dl 0
loc 75
rs 6.6166

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\Library\CrudPanel\Traits;
4
5
use Illuminate\Support\Facades\DB;
6
7
/**
8
 * Properties and methods for the Reorder operation.
9
 */
10
trait Reorder
11
{
12
    /**
13
     * Change the order and parents of the given elements, according to the NestedSortable AJAX call.
14
     *
15
     * @param  array  $request  The entire request from the NestedSortable AJAX Call.
16
     * @return int The number of items whose position in the tree has been changed.
17
     */
18
    public function updateTreeOrder($request)
19
    {
20
        $primaryKey = $this->model->getKeyName();
21
22
        $columns = $this->getOperationSetting('reorderColumnNames');
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

22
        /** @scrutinizer ignore-call */ 
23
        $columns = $this->getOperationSetting('reorderColumnNames');
Loading history...
23
24
        // we use the upsert method that should update the values of the matching ids.
25
        // it has the drawback of creating new entries when the id is not found
26
        // for that reason we get a list of all the ids and filter the ones
27
        // sent in the request that are not in the database
28
        $itemKeys = $this->model->query()->select($primaryKey)->get()->pluck($primaryKey);
29
30
        // filter the items that are not in the database and map the request
31
        $reorderItems = collect($request)->filter(function ($item) use ($itemKeys) {
0 ignored issues
show
Bug introduced by
$request of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

31
        $reorderItems = collect(/** @scrutinizer ignore-type */ $request)->filter(function ($item) use ($itemKeys) {
Loading history...
32
            return $item['item_id'] !== '' && $item['item_id'] !== null && $itemKeys->contains($item['item_id']);
33
        })->map(function ($item) use ($primaryKey, $columns) {
34
            $item[$primaryKey] = $item['item_id'];
35
            $item[$columns['parent_id']] = empty($item['parent_id']) ? null : $item['parent_id'];
36
            $item[$columns['depth']] = empty($item['depth']) ? null : (int) $item['depth'];
37
            $item[$columns['lft']] = empty($item['left']) ? null : (int) $item['left'];
38
            $item[$columns['rgt']] = empty($item['right']) ? null : (int) $item['right'];
39
40
            // unset mapped items properties.
41
            if ($columns['parent_id'] !== 'parent_id') {
42
                unset($item['parent_id']);
43
            }
44
            if ($columns['depth'] !== 'depth') {
45
                unset($item['depth']);
46
            }
47
            if ($columns['lft'] !== 'left') {
48
                unset($item['left']);
49
            }
50
            if ($columns['rgt'] !== 'right') {
51
                unset($item['right']);
52
            }
53
54
            // unset the item_id property
55
            unset($item['item_id']);
56
57
            return $item;
58
        })->toArray();
59
60
        $sentIds = array_column($reorderItems, $primaryKey);
61
62
        $itemKeys = $itemKeys->filter(function ($id) use ($sentIds) {
63
            return in_array($id, $sentIds);
64
        });
65
66
        // wrap the queries in a transaction to avoid partial updates
67
        DB::connection($this->model->getConnectionName())->transaction(function () use ($reorderItems, $primaryKey, $itemKeys, $columns) {
68
            // create a string of ?,?,?,? to use as bind placeholders for item keys
69
            $reorderItemsBindString = implode(',', array_fill(0, count($reorderItems), '?'));
70
71
            // each of this properties will be updated using a single query with a CASE statement
72
            // this ensures that only 4 queries are run, no matter how many items are reordered
73
            foreach (array_values($columns) as $column) {
74
                $query = '';
75
                $bindings = [];
76
                $query .= "UPDATE {$this->model->getTable()} SET {$column} = CASE ";
77
                foreach ($reorderItems as $item) {
78
                    $query .= "WHEN {$primaryKey} = ? THEN ? ";
79
                    $bindings[] = $item[$primaryKey];
80
                    $bindings[] = $item[$column];
81
                }
82
                // add the bind placeholders for the item keys at the end the array of bindings
83
                array_push($bindings, ...$itemKeys->toArray());
84
85
                // add the where clause to the query to help match the items
86
                $query .= "ELSE {$column} END WHERE {$primaryKey} IN ({$reorderItemsBindString})";
87
88
                DB::connection($this->model->getConnectionName())->statement($query, $bindings);
89
            }
90
        });
91
92
        return count($reorderItems);
93
    }
94
95
    /**
96
     * Enable the Reorder functionality in the CRUD Panel for users that have the been given access to 'reorder' using:
97
     * $this->crud->allowAccess('reorder');.
98
     *
99
     * @param  string  $label  Column name that will be shown on the labels.
100
     * @param  int  $max_level  Maximum hierarchy level to which the elements can be nested (1 = no nesting, just reordering).
101
     */
102
    public function enableReorder($label = 'name', $max_level = 1)
103
    {
104
        $this->setOperationSetting('enabled', 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

104
        $this->/** @scrutinizer ignore-call */ 
105
               setOperationSetting('enabled', true);
Loading history...
105
        $this->setOperationSetting('label', $label);
106
        $this->setOperationSetting('max_level', $max_level);
107
    }
108
109
    /**
110
     * Disable the Reorder functionality in the CRUD Panel for all users.
111
     */
112
    public function disableReorder()
113
    {
114
        $this->setOperationSetting('enabled', false);
115
    }
116
117
    /**
118
     * Check if the Reorder functionality is enabled or not.
119
     *
120
     * @return bool
121
     */
122
    public function isReorderEnabled()
123
    {
124
        return $this->getOperationSetting('enabled');
125
    }
126
}
127