Completed
Push — master ( b06b97...f73407 )
by Colin
16s
created

Node::detach()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 14
cts 14
cp 1
rs 9.3222
c 0
b 0
f 0
cc 5
nc 9
nop 0
crap 5
1
<?php
2
3
namespace League\CommonMark\Node;
4
5
abstract class Node
6
{
7
    /**
8
     * @var int
9
     */
10
    protected $depth = 0;
11
12
    /**
13
     * @var Node|null
14
     */
15
    protected $parent;
16
17
    /**
18
     * @var Node|null
19
     */
20
    protected $previous;
21
22
    /**
23
     * @var Node|null
24
     */
25
    protected $next;
26
27
    /**
28
     * @var Node|null
29
     */
30
    protected $firstChild;
31
32
    /**
33
     * @var Node|null
34
     */
35
    protected $lastChild;
36
37
    /**
38
     * @return Node|null
39
     */
40 15
    public function previous(): ?Node
41
    {
42 15
        return $this->previous;
43
    }
44
45
    /**
46
     * @return Node|null
47
     */
48 1947
    public function next(): ?Node
49
    {
50 1947
        return $this->next;
51
    }
52
53
    /**
54
     * @return Node|null
55
     */
56 1962
    public function parent(): ?Node
57
    {
58 1962
        return $this->parent;
59
    }
60
61
    /**
62
     * @param Node|null $node
63
     */
64 1980
    protected function setParent(Node $node = null)
65
    {
66 1980
        $this->parent = $node;
67 1980
        $this->depth = ($node === null) ? 0 : $node->depth + 1;
68 1980
    }
69
70
    /**
71
     * Inserts the $sibling node after $this
72
     *
73
     * @param Node $sibling
74
     */
75 1503
    public function insertAfter(Node $sibling)
76
    {
77 1503
        $sibling->detach();
78 1503
        $sibling->next = $this->next;
79
80 1503
        if ($sibling->next) {
81 618
            $sibling->next->previous = $sibling;
82
        }
83
84 1503
        $sibling->previous = $this;
85 1503
        $this->next = $sibling;
86 1503
        $sibling->setParent($this->parent);
87
88 1503
        if (!$sibling->next) {
89 1503
            $sibling->parent->lastChild = $sibling;
90
        }
91 1503
    }
92
93
    /**
94
     * Inserts the $sibling node before $this
95
     *
96
     * @param Node $sibling
97
     */
98 9
    public function insertBefore(Node $sibling)
99
    {
100 9
        $sibling->detach();
101 9
        $sibling->previous = $this->previous;
102
103 9
        if ($sibling->previous) {
104 3
            $sibling->previous->next = $sibling;
105
        }
106
107 9
        $sibling->next = $this;
108 9
        $this->previous = $sibling;
109 9
        $sibling->setParent($this->parent);
110
111 9
        if (!$sibling->previous) {
112 6
            $sibling->parent->firstChild = $sibling;
113
        }
114 9
    }
115
116 384
    public function replaceWith(Node $replacement)
117
    {
118 384
        $replacement->detach();
119 384
        $this->insertAfter($replacement);
120 384
        $this->detach();
121 384
    }
122
123 1980
    public function detach()
124
    {
125 1980
        if ($this->previous) {
126 657
            $this->previous->next = $this->next;
127 1980
        } elseif ($this->parent) {
128 534
            $this->parent->firstChild = $this->next;
129
        }
130
131 1980
        if ($this->next) {
132 666
            $this->next->previous = $this->previous;
133 1980
        } elseif ($this->parent) {
134 591
            $this->parent->lastChild = $this->previous;
135
        }
136
137 1980
        $this->parent = null;
138 1980
        $this->next = null;
139 1980
        $this->previous = null;
140 1980
        $this->depth = 0;
141 1980
    }
142
143
    /**
144
     * @return bool
145
     */
146
    abstract public function isContainer(): bool;
147
148
    /**
149
     * @return Node|null
150
     */
151 1953
    public function firstChild(): ?Node
152
    {
153 1953
        return $this->firstChild;
154
    }
155
156
    /**
157
     * @return Node|null
158
     */
159 1944
    public function lastChild(): ?Node
160
    {
161 1944
        return $this->lastChild;
162
    }
163
164
    /**
165
     * @return Node[]
166
     */
167 2043
    public function children(): iterable
168
    {
169 2043
        $children = [];
170 2043
        for ($current = $this->firstChild; null !== $current; $current = $current->next) {
171 1959
            $children[] = $current;
172
        }
173
174 2043
        return $children;
175
    }
176
177
    /**
178
     * @param Node $child
179
     */
180 1974
    public function appendChild(Node $child)
181
    {
182 1974
        if ($this->lastChild) {
183 1488
            $this->lastChild->insertAfter($child);
184
        } else {
185 1974
            $child->detach();
186 1974
            $child->setParent($this);
187 1974
            $this->lastChild = $this->firstChild = $child;
188
        }
189 1974
    }
190
191
    /**
192
     * Adds $child as the very first child of $this
193
     *
194
     * @param Node $child
195
     */
196 6
    public function prependChild(Node $child)
197
    {
198 6
        if ($this->firstChild) {
199 3
            $this->firstChild->insertBefore($child);
200
        } else {
201 6
            $child->detach();
202 6
            $child->setParent($this);
203 6
            $this->lastChild = $this->firstChild = $child;
204
        }
205 6
    }
206
207
    /**
208
     * Detaches all child nodes of given node
209
     */
210 6
    public function detachChildren()
211
    {
212 6
        foreach ($this->children() as $children) {
213 6
            $children->setParent(null);
214
        }
215 6
        $this->firstChild = $this->lastChild = null;
216 6
    }
217
218
    /**
219
     * Replace all children of given node with collection of another
220
     *
221
     * @param iterable $children
222
     *
223
     * @return $this
224
     */
225 3
    public function replaceChildren(iterable $children)
226
    {
227 3
        $this->detachChildren();
228 3
        foreach ($children as $item) {
229 3
            $this->appendChild($item);
230
        }
231
232 3
        return $this;
233
    }
234
235
    /**
236
     * @return int
237
     */
238 396
    public function getDepth(): int
239
    {
240 396
        return $this->depth;
241
    }
242
243
    /**
244
     * @return NodeWalker
245
     */
246 1941
    public function walker(): NodeWalker
247
    {
248 1941
        return new NodeWalker($this);
249
    }
250
}
251