DomHelper::removeNodes()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Paysera\PhpStormHelper\Service;
6
7
use DOMDocument;
8
use DOMElement;
9
use DOMNode;
10
use RuntimeException;
11
12
class DomHelper
13
{
14 24 View Code Duplication
    public function loadDocument(string $pathToXml): DOMDocument
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
15
    {
16 24
        if (!file_exists($pathToXml)) {
17
            throw new RuntimeException(sprintf('File %s does not exist', $pathToXml));
18
        }
19
20 24
        $document = $this->createEmptyDomDocument();
21 24
        $this->loadXmlContents($document, $pathToXml);
22 24
        return $document;
23
    }
24
25 6 View Code Duplication
    public function loadOrCreateDocument(string $pathToXml): DOMDocument
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

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