Completed
Push — master ( 77e4a4...d10009 )
by Gilles
03:09
created

HtmlNode   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 2 Features 0
Metric Value
eloc 66
c 4
b 2
f 0
dl 0
loc 205
ccs 68
cts 68
cp 1
rs 10
wmc 26

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
B innerHtml() 0 37 7
A setHtmlSpecialCharsDecode() 0 4 1
B text() 0 34 9
A outerHtml() 0 28 4
A clear() 0 9 2
A getIteratorArray() 0 3 1
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 text was if it was scanned previously.
31
     *
32
     * @var string
33
     */
34
    protected $text = null;
35
36
    /**
37
     * Remembers what the text was when we looked into all our
38
     * children nodes.
39
     *
40
     * @var string
41
     */
42
    protected $textWithChildren = null;
43
44
    /**
45
     * Sets up the tag of this node.
46
     *
47
     * @param string|Tag $tag
48
     */
49 354
    public function __construct($tag)
50
    {
51 354
        if ( ! $tag instanceof Tag) {
52 270
            $tag = new Tag($tag);
53
        }
54 354
        $this->tag = $tag;
55 354
        parent::__construct();
56 354
    }
57
58
    /**
59
     * @param bool $htmlSpecialCharsDecode
60
     * @return void
61
     */
62 228
    public function setHtmlSpecialCharsDecode($htmlSpecialCharsDecode = false): void
63
    {
64 228
        parent::setHtmlSpecialCharsDecode($htmlSpecialCharsDecode);
65 228
        $this->tag->setHtmlSpecialCharsDecode($htmlSpecialCharsDecode);
66 228
    }
67
68
    /**
69
     * Gets the inner html of this node.
70
     * @return string
71
     * @throws ChildNotFoundException
72
     * @throws UnknownChildTypeException
73
     */
74 138
    public function innerHtml(): string
75
    {
76 138
        if ( ! $this->hasChildren()) {
77
            // no children
78 18
            return '';
79
        }
80
81 129
        if ( ! is_null($this->innerHtml)) {
0 ignored issues
show
introduced by
The condition is_null($this->innerHtml) is always false.
Loading history...
82
            // we already know the result.
83 3
            return $this->innerHtml;
84
        }
85
86 129
        $child  = $this->firstChild();
87 129
        $string = '';
88
89
        // continue to loop until we are out of children
90 129
        while ( ! is_null($child)) {
91 129
            if ($child instanceof TextNode) {
92 123
                $string .= $child->text();
93 114
            } elseif ($child instanceof HtmlNode) {
94 114
                $string .= $child->outerHtml();
95
            } else {
96 3
                throw new UnknownChildTypeException('Unknown child type "'.get_class($child).'" found in node');
97
            }
98
99
            try {
100 129
                $child = $this->nextChild($child->id());
101 129
            } catch (ChildNotFoundException $e) {
102
                // no more children
103 129
                $child = null;
104
            }
105
        }
106
107
        // remember the results
108 129
        $this->innerHtml = $string;
109
110 129
        return $string;
111
    }
112
113
    /**
114
     * Gets the html of this node, including it's own
115
     * tag.
116
     * @return string
117
     * @throws ChildNotFoundException
118
     * @throws UnknownChildTypeException
119
     */
120 138
    public function outerHtml(): string
121
    {
122
        // special handling for root
123 138
        if ($this->tag->name() == 'root') {
124 3
            return $this->innerHtml();
125
        }
126
127 138
        if ( ! is_null($this->outerHtml)) {
0 ignored issues
show
introduced by
The condition is_null($this->outerHtml) is always false.
Loading history...
128
            // we already know the results.
129 6
            return $this->outerHtml;
130
        }
131
132 138
        $return = $this->tag->makeOpeningTag();
133 138
        if ($this->tag->isSelfClosing()) {
134
            // ignore any children... there should not be any though
135 84
            return $return;
136
        }
137
138
        // get the inner html
139 120
        $return .= $this->innerHtml();
140
141
        // add closing tag
142 120
        $return .= $this->tag->makeClosingTag();
143
144
        // remember the results
145 120
        $this->outerHtml = $return;
146
147 120
        return $return;
148
    }
149
150
    /**
151
     * Gets the text of this node (if there is any text). Or get all the text
152
     * in this node, including children.
153
     *
154
     * @param bool $lookInChildren
155
     * @return string
156
     */
157 48
    public function text(bool $lookInChildren = false): string
158
    {
159 48
        if ($lookInChildren) {
160 6
            if ( ! is_null($this->textWithChildren)) {
0 ignored issues
show
introduced by
The condition is_null($this->textWithChildren) is always false.
Loading history...
161
                // we already know the results.
162 6
                return $this->textWithChildren;
163
            }
164 45
        } elseif ( ! is_null($this->text)) {
0 ignored issues
show
introduced by
The condition is_null($this->text) is always false.
Loading history...
165
            // we already know the results.
166 3
            return $this->text;
167
        }
168
169
        // find out if this node has any text children
170 48
        $text = '';
171 48
        foreach ($this->children as $child) {
172
            /** @var AbstractNode $node */
173 45
            $node = $child['node'];
174 45
            if ($node instanceof TextNode) {
175 45
                $text .= $child['node']->text;
176 6
            } elseif ($lookInChildren &&
177 6
                $node instanceof HtmlNode
178
            ) {
179 32
                $text .= $node->text($lookInChildren);
180
            }
181
        }
182
183
        // remember our result
184 48
        if ($lookInChildren) {
185 6
            $this->textWithChildren = $text;
186
        } else {
187 45
            $this->text = $text;
188
        }
189
190 48
        return $text;
191
    }
192
193
    /**
194
     * Call this when something in the node tree has changed. Like a child has been added
195
     * or a parent has been changed.
196
     */
197 336
    protected function clear(): void
198
    {
199 336
        $this->innerHtml = null;
200 336
        $this->outerHtml = null;
201 336
        $this->text      = null;
202 336
        $this->textWithChildren = null;
203
204 336
        if (is_null($this->parent) === false) {
205 282
            $this->parent->clear();
0 ignored issues
show
Bug introduced by
The method clear() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

205
            $this->parent->/** @scrutinizer ignore-call */ 
206
                           clear();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
206
        }
207 336
    }
208
209
    /**
210
     * Returns all children of this html node.
211
     *
212
     * @return array
213
     */
214 6
    protected function getIteratorArray(): array
215
    {
216 6
        return $this->getChildren();
217
    }
218
}
219