DomVisitor::__construct()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
1
<?php
2
/**
3
 * (c) Steve Nebes <[email protected]>.
4
 *
5
 *  For the full copyright and license information, please view the LICENSE
6
 *  file that was distributed with this source code.
7
 */
8
9
declare(strict_types=1);
10
11
namespace SN\HtmlSanitizer;
12
13
use SN\HtmlSanitizer\Model\Cursor;
14
use SN\HtmlSanitizer\Node\DocumentNode;
15
use SN\HtmlSanitizer\Node\TextNode;
16
use SN\HtmlSanitizer\NodeVisitor\NodeVisitorInterface;
17
18
/**
19
 * The DomVisitor iterate over the parsed DOM tree and visit nodes using NodeVisitorInterface objects.
20
 * For performance reasons, these objects are split in 2 groups: generic ones and node-specific ones.
21
 */
22
class DomVisitor
23
{
24
    /**
25
     * @var NodeVisitorInterface[]
26
     */
27
    private $nodeVisitors = [];
28
29
    /**
30
     * @param NodeVisitorInterface[] $visitors
31
     */
32 5
    public function __construct(array $visitors = [])
33
    {
34 5
        foreach ($visitors as $visitor) {
35 5
            if ($visitor instanceof NodeVisitorInterface) {
36 5
                foreach ($visitor->getSupportedNodeNames() as $nodeName) {
37 5
                    $this->nodeVisitors[$nodeName][] = $visitor;
38
                }
39
            }
40
        }
41 5
    }
42
43
    /**
44
     * @param \DOMNode $node
45
     *
46
     * @return DocumentNode
47
     */
48 3
    public function visit(\DOMNode $node): DocumentNode
49
    {
50 3
        $cursor = new Cursor();
51 3
        $cursor->node = new DocumentNode();
52
53 3
        $this->visitNode($node, $cursor);
54
55 3
        return $cursor->node;
56
    }
57
58
    /**
59
     * @param \DOMNode $node
60
     * @param Cursor   $cursor
61
     */
62 3
    private function visitNode(\DOMNode $node, Cursor $cursor)
63
    {
64
        /** @var NodeVisitorInterface[] $supportedVisitors */
65 3
        $supportedVisitors = $this->nodeVisitors[$node->nodeName] ?? [];
66
67 3
        foreach ($supportedVisitors as $visitor) {
68 3
            if ($visitor->supports($node, $cursor)) {
69 3
                $visitor->enterNode($node, $cursor);
70
            }
71
        }
72
73
        /** @var \DOMNode $child */
74 3
        foreach ($node->childNodes ?? [] as $child) {
75 3
            if ('#text' === $child->nodeName) {
76
                // Add text in the safe tree without a visitor for performance
77 1
                $cursor->node->addChild(new TextNode($cursor->node, $child->nodeValue));
78 3
            } elseif (!$child instanceof \DOMText) {
79
                // Ignore comments for security reasons (interpreted differently by browsers)
80 3
                $this->visitNode($child, $cursor);
81
            }
82
        }
83
84 3
        foreach (\array_reverse($supportedVisitors) as $visitor) {
85 3
            if ($visitor->supports($node, $cursor)) {
86 3
                $visitor->leaveNode($node, $cursor);
87
            }
88
        }
89 3
    }
90
}
91