Completed
Push — master ( 84e485...c5777c )
by Colin
46:01 queued 44:53
created

Element::getNextSibling()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
namespace League\HTMLToMarkdown;
4
5
class Element implements ElementInterface
6
{
7
    /**
8
     * @var \DOMNode
9
     */
10
    protected $node;
11
12
    /**
13
     * @var ElementInterface|null
14
     */
15
    private $nextCached;
16
17
    /**
18
     * @var DOMNode|null
19
     */
20
    private $previousSiblingCached;
21
22 96
    public function __construct(\DOMNode $node)
23
    {
24 96
        $this->node = $node;
25 96
        $this->previousSiblingCached = $this->node->previousSibling;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->node->previousSibling of type object<DOMNode> is incompatible with the declared type object<League\HTMLToMarkdown\DOMNode>|null of property $previousSiblingCached.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
26 96
    }
27
28
    /**
29
     * @return bool
30
     */
31 18
    public function isBlock()
32
    {
33 18
        switch ($this->getTagName()) {
34 18
            case 'blockquote':
35 18
            case 'body':
36 18
            case 'div':
37 18
            case 'h1':
38 18
            case 'h2':
39 18
            case 'h3':
40 18
            case 'h4':
41 18
            case 'h5':
42 18
            case 'h6':
43 18
            case 'hr':
44 18
            case 'html':
45 18
            case 'li':
46 17
            case 'p':
47 17
            case 'ol':
48 17
            case 'ul':
49 3
                return true;
50 10
            default:
51 15
                return false;
52 10
        }
53
    }
54
55
    /**
56
     * @return bool
57
     */
58 18
    public function isText()
59
    {
60 18
        return $this->getTagName() === '#text';
61
    }
62
63
    /**
64
     * @return bool
65
     */
66 9
    public function isWhitespace()
67
    {
68 9
        return $this->getTagName() === '#text' && trim($this->getValue()) === '';
69
    }
70
71
    /**
72
     * @return string
73
     */
74 96
    public function getTagName()
75
    {
76 96
        return $this->node->nodeName;
77
    }
78
79
    /**
80
     * @return string
81
     */
82 84
    public function getValue()
83
    {
84 84
        return $this->node->nodeValue;
85
    }
86
87
    /**
88
     * @return ElementInterface|null
89
     */
90 81
    public function getParent()
91
    {
92 81
        return new static($this->node->parentNode) ?: null;
93
    }
94
95
    /**
96
     * @return ElementInterface|null
97
     */
98 18
    public function getNextSibling()
99
    {
100 18
        return $this->node->nextSibling !== null ? new static($this->node->nextSibling) : null;
101
    }
102
103
    /**
104
     * @return ElementInterface|null
105
     */
106 18
    public function getPreviousSibling()
107
    {
108 18
        return $this->previousSiblingCached !== null ? new static($this->previousSiblingCached) : null;
109
    }
110
111
    /**
112
     * @return bool
113
     */
114 96
    public function hasChildren()
115
    {
116 96
        return $this->node->hasChildNodes();
117
    }
118
119
    /**
120
     * @return ElementInterface[]
121
     */
122 96
    public function getChildren()
123
    {
124 96
        $ret = array();
125
        /** @var \DOMNode $node */
126 96
        foreach ($this->node->childNodes as $node) {
127 96
            $ret[] = new static($node);
128 64
        }
129
130 96
        return $ret;
131
    }
132
133
    /**
134
     * @return ElementInterface|null
135
     */
136 24
    public function getNext()
137
    {
138 24
        if ($this->nextCached === null) {
139 24
            $nextNode = $this->getNextNode($this->node);
140 24
            if ($nextNode !== null) {
141 24
                $this->nextCached = new static($nextNode);
142 16
            }
143 16
        }
144
145 24
        return $this->nextCached;
146
    }
147
148
    /**
149
     * @param \DomNode $node
150
     * @param bool $checkChildren
151
     *
152
     * @return \DomNode|null
153
     */
154 24
    private function getNextNode($node, $checkChildren = true)
155
    {
156 24
        if ($checkChildren && $node->firstChild) {
157
            return $node->firstChild;
158
        }
159
160 24
        if ($node->nextSibling) {
161 24
            return $node->nextSibling;
162
        }
163
164 6
        if ($node->parentNode) {
165 6
            return $this->getNextNode($node->parentNode, false);
166
        }
167
    }
168
169
    /**
170
     * @param string[]|string $tagNames
171
     *
172
     * @return bool
173
     */
174 96
    public function isDescendantOf($tagNames)
175
    {
176 96
        if (!is_array($tagNames)) {
177 6
            $tagNames = array($tagNames);
178 4
        }
179
180 96
        for ($p = $this->node->parentNode; $p !== false; $p = $p->parentNode) {
181 96
            if (is_null($p)) {
182 96
                return false;
183
            }
184
185 96
            if (in_array($p->nodeName, $tagNames)) {
186 24
                return true;
187
            }
188 64
        }
189
190
        return false;
191
    }
192
193
    /**
194
     * @param string $markdown
195
     */
196 96
    public function setFinalMarkdown($markdown)
197
    {
198 96
        $markdown_node = $this->node->ownerDocument->createTextNode($markdown);
199 96
        $this->node->parentNode->replaceChild($markdown_node, $this->node);
200 96
    }
201
202
    /**
203
     * @return string
204
     */
205 87
    public function getChildrenAsString()
206
    {
207 87
        return $this->node->C14N();
208
    }
209
210
    /**
211
     * @return int
212
     */
213 9
    public function getSiblingPosition()
214
    {
215 9
        $position = 0;
216
217
        // Loop through all nodes and find the given $node
218 9
        foreach ($this->getParent()->getChildren() as $current_node) {
219 9
            if (!$current_node->isWhitespace()) {
220 9
                $position++;
221 6
            }
222
223
            // TODO: Need a less-buggy way of comparing these
224
            // Perhaps we can somehow ensure that we always have the exact same object and use === instead?
225 9
            if ($this->equals($current_node)) {
226 9
                break;
227
            }
228 6
        }
229
230 9
        return $position;
231
    }
232
233
    /**
234
     * @return int
235
     */
236 12
    public function getListItemLevel()
237
    {
238 12
        $level = 0;
239 12
        $parent = $this->getParent();
240
241 12
        while ($parent !== null && $parent->node->parentNode) {
242 12
            if ($parent->getTagName() === 'li') {
243 6
                $level++;
244 4
            }
245 12
            $parent = $parent->getParent();
246 8
        }
247
248 12
        return $level;
249
    }
250
251
    /**
252
     * @param string $name
253
     *
254
     * @return string
255
     */
256 30
    public function getAttribute($name)
257
    {
258 30
        if ($this->node instanceof \DOMElement) {
259 30
            return $this->node->getAttribute($name);
260
        }
261
262
        return '';
263
    }
264
265
    /**
266
     * @param ElementInterface $element
267
     *
268
     * @return bool
269
     */
270 9
    public function equals(ElementInterface $element)
271
    {
272 9
        if ($element instanceof self) {
273 9
            return $element->node === $this->node;
274
        }
275
276
        return $element === $this;
277
    }
278
}
279