Passed
Pull Request — master (#6)
by Tim
02:06
created

AttributeValue   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 22
eloc 69
c 1
b 0
f 0
dl 0
loc 156
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getXsiType() 0 13 3
B toXML() 0 38 6
B fromXML() 0 43 11
A getValue() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML11\XML\saml;
6
7
use DOMElement;
8
use SimpleSAML\SAML11\Assert\Assert;
9
use SimpleSAML\SAML11\Constants as C;
10
use SimpleSAML\SAML11\Type\{DateTimeValue, StringValue};
11
use SimpleSAML\XML\AbstractElement;
12
use SimpleSAML\XML\Chunk;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\{SchemaValidatableElementInterface, SchemaValidatableElementTrait};
15
use SimpleSAML\XML\Type\{IntegerValue, ValueTypeInterface};
16
17
use function class_exists;
18
use function explode;
19
use function gettype;
20
use function str_contains;
21
use function strval;
22
23
/**
24
 * Serializable class representing an AttributeValue.
25
 *
26
 * @package simplesamlphp/saml11
27
 */
28
class AttributeValue extends AbstractSamlElement implements SchemaValidatableElementInterface
29
{
30
    use SchemaValidatableElementTrait;
31
32
    /**
33
     * Create an AttributeValue.
34
     *
35
     * @param \SimpleSAML\XML\Type\ValueTypeInterface|\SimpleSAML\XML\AbstractElement $value
36
     * @throws \SimpleSAML\Assert\AssertionFailedException if the supplied value is neither a string or a DOMElement
37
     */
38
    final public function __construct(
39
        protected StringValue|IntegerValue|DateTimeValue|AbstractElement $value,
40
    ) {
41
    }
42
43
44
    /**
45
     * Get the XSI type of this attribute value.
46
     *
47
     * @return string
48
     */
49
    public function getXsiType(): string
50
    {
51
        $value = $this->getValue();
52
53
        if ($value === null) {
54
            return 'xs:nil';
55
        } elseif ($value instanceof ValueTypeInterface) {
56
            return $value::SCHEMA_TYPE;
57
        } else {
58
            return sprintf(
59
                '%s:%s',
60
                $value::getNamespacePrefix(),
61
                $value::getLocalName(),
62
            );
63
        }
64
    }
65
66
67
    /**
68
     * Get this attribute value.
69
     *
70
     * @return (
1 ignored issue
show
Documentation Bug introduced by
The doc comment ( at position 1 could not be parsed: the token is null at position 1.
Loading history...
71
     *   \SimpleSAML\XML\Type\IntegerValue|
72
     *   \SimpleSAML\SAML11\Type\StringValue|
73
     *   \SimpleSAML\SAML11\Type\DateTimeValue|
74
     *   \SimpleSAML\XML\AbstractElement|
75
     *   null
76
     * )
77
     */
78
    public function getValue()
79
    {
80
        return $this->value;
81
    }
82
83
84
    /**
85
     * Convert XML into a AttributeValue
86
     *
87
     * @param \DOMElement $xml The XML element we should load
88
     * @return static
89
     *
90
     * @throws \SimpleSAML\XML\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, static::getLocalName(), InvalidDOMElementException::class);
96
        Assert::same($xml->namespaceURI, static::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\SAML11\XML\%s\%s', $prefix, $eltName);
104
105
                if (class_exists($className)) {
106
                    $value = $className::fromXML($node);
107
                } else {
108
                    $value = Chunk::fromXML($node);
109
                }
110
            } else {
111
                $value = Chunk::fromXML($node);
112
            }
113
        } elseif (
114
            $xml->hasAttributeNS(C::NS_XSI, "type") &&
115
            $xml->getAttributeNS(C::NS_XSI, "type") === "xs:integer"
116
        ) {
117
            // we have an integer as value
118
            $value = IntegerValue::fromString($xml->textContent);
119
        } elseif (
120
            $xml->hasAttributeNS(C::NS_XSI, "nil") &&
121
            ($xml->getAttributeNS(C::NS_XSI, "nil") === "1" || $xml->getAttributeNS(C::NS_XSI, "nil") === "true")
122
        ) {
123
            // we have a nill value
124
            $value = null;
125
        } elseif (
126
            $xml->hasAttributeNS(C::NS_XSI, "type") &&
127
            $xml->getAttributeNS(C::NS_XSI, "type") === "xs:dateTime"
128
        ) {
129
            // we have a dateTime as value
130
            $value = DateTimeValue::fromString($xml->textContent);
131
        } else {
132
            $value = StringValue::fromString($xml->textContent);
133
        }
134
135
        return new static($value);
136
    }
137
138
139
    /**
140
     * Append this attribute value to an element.
141
     *
142
     * @param \DOMElement|null $parent The element we should append this attribute value to.
143
     *
144
     * @return \DOMElement The generated AttributeValue element.
145
     */
146
    public function toXML(?DOMElement $parent = null): DOMElement
147
    {
148
        $e = parent::instantiateParentElement($parent);
149
150
        $value = $this->getValue();
151
        $type = gettype($value);
152
153
        switch ($type) {
154
            case IntegerValue::class:
155
                // make sure that the xs namespace is available in the AttributeValue
156
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C::NS_XSI);
157
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C::NS_XS);
158
                $e->setAttributeNS(C::NS_XSI, 'xsi:type', 'xs:integer');
159
                $e->textContent = strval($value);
160
                break;
161
            case "object":
162
                if ($value instanceof DateTimeValue) {
163
                    $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C::NS_XSI);
164
                    $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C::NS_XS);
165
                    $e->setAttributeNS(C::NS_XSI, 'xsi:type', 'xs:dateTime');
166
                    $e->textContent = strval($value);
167
                } elseif ($value instanceof ValueTypeInterface) {
168
                    if ($value instanceof IntegerValue) {
169
                        $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C::NS_XSI);
170
                        $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C::NS_XS);
171
                        $e->setAttributeNS(C::NS_XSI, 'xsi:type', 'xs:integer');
172
                    }
173
                    $e->textContent = strval($value);
174
                } else {
175
                    $value->toXML($e);
176
                }
177
                break;
178
            default: // string
179
                $e->textContent = strval($value);
180
                break;
181
        }
182
183
        return $e;
184
    }
185
}
186