Passed
Pull Request — master (#225)
by
unknown
12:21
created

HtmlNode::innerText()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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