44
55namespace SimpleSAML \SAML2 \XML \saml ;
66
7- use DateTimeImmutable ;
8- use DateTimeInterface ;
97use DOMElement ;
108use SimpleSAML \SAML2 \Assert \Assert ;
11- use SimpleSAML \SAML2 \Constants as C ;
9+ use SimpleSAML \SAML2 \Exception \ RuntimeException ;
1210use SimpleSAML \XML \AbstractElement ;
1311use SimpleSAML \XML \Chunk ;
12+ use SimpleSAML \XML \Registry \ElementRegistry ;
1413use SimpleSAML \XML \SchemaValidatableElementInterface ;
1514use SimpleSAML \XML \SchemaValidatableElementTrait ;
1615use SimpleSAML \XMLSchema \Constants as C_XSI ;
1716use SimpleSAML \XMLSchema \Exception \InvalidDOMElementException ;
17+ use SimpleSAML \XMLSchema \Type \DateTimeValue ;
18+ use SimpleSAML \XMLSchema \Type \IntegerValue ;
19+ use SimpleSAML \XMLSchema \Type \Interface \ValueTypeInterface ;
20+ use SimpleSAML \XMLSchema \Type \StringValue ;
1821
19- use function class_exists ;
20- use function explode ;
21- use function gettype ;
22- use function intval ;
23- use function str_contains ;
22+ use function sprintf ;
23+ use function strval ;
2424
2525/**
2626 * Serializable class representing an AttributeValue.
@@ -35,11 +35,14 @@ class AttributeValue extends AbstractSamlElement implements SchemaValidatableEle
3535 /**
3636 * Create an AttributeValue.
3737 *
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
38+ * @param (
39+ * \SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface|
40+ * \SimpleSAML\XML\AbstractElement|
41+ * null
42+ * ) $value
4043 */
4144 final public function __construct (
42- protected string | int |null | DateTimeInterface | AbstractElement $ value ,
45+ protected ValueTypeInterface | AbstractElement |null $ value ,
4346 ) {
4447 }
4548
@@ -50,35 +53,31 @@ final public function __construct(
5053 public function getXsiType (): string
5154 {
5255 $ 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 " ;
56+
57+ if ($ value === null ) {
58+ return 'xs:nil ' ;
59+ } elseif ($ value instanceof AbstractElement) {
60+ return sprintf (
61+ '%s:%s ' ,
62+ $ value ::getNamespacePrefix (),
63+ AbstractElement::getClassName (get_class ($ value )),
64+ );
7265 }
66+
67+ return $ value ->getType ();
7368 }
7469
7570
7671 /**
7772 * Get this attribute value.
7873 *
79- * @return string|int|\SimpleSAML\XML\AbstractElement|null
74+ * @return (
75+ * \SimpleSAML\XMLSchema\Type\Interface\ValueTypeInterface|
76+ * \SimpleSAML\XML\AbstractElement|
77+ * null
78+ * )
8079 */
81- public function getValue ()
80+ public function getValue (): ValueTypeInterface | AbstractElement | null
8281 {
8382 return $ this ->value ;
8483 }
@@ -92,52 +91,40 @@ public function getValue()
9291 */
9392 public static function fromXML (DOMElement $ xml ): static
9493 {
95- Assert::same ($ xml ->localName , ' AttributeValue ' , InvalidDOMElementException::class);
94+ Assert::same ($ xml ->localName , static :: getLocalName () , InvalidDOMElementException::class);
9695 Assert::same ($ xml ->namespaceURI , AttributeValue::NS , InvalidDOMElementException::class);
9796
9897 if ($ xml ->childElementCount > 0 ) {
9998 $ node = $ xml ->firstElementChild ;
10099
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 );
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- ) {
100+ $ registry = ElementRegistry::getInstance ();
101+ $ handler = $ registry ->getElementHandler ($ node ->namespaceURI , $ node ->localName );
102+
103+ $ value = $ handler ? $ handler ::fromXML ($ node ) : Chunk::fromXML ($ node );
104+ } elseif ($ xml ->hasAttributeNS (C_XSI ::NS_XSI , 'nil ' )) {
105+ Assert::oneOf ($ xml ->getAttributeNS (C_XSI ::NS_XSI , 'nil ' ), ['1 ' , 'true ' ]);
135106 Assert::isEmpty ($ xml ->nodeValue );
136107 Assert::isEmpty ($ xml ->textContent );
137108
138109 $ value = null ;
110+ } elseif ($ xml ->hasAttributeNS (C_XSI ::NS_XSI , 'type ' )) {
111+ $ type = $ xml ->getAttributeNS (C_XSI ::NS_XSI , 'type ' );
112+
113+ switch ($ type ) {
114+ case 'xs:dateTime ' :
115+ $ value = DateTimeValue::fromString ($ xml ->textContent );
116+ break ;
117+ case 'xs:integer ' :
118+ $ value = IntegerValue::fromString ($ xml ->textContent );
119+ break ;
120+ case 'xs:string ' :
121+ $ value = StringValue::fromString ($ xml ->textContent );
122+ break ;
123+ default :
124+ throw new RuntimeException (sprintf ("Cannot process xsi:type '%s' " , $ type ));
125+ }
139126 } else {
140- $ value = $ xml ->textContent ;
127+ $ value = StringValue:: fromString ( $ xml ->textContent ) ;
141128 }
142129
143130 return new static ($ value );
@@ -152,33 +139,18 @@ public function toXML(?DOMElement $parent = null): DOMElement
152139 $ e = parent ::instantiateParentElement ($ parent );
153140
154141 $ 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 ;
142+ if ($ value === null ) {
143+ $ e ->setAttributeNS ('http://www.w3.org/2000/xmlns/ ' , 'xmlns:xsi ' , C_XSI ::NS_XSI );
144+ $ e ->setAttributeNS (C_XSI ::NS_XSI , 'xsi:nil ' , '1 ' );
145+ } elseif ($ value instanceof AbstractElement) {
146+ $ value ->toXML ($ e );
147+ } elseif ($ value instanceof StringValue) {
148+ $ e ->textContent = strval ($ value );
149+ } else {
150+ $ e ->setAttributeNS ('http://www.w3.org/2000/xmlns/ ' , 'xmlns:xs ' , C_XSI ::NS_XS );
151+ $ e ->setAttributeNS ('http://www.w3.org/2000/xmlns/ ' , 'xmlns:xsi ' , C_XSI ::NS_XSI );
152+ $ e ->setAttributeNS (C_XSI ::NS_XSI , 'xsi:type ' , $ value ->getType ());
153+ $ e ->textContent = strval ($ value );
182154 }
183155
184156 return $ e ;
0 commit comments