Code

< 40 %
40-60 %
> 60 %
1
<?php
2
3
namespace paulzi\autotree;
4
5
use yii\base\InvalidCallException;
6
7
trait AutoTreeTrait
8
{
9
    /**
10
     * @var \yii\base\Behavior[]
11
     */
12
    private $_autoTreeMap;
13
14
    private $_autoTreeReturnBehavior = false;
15
16
17
    /**
18
     * @return array
19
     */
20 61
    private static function autoTreeAliases()
21
    {
22
        return [
23 61
            'paulzi\adjacencyList\AdjacencyListBehavior'       => 'al',
24
            'paulzi\adjacencylist\AdjacencyListBehavior'       => 'al',
25
            'paulzi\nestedSets\NestedSetsBehavior'             => 'ns',
26
            'paulzi\nestedsets\NestedSetsBehavior'             => 'ns',
27
            'paulzi\nestedIntervals\NestedIntervalsBehavior'   => 'ni',
28
            'paulzi\nestedintervals\NestedIntervalsBehavior'   => 'ni',
29
            'paulzi\materializedPath\MaterializedPathBehavior' => 'mp',
30
            'paulzi\materializedpath\MaterializedPathBehavior' => 'mp',
31
        ];
32
    }
33
34
    /**
35
     *
36
     */
37 61
    private function autoTreeInit()
38
    {
39
        /** @var \yii\base\Component|self $this */
40 61
        $aliases = $this->autoTreeAliases();
41 61
        foreach ($this->getBehaviors() as $behavior) {
42 61
            $className = $behavior::className();
43 61
            if (isset($aliases[$className]) && !isset($this->_autoTreeMap[$aliases[$className]])) {
44 61
                $this->_autoTreeMap[$aliases[$className]] = $behavior;
45
            }
46
        }
47 61
    }
48
49
    /**
50
     * @param string $method
51
     * @param array $list
52
     * @param array $arguments
53
     * @param bool $firstOnly
54
     * @return mixed
55
     */
56 61
    private function autoTreeCall($method, $list, $arguments = [], $firstOnly = true)
57
    {
58 61
        if ($this->_autoTreeMap === null) {
59 61
            $this->autoTreeInit();
60
        }
61
62 61
        $result  = null;
63 61
        $founded = false;
64 61
        foreach ($list as $alias) {
65 61
            if (isset($this->_autoTreeMap[$alias])) {
66 61
                $behavior = $this->_autoTreeMap[$alias];
67 61
                if (method_exists($behavior, $method)) {
68 61
                    if ($this->_autoTreeReturnBehavior) {
69 6
                        return $behavior;
70
                    }
71 61
                    $founded = true;
72 61
                    $result = call_user_func_array([$behavior, $method], $arguments);
73 61
                    if ($firstOnly) {
74 61
                        return $result;
75
                    }
76
                }
77
            }
78
        }
79
80 27
        if (!$founded) {
81
            throw new InvalidCallException("Method '{$method}' not founded");
82
        }
83
84 27
        return $result;
85
    }
86
87
    /**
88
     * @inheritdoc
89
     */
90 51
    public function __get($name)
91
    {
92
        /** @var \yii\db\BaseActiveRecord|self $this */
93
        // replace getParents() by getParentsOrdered() if behavior not support ordered query
94 51 View Code Duplication
        if ($name === 'parents') {
95 3
            $this->_autoTreeReturnBehavior = true;
96 3
            $behavior = $this->getParents();
97 3
            $this->_autoTreeReturnBehavior = false;
98 3
            if (method_exists($behavior, 'getParentsOrdered')) {
99
                $this->populateRelation($name, $behavior->getParentsOrdered());
100
            }
101
        }
102 51 View Code Duplication
        if ($name === 'descendants') {
103 3
            $this->_autoTreeReturnBehavior = true;
104 3
            $behavior = $this->getDescendants();
105 3
            $this->_autoTreeReturnBehavior = false;
106 3
            if (method_exists($behavior, 'getDescendantsOrdered')) {
107
                $this->populateRelation($name, $behavior->getDescendantsOrdered());
108
            }
109
        }
110 51
        return parent::__get($name);
111
    }
112
113
    /**
114
     * @param int|null $depth
115
     * @return \yii\db\ActiveQuery
116
     */
117 3
    public function getParents($depth = null)
118
    {
119 3
        return $this->autoTreeCall('getParents', ['mp', 'ns', 'ni', 'al'], [$depth]);
120
    }
121
122
    /**
123
     * @return \yii\db\ActiveQuery
124
     */
125 3
    public function getParent()
126
    {
127 3
        return $this->autoTreeCall('getParent', ['al', 'mp', 'ns', 'ni']);
128
    }
129
130
    /**
131
     * @return \yii\db\ActiveQuery
132
     */
133 3
    public function getRoot()
134
    {
135 3
        return $this->autoTreeCall('getRoot', ['mp', 'ns', 'ni', 'al']);
136
    }
137
138
    /**
139
     * @param int|null $depth
140
     * @param bool $andSelf
141
     * @return \yii\db\ActiveQuery
142
     */
143 5
    public function getDescendants($depth = null, $andSelf = false)
144
    {
145 5
        return $this->autoTreeCall('getDescendants', ['ns', 'ni', 'mp', 'al'], [$depth, $andSelf]);
146
    }
147
148
    /**
149
     * @return \yii\db\ActiveQuery
150
     */
151 8
    public function getChildren()
152
    {
153 8
        return $this->autoTreeCall('getChildren', ['al', 'ns', 'ni', 'mp']);
154
    }
155
156
    /**
157
     * @param int|null $depth
158
     * @return \yii\db\ActiveQuery
159
     */
160 3
    public function getLeaves($depth = null)
161
    {
162 3
        return $this->autoTreeCall('getLeaves', ['ns', 'al', 'mp', 'ni'], [$depth]);
163
    }
164
165
    /**
166
     * @return \yii\db\ActiveQuery
167
     * @throws \yii\base\NotSupportedException
168
     */
169 3
    public function getPrev()
170
    {
171 3
        return $this->autoTreeCall('getPrev', ['ns', 'mp', 'ni', 'al']);
172
    }
173
174
    /**
175
     * @return \yii\db\ActiveQuery
176
     * @throws \yii\base\NotSupportedException
177
     */
178 3
    public function getNext()
179
    {
180 3
        return $this->autoTreeCall('getNext', ['ns', 'mp', 'ni', 'al']);
181
    }
182
183
    /**
184
     * Populate children relations for self and all descendants
185
     * @param int $depth = null
186
     * @param string|array $with = null
187
     * @return self
188
     */
189
    public function populateTree($depth = null, $with = null)
190
    {
191
        return $this->autoTreeCall('populateTree', ['ns', 'ni', 'mp', 'al'], [$depth, $with]);
192
    }
193
194
    /**
195
     * @return bool
196
     */
197 12
    public function isRoot()
198
    {
199 12
        return $this->autoTreeCall('isRoot', ['al', 'ns', 'ni', 'mp']);
200
    }
201
202
    /**
203
     * @param \yii\db\BaseActiveRecord $node
204
     * @return bool
205
     */
206 17
    public function isChildOf($node)
207
    {
208 17
        return $this->autoTreeCall('isChildOf', ['ns', 'ni', 'mp', 'al'], [$node]);
209
    }
210
211
    /**
212
     * @return bool
213
     */
214 3
    public function isLeaf()
215
    {
216 3
        return $this->autoTreeCall('isLeaf', ['ns', 'al', 'ni', 'mp']);
217
    }
218
219
    /**
220
     * @return $this
221
     */
222 6
    public function makeRoot()
223
    {
224 6
        return $this->autoTreeCall('makeRoot', ['al', 'ns', 'ni', 'mp'], [], false);
225
    }
226
227
    /**
228
     * @param \yii\db\BaseActiveRecord $node
229
     * @return $this
230
     */
231 6
    public function prependTo($node)
232
    {
233 6
        return $this->autoTreeCall('prependTo', ['al', 'ns', 'ni', 'mp'], [$node], false);
234
    }
235
236
    /**
237
     * @param \yii\db\BaseActiveRecord $node
238
     * @return $this
239
     */
240 3
    public function appendTo($node)
241
    {
242 3
        return $this->autoTreeCall('appendTo', ['al', 'ns', 'ni', 'mp'], [$node], false);
243
    }
244
245
    /**
246
     * @param \yii\db\BaseActiveRecord $node
247
     * @return $this
248
     */
249 3
    public function insertBefore($node)
250
    {
251 3
        return $this->autoTreeCall('insertBefore', ['al', 'ns', 'ni', 'mp'], [$node], false);
252
    }
253
254
    /**
255
     * @param \yii\db\BaseActiveRecord $node
256
     * @return $this
257
     */
258 6
    public function insertAfter($node)
259
    {
260 6
        return $this->autoTreeCall('insertAfter', ['al', 'ns', 'ni', 'mp'], [$node], false);
261
    }
262
263
    /**
264
     * @return bool|int
265
     * @throws \Exception
266
     * @throws \yii\db\Exception
267
     */
268 3
    public function deleteWithChildren()
269
    {
270
        /** @var \yii\db\BaseActiveRecord|self $this */
271 3
        $this->autoTreeCall('preDeleteWithChildren', ['ns', 'ni', 'mp', 'al'], [], false);
272 3
        return $this->autoTreeCall('deleteWithChildren', ['ns', 'ni', 'mp', 'al']);
273
    }
274
}
275