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