Test Setup Failed
Push — dev ( 61c8f1...460265 )
by
unknown
02:47
created

NodeMoveAction::getChildIds()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
3
namespace devgroup\JsTreeWidget\actions\nestedset;
4
5
use yii\base\Action;
6
use Yii;
7
use yii\db\ActiveRecord;
8
use yii\db\Expression;
9
use yii\web\Response;
10
11
class NodeMoveAction extends Action
12
{
13
    /** @var  ActiveRecord */
14
    public $className;
15
16
    public $rootAttribute = 'tree';
17
    public $leftAttribute = 'lft';
18
    public $rightAttribute = 'rgt';
19
    public $depthAttribute = 'depth';
20
21
    private $node;
22
    private $parent;
23
24
25
    public function init()
26
    {
27
        //check for move node as root
28
        //root reorder
29
        //maybe move root to another root
30
    }
31
32
    public function run()
33
    {
34
        Yii::$app->response->format = Response::FORMAT_JSON;
35
        $newParentId = Yii::$app->request->post('parent');
36
        $oldParentId = Yii::$app->request->post('old_parent');
37
        $position = Yii::$app->request->post('position');
38
        $oldPosition = Yii::$app->request->post('old_position');
39
        $nodeId = Yii::$app->request->post('node_id');
40
        $siblings = Yii::$app->request->post('siblings', []);
41
        $class = $this->className;
42
        if ((null === $node = $class::findOne($nodeId)) || (null === $parent = $class::findOne($newParentId))) {
43
            return ['error' => 'Invalid data received'];
44
        }
45
        $this->node = $node;
46
        $this->parent = $parent;
47
        if ($newParentId == $oldParentId) {
48
            return $this->reorder($oldPosition, $position, $siblings);
49
        } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
50
            
51
        }
52
    }
53
54
    public function reorder($oldPosition = null, $position = null, $siblings = [])
55
    {
56
        if (null === $oldPosition || null === $position || true === empty($siblings)) {
57
            return ['info' => 'nothing to change'];
58
        }
59
        $nodeId = $siblings[$position];
60
        $class = $this->className;
61
        $lr = $workWith = [];
0 ignored issues
show
Unused Code introduced by
$workWith is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Unused Code introduced by
$lr is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
62
        $nodeOperator = $siblingsOperator = '';
0 ignored issues
show
Unused Code introduced by
$siblingsOperator is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Unused Code introduced by
$nodeOperator is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
63
        if ($oldPosition > $position) {
64
            //change next
65
            $nodeOperator = '-';
66
            $siblingsOperator = '+';
67
            $workWith = array_slice($siblings, $position, $oldPosition - $position + 1);
68
        } else if ($oldPosition < $position) {
69
            //change previous
70
            $nodeOperator = '+';
71
            $siblingsOperator = '-';
72
            $workWith = array_slice($siblings, $oldPosition, $position - $oldPosition + 1);
73
        } else {
74
            return ['info' => 'nothing to change'];
75
        }
76
        if (true === empty($workWith)) {
77
            return ['info' => 'nothing to change'];
78
        }
79
        $lr = $workWithLr = $this->getLr($workWith);
80
        if (true === empty($lr)) {
81
            return ['info' => 'nothing to change'];
82
        }
83
        unset($workWithLr[$nodeId]);
84
        $lft = array_column($workWithLr, $this->leftAttribute);
85
        $lft = min($lft);
86
        $rgt = array_column($workWithLr, $this->rightAttribute);
87
        $rgt = max($rgt);
88
        $nodeCondition = [
89
            'and',
90
            ['>=', $this->leftAttribute, $lft],
91
            ['<=', $this->rightAttribute, $rgt]
92
        ];
93
        $this->applyRootCondition($nodeCondition);
94
        $nodeDelta = $this->getCount($nodeCondition);
95
        $nodeDelta *= 2;
96
        $siblingsCondition = [
97
            'and',
98
            ['>=', $this->leftAttribute, $lr[$nodeId][$this->leftAttribute]],
99
            ['<=', $this->rightAttribute, $lr[$nodeId][$this->rightAttribute]]
100
        ];
101
        $this->applyRootCondition($siblingsCondition);
102
        $nodeChildren = $this->getChildIds($siblingsCondition);
103
        $siblingsDelta = count($nodeChildren) * 2;
104
        $db = Yii::$app->getDb();
105
        $transaction = $db->beginTransaction();
106
        try {
107
            //updating necessary node siblings
108
            $db->createCommand()->update(
109
                $class::tableName(),
110
                [
111
                    $this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $siblingsOperator, $siblingsDelta)),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 134 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
112
                    $this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $siblingsOperator, $siblingsDelta)),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
