Passed
Branch dev/3.0.0 (c487fc)
by Gilles
01:48
created

HtmlNode::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser\Dom\Node;
6
7
use PHPHtmlParser\Exceptions\ChildNotFoundException;
8
use PHPHtmlParser\Exceptions\UnknownChildTypeException;
9
use PHPHtmlParser\Dom\Tag;
10
11
/**
12
 * Class HtmlNode.
13
 */
14
class HtmlNode extends InnerNode
15
{
16
    /**
17
     * Remembers what the innerHtml was if it was scanned previously.
18
     *
19
     * @var ?string
20
     */
21
    protected $innerHtml;
22
23
    /**
24
     * Remembers what the outerHtml was if it was scanned previously.
25
     *
26
     * @var ?string
27
     */
28
    protected $outerHtml;
29
30
    /**
31
     * Remembers what the text was if it was scanned previously.
32
     *
33
     * @var ?string
34
     */
35
    protected $text;
36
37
    /**
38
     * Remembers what the text was when we looked into all our
39
     * children nodes.
40
     *
41
     * @var ?string
42
     */
43
    protected $textWithChildren;
44
45
    /**
46
     * Sets up the tag of this node.
47
     *
48
     * @param string|Tag $tag
49
     */
50 414
    public function __construct($tag)
51
    {
52 414
        if (!$tag instanceof Tag) {
53 330
            $tag = new Tag($tag);
54
        }
55 414
        $this->tag = $tag;
56 414
        parent::__construct();
57 414
    }
58
59
    /**
60
     * @param bool $htmlSpecialCharsDecode
61
     */
62 285
    public function setHtmlSpecialCharsDecode($htmlSpecialCharsDecode = false): void
63
    {
64 285
        parent::setHtmlSpecialCharsDecode($htmlSpecialCharsDecode);
65 285
        $this->tag->setHtmlSpecialCharsDecode($htmlSpecialCharsDecode);
66 285
    }
67
68
    /**
69
     * Gets the inner html of this node.
70
     *
71
     * @throws ChildNotFoundException
72
     * @throws UnknownChildTypeException
73
     */
74 162
    public function innerHtml(): string
75
    {
76 162
        if (!$this->hasChildren()) {
77
            // no children
78 24
            return '';
79
        }
80
81 150
        if ($this->innerHtml !== null) {
82
            // we already know the result.
83 3
            return $this->innerHtml;
84
        }
85
86 150
        $child = $this->firstChild();
87 150
        $string = '';
88
89
        // continue to loop until we are out of children
90 150
        while ($child !== null) {
91 150
            if ($child instanceof TextNode) {
92 141
                $string .= $child->text();
93 129
            } elseif ($child instanceof HtmlNode) {
94 129
                $string .= $child->outerHtml();
95
            } else {
96 3
                throw new UnknownChildTypeException('Unknown child type "' . \get_class($child) . '" found in node');
97
            }
98
99
            try {
100 150
                $child = $this->nextChild($child->id());
101 150
            } catch (ChildNotFoundException $e) {
102
                // no more children
103 150
                unset($e);
104 150
                $child = null;
105
            }
106
        }
107
108
        // remember the results
109 150
        $this->innerHtml = $string;
110
111 150
        return $string;
112
    }
113
114
    /**
115
     * Gets the html of this node, including it's own
116
     * tag.
117
     *
118
     * @throws ChildNotFoundException
119
     * @throws UnknownChildTypeException
120
     */
121 156
    public function outerHtml(): string
122
    {
123
        // special handling for root
124 156
        if ($this->tag->name() == 'root') {
125 12
            return $this->innerHtml();
126
        }
127
128 156
        if ($this->outerHtml !== null) {
129
            // we already know the results.
130 6
            return $this->outerHtml;
131
        }
132
133 156
        $return = $this->tag->makeOpeningTag();
134 156
        if ($this->tag->isSelfClosing()) {
135
            // ignore any children... there should not be any though
136 87
            return $return;
137
        }
138
139
        // get the inner html
140 141
        $return .= $this->innerHtml();
141
142
        // add closing tag
143 141
        $return .= $this->tag->makeClosingTag();
144
145
        // remember the results
146 141
        $this->outerHtml = $return;
147
148 141
        return $return;
149
    }
150
151
    /**
152
     * Gets the text of this node (if there is any text). Or get all the text
153
     * in this node, including children.
154
     */
155 48
    public function text(bool $lookInChildren = false): string
156
    {
157 48
        if ($lookInChildren) {
158 6
            if ($this->textWithChildren !== null) {
159
                // we already know the results.
160 6
                return $this->textWithChildren;
161
            }
162 45
        } elseif ($this->text !== null) {
163
            // we already know the results.
164 3
            return $this->text;
165
        }
166
167
        // find out if this node has any text children
168 48
        $text = '';
169 48
        foreach ($this->children as $child) {
170
            /** @var AbstractNode $node */
171 45
            $node = $child['node'];
172 45
            if ($node instanceof TextNode) {
173 45
                $text .= $child['node']->text;
174
            } elseif (
175 6
                $lookInChildren &&
176 6
                $node instanceof HtmlNode
177
            ) {
178 6
                $text .= $node->text($lookInChildren);
179
            }
180
        }
181
182
        // remember our result
183 48
        if ($lookInChildren) {
184 6
            $this->textWithChildren = $text;
185
        } else {
186 45
            $this->text = $text;
187
        }
188
189 48
        return $text;
190
    }
191
192
    /**
193
     * Call this when something in the node tree has changed. Like a child has been added
194
     * or a parent has been changed.
195
     */
196 396
    protected function clear(): void
197
    {
198 396
        $this->innerHtml = null;
199 396
        $this->outerHtml = null;
200 396
        $this->text = null;
201 396
        $this->textWithChildren = null;
202
203 396
        if ($this->parent !== null) {
204 312
            $this->parent->clear();
205
        }
206 396
    }
207
208
    /**
209
     * Returns all children of this html node.
210
     */
211 6
    protected function getIteratorArray(): array
212
    {
213 6
        return $this->getChildren();
214
    }
215
}
216