Completed
Push — master ( 74e0f6...d04c0f )
by Carlos C
03:37 queued 11s
created

Xml::createDOMElement()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 6
nop 3
dl 0
loc 17
ccs 11
cts 11
cp 1
crap 4
rs 9.9
c 0
b 0
f 0
1
<?php
2
namespace CfdiUtils\Utils;
3
4
use DOMDocument;
5
use DOMElement;
6
use DOMNode;
7
8
class Xml
9
{
10 105
    public static function documentElement(DOMDocument $document): DOMElement
11
    {
12 105
        if (! $document->documentElement instanceof DOMElement) {
0 ignored issues
show
introduced by
$document->documentElement is always a sub-type of DOMElement.
Loading history...
13 2
            throw new \UnexpectedValueException('DOM Document does not have root element');
14
        }
15 103
        return $document->documentElement;
16
    }
17
18 19
    public static function ownerDocument(DOMNode $node): DOMDocument
19
    {
20
        // $node->ownerDocument is NULL if node is a DOMDocument
21 19
        if (null === $node->ownerDocument) {
22
            if ($node instanceof DOMDocument) {
23
                return $node;
24
            }
25
            /** @codeCoverageIgnore */
26
            throw new \LogicException('node->ownerDocument is null but node is not a DOMDocument');
27
        }
28 19
        return $node->ownerDocument;
29
    }
30
31
    /**
32
     * Creates a DOMDocument object version 1.0 encoding UTF-8
33
     * with output formatting and not preserving white spaces
34
     *
35
     * @return DOMDocument
36
     */
37 126
    public static function newDocument(): DOMDocument
38
    {
39 126
        $document = new DOMDocument('1.0', 'UTF-8');
40 126
        $document->formatOutput = true;
41 126
        $document->preserveWhiteSpace = false;
42 126
        return $document;
43
    }
44
45 98
    public static function newDocumentContent(string $content): DOMDocument
46
    {
47 98
        if ('' === $content) {
48 2
            throw new \UnexpectedValueException('Received xml string argument is empty');
49
        }
50 96
        $document = static::newDocument();
51
        // this error silenced call is intentional, no need to alter libxml_use_internal_errors
52 96
        if (false === @$document->loadXML($content)) {
53 2
            throw new \UnexpectedValueException('Cannot create a DOM Document from xml string');
54
        }
55 94
        return $document;
56
    }
57
58 848
    public static function isValidXmlName(string $name): bool
59
    {
60 848
        if ('' === $name) {
61 3
            return false;
62
        }
63
        $pattern = '/^[:_A-Za-z'
64
            . '\xC0-\xD6\xD8-\xF6\xF8-\x{2FF}\x{370}-\x{37D}\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}'
65
            . '\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}]{1}'
66
            . '[\-:_A-Za-z0-9'
67
            . '\xC0-\xD6\xD8-\xF6\xF8-\x{2FF}\x{370}-\x{37D}\x{37F}-\x{1FFF}\x{200C}-\x{200D}\x{2070}-\x{218F}'
68
            . '\x{2C00}-\x{2FEF}\x{3001}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFFD}\x{10000}-\x{EFFFF}'
69 845
            . '\xB7\x{0300}-\x{036F}\x{203F}-\x{2040}]*$/u';
70 845
        return (1 === preg_match($pattern, $name));
71
    }
72
73
    /**
74
     * This is an alias of DOMDocument::createElement that will replace ampersand '&' with '&amp;'
75
     * @see https://www.php.net/manual/en/domdocument.createelement.php
76
     *
77
     * @param DOMDocument $document
78
     * @param string $name
79
     * @param string $content
80
     * @return DOMElement
81
     */
82 10
    public static function createElement(DOMDocument $document, string $name, string $content = ''): DOMElement
83
    {
84 10
        return static::createDOMElement(
85
            function () use ($document, $name) {
86 10
                return $document->createElement($name);
87 10
            },
88 10
            sprintf('Cannot create element with name %s', $name),
89
            $content
90
        );
91
    }
92
93
    /**
94
     * This is an alias of DOMDocument::createElementNS that will replace ampersand '&' with '&amp;'
95
     * @see https://www.php.net/manual/en/domdocument.createelementns.php
96
     *
97
     * @param DOMDocument $document
98
     * @param string $namespaceURI
99
     * @param string $name
100
     * @param string $content
101
     * @return DOMElement
102
     */
103 11
    public static function createElementNS(
104
        DOMDocument $document,
105
        string $namespaceURI,
106
        string $name,
107
        string $content = ''
108
    ): DOMElement {
109 11
        return static::createDOMElement(
110
            function () use ($document, $namespaceURI, $name) {
111 11
                return $document->createElementNS($namespaceURI, $name);
112 11
            },
113 11
            sprintf('Cannot create element with name %s namespace %s', $name, $namespaceURI),
114
            $content
115
        );
116
    }
117
118 21
    private static function createDOMElement(\Closure $fnCreate, string $errorMessage, string $content): DOMElement
119
    {
120
        /** @var DOMElement|null $element */
121 21
        $element = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $element is dead and can be removed.
Loading history...
122 21
        $previousException = null;
123
        try {
124 21
            $element = $fnCreate();
125 3
        } catch (\Throwable $creationException) {
126 3
            $previousException = $creationException;
127
        }
128 21
        if (! $element instanceof DOMElement) {
129 3
            throw new \LogicException($errorMessage, 0, $previousException);
130
        }
131 18
        if ('' !== $content) {
132 16
            $element->appendChild(static::ownerDocument($element)->createTextNode($content));
133
        }
134 18
        return $element;
135
    }
136
}
137