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

FullTreeDataAction::run()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 22
rs 9.2
cc 2
eloc 18
nc 2
nop 0
1
<?php
2
3
namespace devgroup\JsTreeWidget\actions\nestedset;
4
5
use yii\base\Action;
6
use yii\base\InvalidConfigException;
7
use yii\db\ActiveRecord;
8
use Yii;
9
use yii\db\Query;
10
use yii\web\Response;
11
12
class FullTreeDataAction extends Action
13
{
14
    /** @var string */
15
    public $leftAttribute = 'lft';
16
    /** @var string */
17
    public $rightAttribute = 'rgt';
18
    /** @var string set name for multi root tree */
19
    public $rootAttribute = false;
20
    /** @var  ActiveRecord */
21
    public $className;
22
    /** @var string */
23
    public $modelLabelAttribute = 'name';
24
25
    private $tableName;
26
27
    public function init()
28
    {
29
        if (true === empty($this->className) || false === is_subclass_of($this->className, ActiveRecord::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \yii\db\ActiveRecord::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
30
            throw new InvalidConfigException('"className" param must be set and must be child of ActiveRecord');
31
        }
32
        /** @var ActiveRecord $class */
33
        $class = $this->className;
34
        $this->tableName = $class::tableName();
35
        $scheme = Yii::$app->getDb()->getTableSchema($this->tableName);
36
        $columns = $scheme->columns;
37
        if (false !== $this->rootAttribute && false === isset($columns[$this->rootAttribute])) {
38
            throw new InvalidConfigException("Column '{$this->rootAttribute}' not found in the '{$this->tableName}' table");
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 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...
39
        }
40
        if (false === isset(
41
                $columns[$this->leftAttribute],
42
                $columns[$this->rightAttribute],
43
                $columns[$this->modelLabelAttribute]
44
            )
45
        ) {
46
            throw new InvalidConfigException(
47
                "Some of the '{$this->leftAttribute}', '{$this->rightAttribute}', '{$this->modelLabelAttribute}', "
48
                . "not found in the '{$this->tableName}' columns list"
49
            );
50
        }
51
    }
52
53
    public function run()
54
    {
55
        $selectArray = [
56
            'id',
57
            $this->leftAttribute,
58
            $this->rightAttribute,
59
            $this->modelLabelAttribute,
60
        ];
61
        $orderBy = [];
62
        if (false !== $this->rootAttribute) {
63
            $selectArray[] = $this->rootAttribute;
64
            $orderBy[$this->rootAttribute] = SORT_ASC;
65
        }
66
        $orderBy[$this->leftAttribute] = SORT_ASC;
67
        Yii::$app->response->format = Response::FORMAT_JSON;
68
        $data = (new Query())
69
            ->from($this->tableName)
70
            ->select($selectArray)
71
            ->orderBy($orderBy)
72
            ->all();
73
        return $this->prepareNestedData($data);
74
    }
75
76
    /**
77
     * Converts single or multi root Nested Set database data into multidimensional array for using in the
78
     * jsTree widget
79
     *
80
     * @param array $data
81
     * @param int $lft
82
     * @param null $rgt
83
     * @param int $root
84
     * @return array
85
     */
86
    public function prepareNestedData($data, $lft = 0, $rgt = null, $root = 0)
87
    {
88
        $res = [];
89
        foreach ($data as $row) {
90
            $currentRoot = isset($row[$this->rootAttribute]) ? $row[$this->rootAttribute] : 0;
91
            if (is_null($rgt) || $row[$this->rightAttribute] < $rgt) {
92
                if ($lft + 1 == $row[$this->leftAttribute] && $root == $currentRoot) {
93
                    if ($row[$this->leftAttribute] + 1 !== $row[$this->rightAttribute]) {
94
                        $res[] = [
95
                            'id' => $row['id'],
96
                            'text' => $row[$this->modelLabelAttribute],
97
                            'children' => self::prepareNestedData(
98
                                $data,
99
                                $row[$this->leftAttribute],
100
                                $row[$this->rightAttribute],
101
                                $currentRoot
102
                            ),
103
                        ];
104
                    } else {
105
                        $res[] = [
106
                            'id' => $row['id'],
107
                            'text' => $row[$this->modelLabelAttribute],
108
                            'children' => []
109
                        ];
110
                    }
111
                    $lft = $row[$this->rightAttribute];
112
                } else if ($row[$this->leftAttribute] == 1 && $root !== $currentRoot) {
113
                    $res[] = [
114
                        'id' => $row['id'],
115
                        'text' => $row[$this->modelLabelAttribute],
116
                        'children' => self::prepareNestedData(
117
                            $data,
118
                            $row[$this->leftAttribute],
119
                            $row[$this->rightAttribute],
120
                            $currentRoot
121
                        ),
122
                    ];
123
                }
124
            }
125
        }
126
        return $res;
127
    }
128
}