XmlContent::fromValue()   C
last analyzed

Complexity

Conditions 15
Paths 20

Size

Total Lines 47
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 38
nc 20
nop 1
dl 0
loc 47
rs 5.9166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
namespace Ivory\Value;
4
5
/**
6
 * Encapsulation of some XML content, not necessarily an XML document.
7
 *
8
 * The objects are immutable.
9
 */
10
class XmlContent
11
{
12
    private $xmlStr;
13
14
    /**
15
     * Creates a new XML content value. If the value forms a document, it creates an {@link XmlDocument} object.
16
     *
17
     * If an object of an unrecognized class is given, its string serialization is used as the XML string.
18
     *
19
     * @param string|XmlContent|\DOMDocument|\DOMNode|\DOMNodeList|\SimpleXMLElement|object $value
20
     * @return XmlContent
21
     */
22
    public static function fromValue($value): XmlContent
23
    {
24
        if (is_string($value)) {
25
            $xmlStr = $value;
26
            $isDoc = self::isXmlDocument($value);
27
        } elseif ($value instanceof XmlContent) {
28
            return $value;
29
        } elseif ($value instanceof \DOMDocument) {
30
            $xmlStr = $value->saveXML();
31
            if ($xmlStr === false) {
32
                throw new \InvalidArgumentException('value');
33
            }
34
            $isDoc = true;
35
        } elseif ($value instanceof \DOMNode) {
36
            $d = $value->ownerDocument->saveXML($value);
0 ignored issues
show
Bug introduced by
The method saveXML() does not exist on null. ( Ignorable by Annotation )

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

36
            /** @scrutinizer ignore-call */ 
37
            $d = $value->ownerDocument->saveXML($value);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
37
            if ($d === false) {
38
                throw new \InvalidArgumentException('value');
39
            }
40
            $xmlStr = self::getXMLDeclaration($value->ownerDocument) . $d;
0 ignored issues
show
Bug introduced by
It seems like $value->ownerDocument can also be of type null; however, parameter $doc of Ivory\Value\XmlContent::getXMLDeclaration() 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

40
            $xmlStr = self::getXMLDeclaration(/** @scrutinizer ignore-type */ $value->ownerDocument) . $d;
Loading history...
41
            $isDoc = true;
42
        } elseif ($value instanceof \DOMNodeList) {
43
            $xmlStr = ($value->length > 0 ? self::getXMLDeclaration($value->item(0)->ownerDocument) : '');
44
            foreach ($value as $i => $node) {
45
                $n = $node->ownerDocument->saveXML($node);
46
                if ($n === false) {
47
                    throw new \InvalidArgumentException("value, node $i");
48
                }
49
                $xmlStr .= $n;
50
            }
51
            $isDoc = ($value->length == 1);
52
        } elseif ($value instanceof \SimpleXMLElement) {
53
            $xmlStr = $value->saveXML();
54
            if ($xmlStr === false) {
55
                throw new \InvalidArgumentException('value');
56
            }
57
            $isDoc = true;
58
        } elseif (is_object($value)) {
59
            $xmlStr = (string)$value;
60
            $isDoc = self::isXmlDocument($xmlStr);
61
        } else {
62
            throw new \InvalidArgumentException('value');
63
        }
64
65
        if ($isDoc) {
66
            return new XmlDocument($xmlStr);
0 ignored issues
show
Bug introduced by
It seems like $xmlStr can also be of type true; however, parameter $xmlStr of Ivory\Value\XmlDocument::__construct() does only seem to accept string, 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

66
            return new XmlDocument(/** @scrutinizer ignore-type */ $xmlStr);
Loading history...
67
        } else {
68
            return new XmlContent($xmlStr);
0 ignored issues
show
Bug introduced by
It seems like $xmlStr can also be of type true; however, parameter $xmlStr of Ivory\Value\XmlContent::__construct() does only seem to accept string, 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

68
            return new XmlContent(/** @scrutinizer ignore-type */ $xmlStr);
Loading history...
69
        }
70
    }
71
72
    private static function isXmlDocument(string $xmlStr): bool
73
    {
74
        $reader = new \XMLReader();
75
        /** @noinspection PhpStaticAsDynamicMethodCallInspection it is also a non-static method */
76
        $reader->XML($xmlStr);
77
78
        if (!@$reader->read()) {
79
            return false;
80
        }
81
82
        do {
83
            $read = @$reader->read();
84
        } while ($read);
85
86
        return ($reader->depth == 0);
87
    }
88
89
    private static function getXMLDeclaration(\DOMDocument $doc): string
90
    {
91
        $out = '<?xml version="' . $doc->xmlVersion . '"';
92
        if (strlen($doc->xmlEncoding) > 0) {
93
            $out .= ' encoding="' . $doc->xmlEncoding . '"';
94
        }
95
        if ($doc->xmlStandalone) {
96
            $out .= ' standalone="yes"';
97
        }
98
        $out .= '?>';
99
100
        return $out;
101
    }
102
103
    /**
104
     * @param string $xmlStr
105
     */
106
    private function __construct(string $xmlStr)
107
    {
108
        $this->xmlStr = $xmlStr;
109
    }
110
111
    /**
112
     * @return string the XML value as a string
113
     */
114
    public function toString(): string
115
    {
116
        return $this->xmlStr;
117
    }
118
}
119