Completed
Push — master ( a9b2d8...9165ca )
by Marius
03:47
created

DomHelper::matchesAttributes()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 9
cts 9
cp 1
rs 9.4222
c 0
b 0
f 0
cc 5
nc 6
nop 2
crap 5
1
<?php
2
declare(strict_types=1);
3
4
namespace Paysera\PhpStormHelper\Service;
5
6
use DOMDocument;
7
use DOMElement;
8
use DOMNode;
9
use RuntimeException;
10
11
class DomHelper
12
{
13 18
    public function loadDocument(string $pathToXml): DOMDocument
14
    {
15 18
        if (!file_exists($pathToXml)) {
16
            throw new RuntimeException(sprintf('File %s does not exist', $pathToXml));
17
        }
18
19 18
        $document = $this->createEmptyDomDocument();
20 18
        $this->loadXmlContents($document, $pathToXml);
21 18
        return $document;
22
    }
23
24 6
    public function loadOrCreateDocument(string $pathToXml): DOMDocument
25
    {
26 6
        $document = $this->createEmptyDomDocument();
27
28 6
        if (!file_exists($pathToXml)) {
29 3
            return $document;
30
        }
31
32 3
        $this->loadXmlContents($document, $pathToXml);
33
34 3
        return $document;
35
    }
36
37 24
    private function createEmptyDomDocument(): DOMDocument
38
    {
39 24
        $document = new DOMDocument();
40 24
        $document->preserveWhiteSpace = true;
41 24
        $document->formatOutput = true;
42 24
        return $document;
43
    }
44
45 21
    private function loadXmlContents(DOMDocument $document, string $pathToXml)
46
    {
47 21
        libxml_clear_errors();
48 21
        if (!$document->loadXML(file_get_contents($pathToXml))) {
49
            $error = libxml_get_last_error();
50
            $message = $error === false ? 'Cannot load XML file' : $error->message;
51
            throw new RuntimeException($message);
52
        }
53 21
    }
54
55 24
    public function saveDocument(string $path, DOMDocument $document)
56
    {
57 24
        file_put_contents($path, $document->saveXML());
58 24
    }
59
60 18
    public function findNode(DOMNode $node, string $tagName, array $attributes = null): DOMNode
61
    {
62 18
        $node = $this->findOptionalNode($node, $tagName, $attributes);
63 18
        if ($node === null) {
64
            throw new RuntimeException(sprintf('Node <%s> not found', $tagName));
65
        }
66
67 18
        return $node;
68
    }
69
70 24
    public function findOptionalNode(DOMNode $node, string $tagName, array $attributes = null)
71
    {
72 24
        $nodes = $this->findNodes($node, $tagName, $attributes);
73 24
        if (count($nodes) > 1) {
74
            throw new RuntimeException(sprintf('Expected only single <%s> tag', $tagName));
75 24
        } elseif (count($nodes) === 0) {
76 20
            return null;
77
        }
78
79 21
        return $nodes[0];
80
    }
81
82 24
    public function findOrCreateChildNode(DOMNode $node, string $tagName, array $attributes = null): DOMElement
83
    {
84 24
        $internalNode = $this->findOptionalNode($node, $tagName, $attributes);
85 24
        if ($internalNode === null) {
86 20
            $ownerDocument = $node instanceof DOMDocument ? $node : $node->ownerDocument;
87 20
            $internalNode = $ownerDocument->createElement($tagName);
88 20
            $this->applyAttributesToElement($internalNode, $attributes ?? []);
89 20
            $node->appendChild($internalNode);
90
        }
91 24
        return $internalNode;
92
    }
93
94 22
    public function applyAttributesToElement(DOMElement $node, array $attributes)
95
    {
96 22
        foreach ($attributes as $name => $value) {
97 9
            $node->setAttribute($name, $value);
98
        }
99 22
    }
100
101
    /**
102
     * @param DOMNode $node
103
     * @param string $tagName
104
     * @param array|null $attributes
105
     * @return array|DomNode[]
106
     */
107 24
    public function findNodes(DOMNode $node, string $tagName, array $attributes = null): array
108
    {
109 24
        $result = [];
110
111
        /** @var DOMNode $childNode */
112 24
        foreach ($node->childNodes as $childNode) {
113 23
            if ($childNode->nodeName === $tagName && $this->matchesAttributes($childNode, $attributes)) {
114 23
                $result[] = $childNode;
115
            }
116
        }
117
118 24
        return $result;
119
    }
120
121 23
    private function matchesAttributes(DOMNode $childNode, array $attributes = null): bool
122
    {
123 23
        if ($attributes === null) {
124 20
            return true;
125
        }
126
127 23
        foreach ($attributes as $key => $value) {
128 23
            $attributeNode = $childNode->attributes->getNamedItem($key);
129 23
            $attributeValue = $attributeNode !== null ? $attributeNode->nodeValue : null;
130 23
            if ($attributeValue !== $value) {
131 23
                return false;
132
            }
133
        }
134
135 18
        return true;
136
    }
137
138 11
    public function removeNodes(DOMElement $parentNode, string $tagName, array $attributes = null)
139
    {
140 11
        $mappings = $this->findNodes($parentNode, $tagName, $attributes);
141 11
        foreach ($mappings as $mapping) {
142 3
            $parentNode->removeChild($mapping);
143
        }
144 11
    }
145
}
146