Completed
Push — master ( 317dcf...a9b2d8 )
by Marius
02:57
created

DomHelper::loadDocument()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 10
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2.0185
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 17 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...
14
    {
15 17
        if (!file_exists($pathToXml)) {
16
            throw new RuntimeException(sprintf('File %s does not exist', $pathToXml));
17
        }
18
19 17
        $document = $this->createEmptyDomDocument();
20 17
        $this->loadXmlContents($document, $pathToXml);
21 17
        return $document;
22
    }
23
24 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...
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 23
    private function createEmptyDomDocument(): DOMDocument
38
    {
39 23
        $document = new DOMDocument();
40 23
        $document->preserveWhiteSpace = true;
41 23
        $document->formatOutput = true;
42 23
        return $document;
43
    }
44
45 20
    private function loadXmlContents(DOMDocument $document, string $pathToXml)
46
    {
47 20
        libxml_clear_errors();
48 20
        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 20
    }
54
55 23
    public function saveDocument(string $path, DOMDocument $document)
56
    {
57 23
        file_put_contents($path, $document->saveXML());
58 23
    }
59
60 17
    public function findNode(DOMNode $node, string $tagName, array $attributes = null): DOMNode
61
    {
62 17
        $node = $this->findOptionalNode($node, $tagName, $attributes);
63 17
        if ($node === null) {
64
            throw new RuntimeException(sprintf('Node <%s> not found', $tagName));
65
        }
66
67 17
        return $node;
68
    }
69
70 23
    public function findOptionalNode(DOMNode $node, string $tagName, array $attributes = null)
71
    {
72 23
        $nodes = $this->findNodes($node, $tagName, $attributes);
73 23
        if (count($nodes) > 1) {
74
            throw new RuntimeException(sprintf('Expected only single <%s> tag', $tagName));
75 23
        } elseif (count($nodes) === 0) {
76 17
            return null;
77
        }
78
79 20
        return $nodes[0];
80
    }
81
82 23
    public function findOrCreateChildNode(DOMNode $node, string $tagName, array $attributes = null): DOMElement
83
    {
84 23
        $internalNode = $this->findOptionalNode($node, $tagName, $attributes);
85 23
        if ($internalNode === null) {
86 17
            $ownerDocument = $node instanceof DOMDocument ? $node : $node->ownerDocument;
87 17
            $internalNode = $ownerDocument->createElement($tagName);
88 17
            $this->applyAttributesToElement($internalNode, $attributes ?? []);
89 17
            $node->appendChild($internalNode);
90
        }
91 23
        return $internalNode;
92
    }
93
94 19
    public function applyAttributesToElement(DOMElement $node, array $attributes)
95
    {
96 19
        foreach ($attributes as $name => $value) {
97 9
            $node->setAttribute($name, $value);
98
        }
99 19
    }
100
101
    /**
102
     * @param DOMNode $node
103
     * @param string $tagName
104
     * @param array|null $attributes
105
     * @return array|DomNode[]
106
     */
107 23
    public function findNodes(DOMNode $node, string $tagName, array $attributes = null): array
108
    {
109 23
        $result = [];
110
111
        /** @var DOMNode $childNode */
112 23
        foreach ($node->childNodes as $childNode) {
113 22
            if ($childNode->nodeName === $tagName && $this->matchesAttributes($childNode, $attributes)) {
114 22
                $result[] = $childNode;
115
            }
116
        }
117
118 23
        return $result;
119
    }
120
121 22
    private function matchesAttributes(DOMNode $childNode, array $attributes = null): bool
122
    {
123 22
        if ($attributes === null) {
124 19
            return true;
125
        }
126
127 22
        foreach ($attributes as $key => $value) {
128 22
            $attributeNode = $childNode->attributes->getNamedItem($key);
129 22
            $attributeValue = $attributeNode !== null ? $attributeNode->nodeValue : null;
130 22
            if ($attributeValue !== $value) {
131 22
                return false;
132
            }
133
        }
134
135 17
        return true;
136
    }
137
}
138