Passed
Push — develop ( 477204...0132d1 )
by Mikaël
07:12
created

AbstractDomDocumentHandler::getElementsHandlers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4.0119

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 18
ccs 10
cts 11
cp 0.9091
rs 9.9332
cc 4
nc 4
nop 1
crap 4.0119
1
<?php
2
3
namespace WsdlToPhp\DomHandler;
4
5
use DOMAttr;
6
use DOMDocument;
7
use DOMElement;
8
use DOMNameSpaceNode;
9
use DOMNode;
10
use DOMNodeList;
11
use DOMXPath;
12
use InvalidArgumentException;
13
14
abstract class AbstractDomDocumentHandler
15
{
16
    protected DOMDocument $domDocument;
17
18
    protected ?ElementHandler $rootElement;
19
20 10
    public function __construct(DOMDocument $domDocument)
21
    {
22 10
        $this->domDocument = $domDocument;
23 10
        $this->initRootElement();
24
    }
25
26
    /**
27
     * @param DOMAttr|DOMElement|DOMNode $node
28
     */
29 80
    public function getHandler($node, int $index = -1): AbstractNodeHandler
30
    {
31 80
        if ($node instanceof DOMElement) {
32 62
            return $this->getElementHandler($node, $this, $index);
33
        }
34 60
        if ($node instanceof DOMAttr) {
35 46
            return $this->getAttributeHandler($node, $this, $index);
36
        }
37 14
        if ($node instanceof DOMNameSpaceNode) {
0 ignored issues
show
introduced by
$node is never a sub-type of DOMNameSpaceNode.
Loading history...
38 6
            return new NameSpaceHandler($node, $this, $index);
39
        }
40
41 8
        return $this->getNodeHandler($node, $this, $index);
42
    }
43
44 42
    public function getNodeByName(string $name): ?NodeHandler
45
    {
46 42
        return $this->domDocument->getElementsByTagName($name)->length > 0 ? $this->getNodeHandler($this->domDocument->getElementsByTagName($name)->item(0), $this) : null;
47
    }
48
49 26
    public function getElementByName(string $name): ?ElementHandler
50
    {
51 26
        $node = $this->getNodeByName($name);
52 26
        if ($node instanceof AbstractNodeHandler && $node->getNode() instanceof DOMElement) {
53 24
            return $this->getElementHandler($node->getNode(), $this);
54
        }
55
56 2
        return null;
57
    }
58
59
    /**
60
     * @return AbstractAttributeHandler[]|AbstractElementHandler[]|AbstractNodeHandler[]
61
     */
62 50
    public function getNodesByName(string $name, ?string $checkInstance = null): array
63
    {
64 50
        $nodes = [];
65 50
        if ($this->domDocument->getElementsByTagName($name)->length > 0) {
66 50
            foreach ($this->domDocument->getElementsByTagName($name) as $node) {
67 50
                if (is_null($checkInstance) || $node instanceof $checkInstance) {
68 50
                    $nodes[] = $this->getHandler($node, count($nodes));
69
                }
70
            }
71
        }
72
73 50
        return $nodes;
74
    }
75
76
    /**
77
     * @return AbstractAttributeHandler[]|AbstractElementHandler[]|AbstractNodeHandler[]
78
     */
79 48
    public function getElementsByName(string $name): array
80
    {
81 48
        return $this->getNodesByName($name, DOMElement::class);
82
    }
83
84
    /**
85
     * @param string[] $attributes
86
     *
87
     * @return AbstractAttributeHandler[]|AbstractElementHandler[]|AbstractNodeHandler[]
88
     */
89 46
    public function getElementsByNameAndAttributes(string $name, array $attributes, ?DOMNode $node = null): array
90
    {
91 46
        $matchingElements = $this->getElementsByName($name);
92 46
        if ((!empty($attributes) || $node instanceof DOMNode) && !empty($matchingElements)) {
93 46
            $nodes = $this->searchTagsByXpath($name, $attributes, $node);
94
95 46
            if ($nodes && 0 < $nodes->count()) {
96 46
                $matchingElements = $this->getElementsHandlers($nodes);
97
            }
98
        }
99
100 46
        return $matchingElements;
101
    }
102
103
    /**
104
     * @param DOMNodeList<DOMAttr|DOMElement|DOMNode> $nodeList
105
     *
106
     * @return AbstractElementHandler[]
107
     */
108 48
    public function getElementsHandlers(DOMNodeList $nodeList): array
109
    {
110 48
        $nodes = [];
111 48
        if (0 === $nodeList->count()) {
112
            return $nodes;
113
        }
114
115 48
        $index = 0;
116 48
        foreach ($nodeList as $node) {
117 48
            if (!$node instanceof DOMElement) {
118 2
                continue;
119
            }
120
121 48
            $nodes[] = $this->getElementHandler($node, $this, $index);
122 48
            ++$index;
123
        }
124
125 48
        return $nodes;
126
    }
127
128
    /**
129
     * @param string[] $attributes
130
     *
131
     * @return DOMNodeList<DOMAttr|DOMElement|DOMNode>|false
132
     */
133 46
    public function searchTagsByXpath(string $name, array $attributes, ?DOMNode $node = null)
134
    {
135 46
        $xpath = new DOMXPath($node ? $node->ownerDocument : $this->domDocument);
0 ignored issues
show
Bug introduced by
It seems like $node ? $node->ownerDocument : $this->domDocument can also be of type null; however, parameter $document of DOMXPath::__construct() does only seem to accept DOMDocument, maybe add an additional type check? ( Ignorable by Annotation )

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

135
        $xpath = new DOMXPath(/** @scrutinizer ignore-type */ $node ? $node->ownerDocument : $this->domDocument);
Loading history...
136 46
        $xQuery = sprintf("%s//*[local-name()='%s']", $node instanceof DOMNode ? '.' : '', $name);
137 46
        foreach ($attributes as $attributeName => $attributeValue) {
138 46
            if (false !== strpos($attributeValue, '*')) {
139 2
                $xQuery .= sprintf("[contains(@%s, '%s')]", $attributeName, str_replace('*', '', $attributeValue));
140
            } else {
141 46
                $xQuery .= sprintf("[@%s='%s']", $attributeName, $attributeValue);
142
            }
143
        }
144
145 46
        return $xpath->query($xQuery, $node);
146
    }
147
148
    /**
149
     * @param string[] $attributes
150
     */
151 42
    public function getElementByNameAndAttributes(string $name, array $attributes): ?ElementHandler
152
    {
153 42
        $elements = $this->getElementsByNameAndAttributes($name, $attributes);
154
155 42
        return array_shift($elements);
156
    }
157
158
    /**
159
     * Find valid root node (not a comment, at least a DOMElement node).
160
     *
161
     * @throws InvalidArgumentException
162
     */
163 10
    protected function initRootElement(): void
164
    {
165 10
        if ($this->domDocument->hasChildNodes()) {
166 8
            foreach ($this->domDocument->childNodes as $node) {
167 8
                if ($node instanceof DOMElement) {
168 8
                    $this->rootElement = $this->getElementHandler($node, $this);
169
170 8
                    break;
171
                }
172
            }
173
        } else {
174 2
            throw new InvalidArgumentException('Document seems to be invalid', __LINE__);
175
        }
176
    }
177
178
    abstract protected function getNodeHandler(DOMNode $node, AbstractDomDocumentHandler $domDocument, int $index = -1): NodeHandler;
179
180
    abstract protected function getElementHandler(DOMElement $element, AbstractDomDocumentHandler $domDocument, int $index = -1): ElementHandler;
181
182
    abstract protected function getAttributeHandler(DOMAttr $attribute, AbstractDomDocumentHandler $domDocument, int $index = -1): AttributeHandler;
183
}
184