66use DOMElement ;
77use Psl \Option \Option ;
88use Soap \Encoding \Encoder \Context ;
9+ use Soap \Encoding \Encoder \FixedIsoEncoder ;
910use Soap \Encoding \Encoder \XmlEncoder ;
11+ use Soap \Engine \Metadata \Model \XsdType ;
1012use Soap \WsdlReader \Model \Definitions \BindingUse ;
1113use Soap \WsdlReader \Parser \Xml \QnameParser ;
1214use Soap \Xml \Xmlns as SoapXmlns ;
@@ -42,9 +44,9 @@ static function () use ($context, $value) {
4244 }
4345
4446 /**
45- * @return Option<XmlEncoder<mixed, string> >
47+ * @return Option<XsdType >
4648 */
47- public static function detectEncoderFromXmlElement (Context $ context , DOMElement $ element ): Option
49+ public static function detectXsdTypeFromXmlElement (Context $ context , DOMElement $ element ): Option
4850 {
4951 if ($ context ->bindingUse !== BindingUse::ENCODED ) {
5052 return none ();
@@ -70,14 +72,41 @@ public static function detectEncoderFromXmlElement(Context $context, DOMElement
7072 return none ();
7173 }
7274
73- $ type = $ context ->type ;
74- $ meta = $ type ->getMeta ();
75+ return some (
76+ // We create a new type based on the detected xsi:type, but we keep the meta information of the original type.
77+ // This way we can still detect if the type is nullable, a union, used on an element, ...
78+ $ context ->type
79+ ->copy ($ localName )
80+ ->withXmlTypeName ($ localName )
81+ ->withXmlNamespace ($ namespaceUri )
82+ );
83+ }
84+
85+ /**
86+ * @return Option<XmlEncoder<mixed, string>>
87+ */
88+ public static function detectEncoderFromXmlElement (Context $ context , DOMElement $ element ): Option
89+ {
90+ $ requestedXsiType = self ::detectXsdTypeFromXmlElement ($ context , $ element );
91+ if (!$ requestedXsiType ->isSome ()) {
92+ return none ();
93+ }
94+
95+ // Enhance context to avoid duplicate optionals, repeating elements, xsi:type detections, ...
96+ $ type = $ requestedXsiType ->unwrap ();
97+ $ encoderDetectorTypeMeta = $ type ->getMeta ()
98+ ->withIsNullable (false )
99+ ->withIsRepeatingElement (false );
100+ $ encoderDetectorContext = $ context
101+ ->withType ($ type ->withMeta (static fn () => $ encoderDetectorTypeMeta ))
102+ ->withBindingUse (BindingUse::LITERAL );
75103
76104 return some (
77- match (true ) {
78- $ meta ->isSimple ()->unwrapOr (false ) => $ context ->registry ->findSimpleEncoderByNamespaceName ($ namespaceUri , $ localName ),
79- default => $ context ->registry ->findComplexEncoderByNamespaceName ($ namespaceUri , $ localName ),
80- }
105+ new FixedIsoEncoder (
106+ $ context ->registry ->detectEncoderForContext ($ encoderDetectorContext )->iso (
107+ $ context ->withType ($ type )
108+ ),
109+ )
81110 );
82111 }
83112
0 commit comments