Completed
Push — master ( 3c077b...77d3a9 )
by Gilles
06:36
created

InnerNode::hasChildren()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
namespace PHPHtmlParser\Dom;
3
4
use PHPHtmlParser\Exceptions\ChildNotFoundException;
5
use PHPHtmlParser\Exceptions\CircularException;
6
use stringEncode\Encode;
7
8
/**
9
 * Inner node of the html tree, might have children.
10
 *
11
 * @package PHPHtmlParser\Dom
12
 */
13
abstract class InnerNode extends ArrayNode
14
{
15
16
    /**
17
     * An array of all the children.
18
     *
19
     * @var array
20
     */
21
    protected $children = [];
22
23
    /**
24
     * Sets the encoding class to this node and propagates it
25
     * to all its children.
26
     *
27
     * @param Encode $encode
28
     * @return void
29
     */
30
    public function propagateEncoding(Encode $encode)
31
    {
32
        $this->encode = $encode;
33
        $this->tag->setEncoding($encode);
34
        // check children
35
        foreach ($this->children as $id => $child) {
36
            /** @var AbstractNode $node */
37
            $node = $child['node'];
38
            $node->propagateEncoding($encode);
39
        }
40
    }
41
42
    /**
43
     * Checks if this node has children.
44
     *
45
     * @return bool
46
     */
47
    public function hasChildren()
48
    {
49
        return ! empty($this->children);
50
    }
51
52
    /**
53
     * Returns the child by id.
54
     *
55
     * @param int $id
56
     * @return AbstractNode
57
     * @throws ChildNotFoundException
58
     */
59
    public function getChild($id)
60
    {
61
        if ( ! isset($this->children[$id])) {
62
            throw new ChildNotFoundException("Child '$id' not found in this node.");
63
        }
64
65
        return $this->children[$id]['node'];
66
    }
67
68
    /**
69
     * Returns a new array of child nodes
70
     *
71
     * @return array
72
     */
73
    public function getChildren()
74
    {
75
        $nodes = [];
76
        try {
77
            $child = $this->firstChild();
78
            do {
79
                $nodes[] = $child;
80
                $child   = $this->nextChild($child->id());
81
            } while ( ! is_null($child));
82
        } catch (ChildNotFoundException $e) {
83
            // we are done looking for children
84
        }
85
86
        return $nodes;
87
    }
88
89
    /**
90
     * Counts children
91
     *
92
     * @return int
93
     */
94
    public function countChildren()
95
    {
96
        return count($this->children);
97
    }
98
99
    /**
100
     * Adds a child node to this node and returns the id of the child for this
101
     * parent.
102
     *
103
     * @param AbstractNode $child
104
     * @return bool
105
     * @throws CircularException
106
     */
107
    public function addChild(AbstractNode $child)
108
    {
109
        $key = null;
110
111
        // check integrity
112
        if ($this->isAncestor($child->id())) {
113
            throw new CircularException('Can not add child. It is my ancestor.');
114
        }
115
116
        // check if child is itself
117
        if ($child->id() == $this->id) {
118
            throw new CircularException('Can not set itself as a child.');
119
        }
120
121
        if ($this->hasChildren()) {
122
            if (isset($this->children[$child->id()])) {
123
                // we already have this child
124
                return false;
125
            }
126
            $sibling                      = $this->lastChild();
127
            $key                          = $sibling->id();
128
            $this->children[$key]['next'] = $child->id();
129
        }
130
131
        // add the child
132
        $this->children[$child->id()] = [
133
            'node' => $child,
134
            'next' => null,
135
            'prev' => $key,
136
        ];
137
138
        // tell child I am the new parent
139
        $child->setParent($this);
140
141
        //clear any cache
142
        $this->clear();
143
144
        return true;
145
    }
146
147
    /**
148
     * Removes the child by id.
149
     *
150
     * @param int $id
151
     * @return $this
152
     */
153
    public function removeChild($id)
154
    {
155
        if ( ! isset($this->children[$id])) {
156
            return $this;
157
        }
158
159
        // handle moving next and previous assignments.
160
        $next = $this->children[$id]['next'];
161
        $prev = $this->children[$id]['prev'];
162
        if ( ! is_null($next)) {
163
            $this->children[$next]['prev'] = $prev;
164
        }
165
        if ( ! is_null($prev)) {
166
            $this->children[$prev]['next'] = $next;
167
        }
168
169
        // remove the child
170
        unset($this->children[$id]);
171
172
        //clear any cache
173
        $this->clear();
174
175
        return $this;
176
    }
177
178
    /**
179
     * Attempts to get the next child.
180
     *
181
     * @param int $id
182
     * @return AbstractNode
183
     * @uses $this->getChild()
184
     */
185 View Code Duplication
    public function nextChild($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
    {
187
        $child = $this->getChild($id);
188
        $next  = $this->children[$child->id()]['next'];
189
190
        return $this->getChild($next);
191
    }
192
193
    /**
194
     * Attempts to get the previous child.
195
     *
196
     * @param int $id
197
     * @return AbstractNode
198
     * @uses $this->getChild()
199
     */
200 View Code Duplication
    public function previousChild($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
    {
202
        $child = $this->getchild($id);
203
        $next  = $this->children[$child->id()]['prev'];
204
205
        return $this->getChild($next);
206
    }
207
208
    /**
209
     * Checks if the given node id is a child of the
210
     * current node.
211
     *
212
     * @param int $id
213
     * @return bool
214
     */
215
    public function isChild($id)
216
    {
217
        foreach ($this->children as $childId => $child) {
218
            if ($id == $childId) {
219
                return true;
220
            }
221
        }
222
223
        return false;
224
    }
225
226
    /**
227
     * Checks if the given node id is a descendant of the
228
     * current node.
229
     *
230
     * @param int $id
231
     * @return bool
232
     */
233
    public function isDescendant($id)
234
    {
235
        if ($this->isChild($id)) {
236
            return true;
237
        }
238
239
        foreach ($this->children as $childId => $child) {
240
            /** @var InnerNode $node */
241
            $node = $child['node'];
242
            if ($node instanceof InnerNode &&
243
                $node->hasChildren() &&
244
                $node->isDescendant($id)
245
            ) {
246
                return true;
247
            }
248
        }
249
250
        return false;
251
    }
252
253
    /**
254
     * Sets the parent node.
255
     *
256
     * @param InnerNode $parent
257
     * @return $this
258
     * @throws CircularException
259
     */
260
    public function setParent(InnerNode $parent)
261
    {
262
        // check integrity
263
        if ($this->isDescendant($parent->id())) {
264
            throw new CircularException('Can not add descendant "'.$parent->id().'" as my parent.');
265
        }
266
267
        return parent::setParent($parent);
268
    }
269
}