Node::detach()   A
last analyzed

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
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 *
8
 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
9
 *  - (c) John MacFarlane
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace League\CommonMark\Node;
16
17
abstract class Node
18
{
19
    /**
20
     * @var int
21
     */
22
    protected $depth = 0;
23
24
    /**
25
     * @var Node|null
26
     */
27
    protected $parent;
28
29
    /**
30
     * @var Node|null
31
     */
32
    protected $previous;
33
34
    /**
35
     * @var Node|null
36
     */
37
    protected $next;
38
39
    /**
40
     * @var Node|null
41
     */
42
    protected $firstChild;
43
44
    /**
45
     * @var Node|null
46
     */
47
    protected $lastChild;
48
49
    /**
50
     * @return Node|null
51
     */
52 438
    public function previous(): ?Node
53
    {
54 438
        return $this->previous;
55
    }
56
57
    /**
58
     * @return Node|null
59
     */
60 2088
    public function next(): ?Node
61
    {
62 2088
        return $this->next;
63
    }
64
65
    /**
66
     * @return Node|null
67
     */
68 2106
    public function parent(): ?Node
69
    {
70 2106
        return $this->parent;
71
    }
72
73
    /**
74
     * @param Node|null $node
75
     */
76 2133
    protected function setParent(Node $node = null)
77
    {
78 2133
        $this->parent = $node;
79 2133
        $this->depth = ($node === null) ? 0 : $node->depth + 1;
80 2133
    }
81
82
    /**
83
     * Inserts the $sibling node after $this
84
     *
85
     * @param Node $sibling
86
     */
87 1758
    public function insertAfter(Node $sibling)
88
    {
89 1758
        $sibling->detach();
90 1758
        $sibling->next = $this->next;
91
92 1758
        if ($sibling->next) {
93 711
            $sibling->next->previous = $sibling;
94
        }
95
96 1758
        $sibling->previous = $this;
97 1758
        $this->next = $sibling;
98 1758
        $sibling->setParent($this->parent);
99
100 1758
        if (!$sibling->next && $sibling->parent) {
101 1755
            $sibling->parent->lastChild = $sibling;
102
        }
103 1758
    }
104
105
    /**
106
     * Inserts the $sibling node before $this
107
     *
108
     * @param Node $sibling
109
     */
110 18
    public function insertBefore(Node $sibling)
111
    {
112 18
        $sibling->detach();
113 18
        $sibling->previous = $this->previous;
114
115 18
        if ($sibling->previous) {
116 9
            $sibling->previous->next = $sibling;
117
        }
118
119 18
        $sibling->next = $this;
120 18
        $this->previous = $sibling;
121 18
        $sibling->setParent($this->parent);
122
123 18
        if (!$sibling->previous && $sibling->parent) {
124 6
            $sibling->parent->firstChild = $sibling;
125
        }
126 18
    }
127
128 399
    public function replaceWith(Node $replacement)
129
    {
130 399
        $replacement->detach();
131 399
        $this->insertAfter($replacement);
132 399
        $this->detach();
133 399
    }
134
135 2130
    public function detach()
136
    {
137 2130
        if ($this->previous) {
138 1065
            $this->previous->next = $this->next;
139 2130
        } elseif ($this->parent) {
140 573
            $this->parent->firstChild = $this->next;
141
        }
142
143 2130
        if ($this->next) {
144 975
            $this->next->previous = $this->previous;
145 2130
        } elseif ($this->parent) {
146 933
            $this->parent->lastChild = $this->previous;
147
        }
148
149 2130
        $this->parent = null;
150 2130
        $this->next = null;
151 2130
        $this->previous = null;
152 2130
        $this->depth = 0;
153 2130
    }
154
155
    /**
156
     * @return bool
157
     */
158
    abstract public function isContainer(): bool;
159
160
    /**
161
     * @return Node|null
162
     */
163 2091
    public function firstChild(): ?Node
164
    {
165 2091
        return $this->firstChild;
166
    }
167
168
    /**
169
     * @return Node|null
170
     */
171 2076
    public function lastChild(): ?Node
172
    {
173 2076
        return $this->lastChild;
174
    }
175
176
    /**
177
     * @return Node[]
178
     */
179 2169
    public function children(): iterable
180
    {
181 2169
        $children = [];
182 2169
        for ($current = $this->firstChild; null !== $current; $current = $current->next) {
183 2091
            $children[] = $current;
184
        }
185
186 2169
        return $children;
187
    }
188
189
    /**
190
     * @param Node $child
191
     */
192 2118
    public function appendChild(Node $child)
193
    {
194 2118
        if ($this->lastChild) {
195 1740
            $this->lastChild->insertAfter($child);
196
        } else {
197 2118
            $child->detach();
198 2118
            $child->setParent($this);
199 2118
            $this->lastChild = $this->firstChild = $child;
200
        }
201 2118
    }
202
203
    /**
204
     * Adds $child as the very first child of $this
205
     *
206
     * @param Node $child
207
     */
208 6
    public function prependChild(Node $child)
209
    {
210 6
        if ($this->firstChild) {
211 3
            $this->firstChild->insertBefore($child);
212
        } else {
213 6
            $child->detach();
214 6
            $child->setParent($this);
215 6
            $this->lastChild = $this->firstChild = $child;
216
        }
217 6
    }
218
219
    /**
220
     * Detaches all child nodes of given node
221
     */
222 6
    public function detachChildren()
223
    {
224 6
        foreach ($this->children() as $children) {
225 6
            $children->setParent(null);
226
        }
227 6
        $this->firstChild = $this->lastChild = null;
228 6
    }
229
230
    /**
231
     * Replace all children of given node with collection of another
232
     *
233
     * @param iterable $children
234
     *
235
     * @return $this
236
     */
237 3
    public function replaceChildren(iterable $children)
238
    {
239 3
        $this->detachChildren();
240 3
        foreach ($children as $item) {
241 3
            $this->appendChild($item);
242
        }
243
244 3
        return $this;
245
    }
246
247
    /**
248
     * @return int
249
     */
250 405
    public function getDepth(): int
251
    {
252 405
        return $this->depth;
253
    }
254
255
    /**
256
     * @return NodeWalker
257
     */
258 2076
    public function walker(): NodeWalker
259
    {
260 2076
        return new NodeWalker($this);
261
    }
262
}
263