Completed
Push — master ( c56598...026f51 )
by ARCANEDEV
8s
created

Collection::toFlatTree()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
crap 2
1
<?php namespace Arcanedev\LaravelNestedSet\Eloquent;
2
3
use Arcanedev\LaravelNestedSet\NodeTrait;
4
use Arcanedev\LaravelNestedSet\Utilities\NestedSet;
5
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
6
use Illuminate\Support\Collection as BaseCollection;
7
8
/**
9
 * Class     Collection
10
 *
11
 * @package  Arcanedev\LaravelNestedSet\Eloquent
12
 * @author   ARCANEDEV <[email protected]>
13
 */
14
class Collection extends EloquentCollection
15
{
16
    /* ------------------------------------------------------------------------------------------------
17
     |  Main Functions
18
     | ------------------------------------------------------------------------------------------------
19
     */
20
    /**
21
     * Fill `parent` and `children` relationships for every node in the collection.
22
     *
23
     * This will overwrite any previously set relations.
24
     *
25
     * @return \Arcanedev\LaravelNestedSet\Eloquent\Collection
26
     */
27 20
    public function linkNodes()
28
    {
29 20
        if ($this->isEmpty()) return $this;
30
31 20
        $groupedNodes = $this->groupBy($this->first()->getParentIdName());
32
33
        /** @var  NodeTrait|\Illuminate\Database\Eloquent\Model  $node */
34 20
        foreach ($this->items as $node) {
35 20
            if ($node->getParentId() === null) $node->setRelation('parent', null);
36
37 20
            $children = $groupedNodes->get($node->getKey(), []);
38
39
            /** @var  NodeTrait|\Illuminate\Database\Eloquent\Model  $child */
40 20
            foreach ($children as $child) {
41 20
                $child->setRelation('parent', $node);
42 15
            }
43
44 20
            $node->setRelation('children', EloquentCollection::make($children));
45 15
        }
46
47 20
        return $this;
48
    }
49
50
    /**
51
     * Build a tree from a list of nodes. Each item will have set children relation.
52
     * To successfully build tree "id", "_lft" and "parent_id" keys must present.
53
     * If `$root` is provided, the tree will contain only descendants of that node.
54
     *
55
     * @param  mixed  $root
56
     *
57
     * @return \Arcanedev\LaravelNestedSet\Eloquent\Collection
58
     */
59 20
    public function toTree($root = false)
60
    {
61 20
        if ($this->isEmpty()) return new static;
62
63 20
        $this->linkNodes();
64
65 20
        $items = [];
66 20
        $root  = $this->getRootNodeId($root);
67
68
        /** @var  NodeTrait|\Illuminate\Database\Eloquent\Model  $node */
69 20
        foreach ($this->items as $node) {
70 20
            if ($node->getParentId() == $root) {
71 20
                $items[] = $node;
72 15
            }
73 15
        }
74
75 20
        return new static($items);
76
    }
77
78
    /**
79
     * Build a list of nodes that retain the order that they were pulled from the database.
80
     *
81
     * @param  bool  $root
82
     *
83
     * @return \Arcanedev\LaravelNestedSet\Eloquent\Collection
84
     */
85 4
    public function toFlatTree($root = false)
86
    {
87 4
        $result = new static;
88
89 4
        if ($this->isEmpty()) return $result;
90
91 4
        return $result->flattenTree(
92 4
            $this->groupBy($this->first()->getParentIdName()),
93 4
            $this->getRootNodeId($root)
94 3
        );
95
    }
96
97
    /* ------------------------------------------------------------------------------------------------
98
     |  Other Functions
99
     | ------------------------------------------------------------------------------------------------
100
     */
101
    /**
102
     * Get root node id.
103
     *
104
     * @param  mixed  $root
105
     *
106
     * @return int
107
     */
108 24
    protected function getRootNodeId($root = false)
109
    {
110 24
        if (NestedSet::isNode($root)) {
111 4
            return $root->getKey();
112
        }
113
114 24
        if ($root !== false) return $root;
115
116
        // If root node is not specified we take parent id of node with
117
        // least lft value as root node id.
118 16
        $leastValue = null;
119
120
        /** @var  NodeTrait|\Illuminate\Database\Eloquent\Model  $node */
121 16
        foreach ($this->items as $node) {
122 16
            if ($leastValue === null || $node->getLft() < $leastValue) {
123 16
                $leastValue = $node->getLft();
124 16
                $root       = $node->getParentId();
125 12
            }
126 12
        }
127
128 16
        return $root;
129
    }
130
131
    /**
132
     * Flatten a tree into a non recursive array.
133
     *
134
     * @param  \Illuminate\Support\Collection  $groupedNodes
135
     * @param  mixed                           $parentId
136
     *
137
     * @return \Arcanedev\LaravelNestedSet\Eloquent\Collection
138
     */
139 4
    protected function flattenTree(BaseCollection $groupedNodes, $parentId)
140
    {
141
        /** @var \Arcanedev\LaravelNestedSet\Contracts\Nodeable  $node */
142 4
        foreach ($groupedNodes->get($parentId, []) as $node) {
143 4
            $this->push($node);
144 4
            $this->flattenTree($groupedNodes, $node->getKey());
145 3
        }
146
147 4
        return $this;
148
    }
149
}
150