Completed
Push — master ( dddeda...6cb9bf )
by ARCANEDEV
04:15
created

Collection::flattenTree()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 0
cts 6
cp 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 6
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\Database\Eloquent\Model;
7
8
/**
9
 * Class     Collection
10
 *
11
 * @package  Arcanedev\Taxonomies\Utilities
12
 * @author   ARCANEDEV <[email protected]>
13
 */
14
class Collection extends EloquentCollection
15
{
16
    /**
17
     * Fill `parent` and `children` relationships for every node in the collection.
18
     *
19
     * This will overwrite any previously set relations.
20
     *
21
     * @return $this
22
     */
23 20
    public function linkNodes()
24
    {
25 20
        if ($this->isEmpty()) {
26
            return $this;
27
        }
28
29 20
        $groupedNodes = $this->groupBy($this->first()->getParentIdName());
30
31
        /** @var NodeTrait|Model $node */
32 20
        foreach ($this->items as $node) {
33 20
            if ( ! $node->getParentId()) {
34
                $node->setRelation('parent', null);
35
            }
36
37 20
            $children = $groupedNodes->get($node->getKey(), [ ]);
38
39
            /** @var Model|NodeTrait $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 self
58
     */
59 20
    public function toTree($root = false)
60
    {
61 20
        if ($this->isEmpty()) {
62
            return new static;
63
        }
64
65 20
        $this->linkNodes();
66
67 20
        $items = [ ];
68
69 20
        $root = $this->getRootNodeId($root);
70
71
        /** @var Model|NodeTrait $node */
72 20
        foreach ($this->items as $node) {
73 20
            if ($node->getParentId() == $root) {
74 20
                $items[] = $node;
75 15
            }
76 15
        }
77
78 20
        return new static($items);
79
    }
80
81
    /**
82
     * Get root node id.
83
     *
84
     * @param  mixed  $root
85
     *
86
     * @return int
87
     */
88 20
    protected function getRootNodeId($root)
89
    {
90 20
        if (NestedSet::isNode($root)) {
91 4
            return $root->getKey();
92
        }
93
94 20
        if ($root !== false) {
95 8
            return $root;
96
        }
97
98
        // If root node is not specified we take parent id of node with
99
        // least lft value as root node id.
100 12
        $leastValue = null;
101
102
        /** @var Model|NodeTrait $node */
103 12
        foreach ($this->items as $node) {
104 12
            if ($leastValue === null || $node->getLft() < $leastValue) {
105 12
                $leastValue = $node->getLft();
106 12
                $root       = $node->getParentId();
107 9
            }
108 9
        }
109
110 12
        return $root;
111
    }
112
113
    /**
114
     * Build a list of nodes that retain the order that they were pulled from the database.
115
     *
116
     * @return self
117
     */
118
    public function toFlattenedTree()
119
    {
120
        return $this->toTree()->flattenTree();
121
    }
122
123
    /**
124
     * Flatten a tree into a non recursive array
125
     */
126
    public function flattenTree()
127
    {
128
        $items = [];
129
130
        foreach ($this->items as $node) {
131
            $items = array_merge($items, $this->flattenNode($node));
132
        }
133
134
        return new static($items);
135
    }
136
137
    /* ------------------------------------------------------------------------------------------------
138
     |  Other Functions
139
     | ------------------------------------------------------------------------------------------------
140
     */
141
    /**
142
     * Flatten a single node
143
     *
144
     * @param  \Arcanedev\LaravelNestedSet\NodeTrait  $node
0 ignored issues
show
introduced by
The type NodeTrait for parameter $node is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
145
     *
146
     * @return array
147
     */
148
    protected function flattenNode($node)
149
    {
150
        $items   = [];
151
        $items[] = $node;
152
153
        foreach ($node->children as $childNode) {
0 ignored issues
show
Bug introduced by
The property children does not seem to exist in Arcanedev\LaravelNestedSet\NodeTrait.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
154
            $items = array_merge($items, $this->flattenNode($childNode));
155
        }
156
157
        return $items;
158
    }
159
}
160