AttributeValue::toXML()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 38
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 29
c 1
b 0
f 0
dl 0
loc 38
rs 8.8337
cc 6
nc 6
nop 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\Type\SAMLDateTimeValue;
10
use SimpleSAML\SAML11\Type\SAMLStringValue;
11
use SimpleSAML\XML\AbstractElement;
12
use SimpleSAML\XML\Chunk;
13
use SimpleSAML\XML\SchemaValidatableElementInterface;
14
use SimpleSAML\XML\SchemaValidatableElementTrait;
15
use SimpleSAML\XMLSchema\Constants as C_XSI;
16
use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException;
17
use SimpleSAML\XMLSchema\Type\IntegerValue;
18
use SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface;
19
20
use function class_exists;
21
use function explode;
22
use function gettype;
23
use function str_contains;
24
use function strval;
25
26
/**
27
 * Serializable class representing an AttributeValue.
28
 *
29
 * @package simplesamlphp/saml11
30
 */
31
class AttributeValue extends AbstractSamlElement implements SchemaValidatableElementInterface
32
{
33
    use SchemaValidatableElementTrait;
34
35
36
    /**
37
     * Create an AttributeValue.
38
     *
39
     * @param \SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface|\SimpleSAML\XML\AbstractElement $value
40
     * @throws \SimpleSAML\Assert\AssertionFailedException if the supplied value is neither a string or a DOMElement
41
     */
42
    final public function __construct(
43
        protected SAMLStringValue|IntegerValue|SAMLDateTimeValue|AbstractElement $value,
44
    ) {
45
    }
46
47
48
    /**
49
     * Get the XSI type of this attribute value.
50
     *
51
     * @return string
52
     */
53
    public function getXsiType(): string
54
    {
55
        $value = $this->getValue();
56
57
        if ($value === null) {
58
            return 'xs:nil';
59
        } elseif ($value instanceof ValueTypeInterface) {
60
            return $value::SCHEMA_NAMESPACE_PREFIX . ':' . $value::SCHEMA_TYPE;
61
        } else {
62
            return sprintf(
63
                '%s:%s',
64
                $value::getNamespacePrefix(),
65
                $value::getLocalName(),
66
            );
67
        }
68
    }
69
70
71
    /**
72
     * Get this attribute value.
73
     *
74
     * @return (
75
     *   \SimpleSAML\XMLSchema\Type\IntegerValue|
76
     *   \SimpleSAML\SAML11\Type\SAMLStringValue|
77
     *   \SimpleSAML\SAML11\Type\SAMLDateTimeValue|
78
     *   \SimpleSAML\XML\AbstractElement|
79
     *   null
80
     * )
81
     */
82
    public function getValue()
83
    {
84
        return $this->value;
85
    }
86
87
88
    /**
89
     * Convert XML into a AttributeValue
90
     *
91
     * @param \DOMElement $xml The XML element we should load
92
     * @return static
93
     *
94
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
95
     *   if the qualified name of the supplied element is wrong
96
     */
97
    public static function fromXML(DOMElement $xml): static
98
    {
99
        Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
100
        Assert::same($xml->namespaceURI, static::NS, InvalidDOMElementException::class);
101
102
        if ($xml->childElementCount > 0) {
103
            $node = $xml->firstElementChild;
104
105
            if (str_contains($node->tagName, ':')) {
106
                list($prefix, $eltName) = explode(':', $node->tagName);
107
                $className = sprintf('\SimpleSAML\SAML11\XML\%s\%s', $prefix, $eltName);
108
109
                if (class_exists($className)) {
110
                    $value = $className::fromXML($node);
111
                } else {
112
                    $value = Chunk::fromXML($node);
113
                }
114
            } else {
115
                $value = Chunk::fromXML($node);
116
            }
117
        } elseif (
118
            $xml->hasAttributeNS(C_XSI::NS_XSI, "type") &&
119
            $xml->getAttributeNS(C_XSI::NS_XSI, "type") === "xs:integer"
120
        ) {
121
            // we have an integer as value
122
            $value = IntegerValue::fromString($xml->textContent);
123
        } elseif (
124
            $xml->hasAttributeNS(C_XSI::NS_XSI, "nil") &&
125
            ($xml->getAttributeNS(C_XSI::NS_XSI, "nil") === "1" ||
126
                $xml->getAttributeNS(C_XSI::NS_XSI, "nil") === "true")
127
        ) {
128
            // we have a nill value
129
            $value = null;
130
        } elseif (
131
            $xml->hasAttributeNS(C_XSI::NS_XSI, "type") &&
132
            $xml->getAttributeNS(C_XSI::NS_XSI, "type") === "xs:dateTime"
133
        ) {
134
            // we have a dateTime as value
135
            $value = SAMLDateTimeValue::fromString($xml->textContent);
136
        } else {
137
            $value = SAMLStringValue::fromString($xml->textContent);
138
        }
139
140
        return new static($value);
141
    }
142
143
144
    /**
145
     * Append this attribute value to an element.
146
     *
147
     * @param \DOMElement|null $parent The element we should append this attribute value to.
148
     *
149
     * @return \DOMElement The generated AttributeValue element.
150
     */
151
    public function toXML(?DOMElement $parent = null): DOMElement
152
    {
153
        $e = parent::instantiateParentElement($parent);
154
155
        $value = $this->getValue();
156
        $type = gettype($value);
157
158
        switch ($type) {
159
            case IntegerValue::class:
160
                // make sure that the xs namespace is available in the AttributeValue
161
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C_XSI::NS_XSI);
162
                $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C_XSI::NS_XS);
163
                $e->setAttributeNS(C_XSI::NS_XSI, 'xsi:type', 'xs:integer');
164
                $e->textContent = strval($value);
165
                break;
166
            case "object":
167
                if ($value instanceof SAMLDateTimeValue) {
168
                    $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C_XSI::NS_XSI);
169
                    $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C_XSI::NS_XS);
170
                    $e->setAttributeNS(C_XSI::NS_XSI, 'xsi:type', 'xs:dateTime');
171
                    $e->textContent = strval($value);
172
                } elseif ($value instanceof ValueTypeInterface) {
173
                    if ($value instanceof IntegerValue) {
174
                        $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', C_XSI::NS_XSI);
175
                        $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xs', C_XSI::NS_XS);
176
                        $e->setAttributeNS(C_XSI::NS_XSI, 'xsi:type', 'xs:integer');
177
                    }
178
                    $e->textContent = strval($value);
179
                } else {
180
                    $value->toXML($e);
181
                }
182
                break;
183
            default: // string
184
                $e->textContent = strval($value);
185
                break;
186
        }
187
188
        return $e;
189
    }
190
}
191