113
                ],
114
                $nodeCondition
115
            )->execute();
116
            //updating node
117
            $db->createCommand()->update(
118
                $class::tableName(),
119
                [
120
                    $this->leftAttribute => new Expression($this->leftAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 126 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
121
                    $this->rightAttribute => new Expression($this->rightAttribute . sprintf('%s%d', $nodeOperator, $nodeDelta)),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 128 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
122
                ],
123
                ['id' => $nodeChildren]
124
            )->execute();
125
            $transaction->commit();
126
        } catch (\Exception $e) {
127
            $transaction->rollBack();
128
            return ['error', $e->getMessage()];
129
        }
130
        return ['siblingsDelta' => $siblingsDelta, 'nodeDelta' => $nodeDelta, 'workWith' => $workWith];
131
    }
132
133
    private function move(){
134
        
135
    }
136
137
    /**
138
     * Returns field set of rows to be modified while reordering
139
     *
140
     * @param array $ids
141
     * @return array|\yii\db\ActiveRecord[]
142
     */
143
    private function getLr($ids)
144
    {
145
        $class = $this->className;
146
        $lr = $class::find()
147
            ->select(['id', $this->leftAttribute, $this->rightAttribute])
148
            ->where(['id' => $ids])
149
            ->indexBy('id')
150
            ->asArray(true)
151
            ->all();
152
        return $lr;
153
    }
154
155
    /**
156
     * Returns count of records to be modified while reordering
157
     * @param array $condition
158
     * @return int|string
159
     */
160
    public function getCount($condition)
161
    {
162
        $class = $this->className;
163
        $count = $class::find()
164
            ->select(['id', $this->leftAttribute, $this->rightAttribute, $this->rootAttribute])
165
            ->where($condition)
166
            ->count();
167
        return $count;
168
    }
169
170
    private function getChildIds($condition)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
171
    {
172
        $class = $this->className;
173
        $count = $class::find()
174
            ->select('id')
175
            ->where($condition)
176
            ->column();
177
        return $count;
178
    }
179
180
    private function applyRootCondition(&$condition)
181
    {
182
        if (false !== $this->rootAttribute) {
183
            $condition[] = [$this->rootAttribute => $this->node->{$this->rootAttribute}];
184
        }
185
    }
186
187
    /**
188
     * @return null|ActiveRecord
0 ignored issues
show
Documentation introduced by
Should the return type not be array|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
189
     */
190
    private function getFirstChild()
191
    {
192
        $class = $this->className;
193
        return $class::findOne([$this->leftAttribute => $this->parent->{$this->leftAttribute} + 1]);
194
    }
195
196
197
    protected function isChildOf($parent)
198
    {
199
        if ($this->node->{$this->rootAttribute} !== $parent->{$this->rootAttribute}) {
200
            return false;
201
        }
202
        if ($this->node->{$this->leftAttribute} > $parent->{$this->leftAttribute}
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $this->node->{$th...$this->rightAttribute};.
Loading history...
203
            && $this->node->{$this->rightAttribute} < $parent->{$this->rightAttribute}
204
        ) {
205
            return true;
206
        }
207
        return false;
208
    }
209
}