Closed rvdbogerd closed 5 years ago
Hi! Thanks for the interest in this project.
Firs of all, this project currently supports WSDL-1.1 (see https://github.com/goetas-webservices/wsdl-reader), so I'm not sure how to proceed. I haven't yet experimented with WSDL-2.0 (is it already adopted? I thought it never took off...).
https://github.com/goetas-webservices/xsd-reader should be able to support extension (instead of override).
Is this behavior also part of WSDL-1.1?
So, I've researched this thing all day, and found the following..
XML Inline schemas definition by Microsoft .NET:
You can also have multiple inline schemas that define the same target namespace as long as no elements or attributes from that namespace were processed.
I found some old threads like this one, stating:
I created a WSDL with multiple inline schema's with the same targetNamespace. WSDL 1.1 is not very clear regarding this, but this is corrected in WSDL 2.0, which explicitly allows this: A WSDL 2.0 document may define multiple inline schemas in its types element. The two or more schemas may have the same target namespace provided that they do not define the same elements or types. It is an error to define the same element or type more than once, even if the definitions are identical.
So it seems nobody ever stated that it ISN'T allowed, and the 2.0 spec states specifically that it IS.
For arguments sake, let's consider this slimmed down piece of WSDL:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="MetadataService" targetNamespace="http://rechtspraak.nl/MetadataService/v1"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://rechtspraak.nl/MetadataService/v1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<wsdl:types>
<xs:schema elementFormDefault="qualified" targetNamespace="http://rechtspraak.nl/Service/DataTypes"
xmlns:q1="http://rechtspraak.nl/Service/DataTypes">
<xs:complexType name="CodelijstWaarde">
<xs:sequence>
<xs:element name="Titel" type="xs:string"/>
<xs:element name="Waarde" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="CodelijstWaarde" type="q1:CodelijstWaarde"/>
</xs:schema>
<!--<xs:schema targetNamespace="http://rechtspraak.nl/Service/DataTypes"-->
<!--xmlns:q1="http://rechtspraak.nl/Service/DataTypes">-->
<!--<xs:simpleType name="String50">-->
<!--<xs:restriction base="xs:string">-->
<!--<xs:minLength value="1"/>-->
<!--<xs:maxLength value="50"/>-->
<!--</xs:restriction>-->
<!--</xs:simpleType>-->
<!--<xs:element name="String50" type="q1:String50" xmlns:q1="http://rechtspraak.nl/Service/DataTypes"/>-->
<!--</xs:schema>-->
<xs:schema elementFormDefault="qualified" targetNamespace="http://rechtspraak.nl/Service/Metadata" xmlns:tns="http://rechtspraak.nl/Service/Metadata">
<xs:import namespace="http://rechtspraak.nl/Service/DataTypes"/>
<xs:complexType name="CodelijstWaarden">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="CodelijstWaarde" nillable="true" type="q1:CodelijstWaarde" xmlns:q1="http://rechtspraak.nl/Service/DataTypes" />
</xs:sequence>
</xs:complexType>
<xs:element name="CodelijstWaarden" type="tns:CodelijstWaarden"/>
</xs:schema>
</wsdl:types>
</wsdl:definitions>
When I run vendor/bin/soap-client -vvv generate config/config.yml src/Service/Container --dest-class=Service/Container/SoapContainer
in the demo app, it generates all code just fine. But if I uncomment the second schema, I get the following error:
In SchemaReader.php line 1024:
[GoetasWebservices\XML\XSDReader\Exception\TypeException]
Can't find type named {http://rechtspraak.nl/Service/DataTypes}#CodelijstWaarde, at line 34 in ~/soap-client-demo/config/metadata-snippet.xml
What do you think the intended behaviour of your library should be?
Oh, btw, if I uncomment and put the second block on top, it all works fine, so that indicates that it is overriding the first schema (or at least the reference).
The trick stays somewhere in this lines: https://github.com/goetas-webservices/xsd-reader/blob/58aafb98e868b9fb0e0553a8a6310fc99164a166/src/Schema/Schema.php#L33
There is performed the search of elements, if you are interested to play with it, that should be a good starting point.
Thanks! I'll have a look at it today
Yet another day of debugging and I FINALLY found the bug, yay!
The schema gets overridden on line: https://github.com/goetas-webservices/xsd-reader/blob/58aafb98e868b9fb0e0553a8a6310fc99164a166/src/Schema/Schema.php#L267
This behaviour seems inconsistent with that of SchemaReader::loadedSchemas[NAMESPACE][]
, which is a multidimensional array, also indexed by namespace.
So the following if statement fixes the issue, but does not seem to me as a proper fix.
public function addSchema(self $schema, string $namespace = null): void
{
if ($namespace !== null) {
if ($schema->getTargetNamespace() !== $namespace) {
throw new SchemaException(
sprintf(
"The target namespace ('%s') for schema, does not match the declared namespace '%s'",
$schema->getTargetNamespace(),
$namespace
)
);
}
/** FIX STARTS HERE **/
dump('Now adding child schema on array key '.$namespace);
if (isset($this->schemas[$namespace])) {
dump('but it is already set! Oh well, we just save a copy of it');
$this->schemas[] = $this->schemas[$namespace];
}
/** END FIX **/
$this->schemas[$namespace] = $schema;
} else {
$this->schemas[] = $schema;
}
}
I can verify that above fix works for multiple schemas in one file.
We could make the schemas
property multidimensional too, but I'm afraid that will break BC. Suggestions?
Hi! First of all, thanks for all your efforts in trying to make soap work with PHP 👍 I know it's a pain..
Talking about that, I've been playing (read: debugging) my third party SOAP webservice with your libraries and have the following issues:
The WSDL (2.0) definition that I get from the webservice, has multiple inline schemas with the same targetNamespace. It seems like your schema reader is overwriting it everytime it finds a
<xs:schema>
line. I looked it up in the WSDL-2.0 spec at http://www.w3.org/TR/wsdl20/ which states:So the desired behaviour is that multiple
schema
nodes with the same targetNamespace should "extend" each other, not override. I'd like to make PR to make that happen. Before I start, any concerns, thoughts, ideas? :D