Passed
Push — master ( 668c77...c11634 )
by Gilles
02:19
created

HtmlNode::text()   B

Complexity

Conditions 9
Paths 18

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9

Importance

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