AttributeValue::fromXML()   B
last analyzed

Complexity

Conditions 11
Paths 7

Size

Total Lines 51
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 33
nc 7
nop 1
dl 0
loc 51
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    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
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\saml;
6
7
use DateTimeImmutable;
8
use DateTimeInterface;
9
use DOMElement;
10
use SimpleSAML\SAML2\Assert\Assert;
11
use SimpleSAML\SAML2\Constants as C;
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\Constants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use SimpleSAML\XML\AbstractElement;
13
use SimpleSAML\XML\Chunk;
14
use SimpleSAML\XML\SchemaValidatableElementInterface;
15
use SimpleSAML\XML\SchemaValidatableElementTrait;
16
use SimpleSAML\XMLSchema\Constants as C_XSI;
0 ignored issues
show
Bug introduced by
The type SimpleSAML\XMLSchema\Constants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException;
18
19
use function class_exists;
20
use function explode;
21
use function gettype;
22
use function intval;
23
use function str_contains;
24
25
/**
26
 * Serializable class representing an AttributeValue.
27
 *
28
 * @package simplesamlphp/saml2
29
 */
30
class AttributeValue extends AbstractSamlElement implements SchemaValidatableElementInterface
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML2\XML\saml\AbstractSamlElement was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
{
32
    use SchemaValidatableElementTrait;
33
34
35
    /**
36
     * Create an AttributeValue.
37
     *
38
     * @param string|int|null|\DateTimeInterface|\SimpleSAML\XML\AbstractElement $value
39
     * @throws \SimpleSAML\Assert\AssertionFailedException if the supplied value is neither a string or a DOMElement
40
     */
41
    final public function __construct(
42
        protected string|int|null|DateTimeInterface|AbstractElement $value,
43
    ) {
44
    }
45
46
47
    /**
48
     * Get the XSI type of this attribute value.
49
     */
50
    public function getXsiType(): string
51
    {
52
        $value = $this->getValue();
53
        $type = gettype($value);
54
55
        switch ($type) {
56
            case "integer":
57
                return "xs:integer";
58
            case "NULL":
59
                return "xs:nil";
60
            case "object":
61
                if ($value instanceof DateTimeInterface) {
62
                    return 'xs:dateTime';
63
                }
64
65
                return sprintf(
66
                    '%s:%s',
67
                    $value::getNamespacePrefix(),
68
                    AbstractElement::getClassName(get_class($value)),
69
                );
70
            default:
71
                return "xs:string";
72
        }
73
    }
74
75
76
    /**
77
     * Get this attribute value.
78
     *
79
     * @return string|int|\SimpleSAML\XML\AbstractElement|null
80
     */
81
    public function getValue()
82
    {
83
        return $this->value;
84
    }
85
86
87
    /**
88
     * Convert XML into a AttributeValue
89
     *
90
     * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException
91
     *   if the qualified name of the supplied element is wrong
92
     */
93
    public static function fromXML(DOMElement $xml): static
94
    {
95
        Assert::same($xml->localName, 'AttributeValue', InvalidDOMElementException::class);
96
        Assert::same($xml->namespaceURI, AttributeValue::NS, InvalidDOMElementException::class);
97
98
        if ($xml->childElementCount > 0) {
99
            $node = $xml->firstElementChild;
100
101
            if (str_contains($node->tagName, ':')) {
102
                list($prefix, $eltName) = explode(':', $node->tagName);
103
                $className = sprintf('\SimpleSAML\SAML2\XML\%s\%s', $prefix, $eltName);
104
105
                if (class_exists($className)) {
106
                    $value = $className::fromXML($node);
107
                } else {
108
                    $value = Chunk::fromXML($node);
0 ignored issues
show
Bug introduced by
It seems like $node can also be of type null; however, parameter $xml of SimpleSAML\XML\Chunk::fromXML() does only seem to accept DOMElement, 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

108
                    $value = Chunk::fromXML(/** @scrutinizer ignore-type */ $node);
Loading history...
109
                }
110
            } else {
111
                $value = Chunk::fromXML($node);
112
            }
113
        } elseif (
114
            $xml->hasAttributeNS(C_XSI::NS_XSI, "type") &&
115
            $xml->getAttributeNS(C_XSI::NS_XSI, "type") === "xs:integer"
116
        ) {
117
            Assert::numeric($xml->textContent);
118
119
            // we have an integer as value
120
            $value = intval($xml->textContent);
121
        } elseif (
122
            $xml->hasAttributeNS(C_XSI::NS_XSI, "type") &&
123
            $xml->getAttributeNS(C_XSI::NS_XSI, "type") === "xs:dateTime"
124
        ) {
125
            Assert::validDateTime($xml->textContent);
126
127
            // we have a dateTime as value
128
            $value = new DateTimeImmutable($xml->textContent);
129
        } elseif (
130
            // null value
131
            $xml->hasAttributeNS(C_XSI::NS_XSI, "nil") &&
132
            ($xml->getAttributeNS(C_XSI::NS_XSI, "nil") === "1" ||
133
                $xml->getAttributeNS(C_XSI::NS_XSI, "nil") === "true")
134
        ) {
135
            Assert::isEmpty($xml->nodeValue);
136
            Assert::isEmpty($xml->textContent);
137
138
            $value = null;
139
        } else {
140
            $value = $xml->textContent;
141
        }
142
143
        return new static($value);
144
    }
145
146
147
    /**
148
     * Append this attribute value to an element.
149
     */
150
    public function toXML(?DOMElement $parent = null): DOMElement
151
    {
152
        $e = parent::instantiateParentElement($parent);
153
154
        $value = $this->getValue();
155
        $type = gettype($value);
156
157
        switch ($type) {
158
            case "integer":
159
                // make sure that the xs namespace is available in the AttributeValue
160
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C_XSI::NS_XSI);
161
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C_XSI::NS_XS);
162
                $e->setAttributeNS(C_XSI::NS_XSI, 'xsi:type', 'xs:integer');
163
                $e->textContent = strval($value);
164
                break;
165
            case "NULL":
166
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C_XSI::NS_XSI);
167
                $e->setAttributeNS(C_XSI::NS_XSI, 'xsi:nil', '1');
168
                break;
169
            case "object":
170
                if ($value instanceof DateTimeInterface) {
171
                    $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C_XSI::NS_XSI);
172
                    $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C_XSI::NS_XS);
173
                    $e->setAttributeNS(C_XSI::NS_XSI, 'xsi:type', 'xs:dateTime');
174
                    $e->textContent = $value->format(C::DATETIME_FORMAT);
175
                } else {
176
                    $value->toXML($e);
177
                }
178
                break;
179
            default: // string
180
                $e->textContent = $value;
181
                break;
182
        }
183
184
        return $e;
185
    }
186
}
187