Types in different namespaces are not handled properly
Bug Report
| Q | A |
|---|---|
| BC Break | From my perspective this is a bug, but it could change the way classes are generated |
| Version | 4.2.0 |
Summary
Having a type with the same name in different namespaces, might result in types not being generated
Current behavior
Currently there seems to be a problem with the a type using the same name in different namespaces and having ever so slight differences in their definition.
An example of this would be in this WSDL: https://acceptance.eudr.webcloud.ec.europa.eu/tracesnt/ws/EUDRSubmissionServiceV1?wsdl
It defines CountryType in two different namespaces:
-
http://ec.europa.eu/sanco/tracesnt/base/v4:CountryType -
http://ec.europa.eu/tracesnt/certificate/eudr/model/v1:CountryType
One is a simple string, which would be skipped as scalar string type during generation, the other one has an enum to it.
Since they both are named the same, they will get "merged" by \Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\IntersectDuplicateTypesStrategy, in the process losing the definition of the v1 enum version.
This results in a an entry in the classmap:
<?php
new ClassMap('http://ec.europa.eu/tracesnt/certificate/eudr/model/v1', 'CountryType', \App\Generated\Eudr\Type\CountryType::class),
But \App\Generated\Eudr\Type\CountryType::class does not even exist, because it does not get generated.
How to reproduce
You can use this config to generate the code:
<?php
use Phpro\SoapClient\CodeGenerator\Assembler;
use Phpro\SoapClient\CodeGenerator\Rules;
use Phpro\SoapClient\CodeGenerator\Config\Config;
use Phpro\SoapClient\Soap\EngineOptions;
use Phpro\SoapClient\Soap\DefaultEngineFactory;
return Config::create()
->setEngine($engine = DefaultEngineFactory::create(
EngineOptions::defaults('https://eudr.webcloud.ec.europa.eu/tracesnt/ws/EUDRSubmissionServiceV1?wsdl')
))
->setTypeDestination('app/Generated/Eudr/Type')
->setTypeNamespace('App\Generated\Eudr\Type')
->setClientDestination('app/Generated/Eudr')
->setClientName('SubmissionServiceClient')
->setClientNamespace('App\Generated\Eudr')
->setClassMapDestination('app/Generated/Eudr')
->setClassMapName('SubmissionServiceClassmap')
->setClassMapNamespace('App\Generated\Eudr')
->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler(new Assembler\GetterAssemblerOptions())))
->addRule(new Rules\AssembleRule(new Assembler\ImmutableSetterAssembler(
new Assembler\ImmutableSetterAssemblerOptions()
)))
->addRule(
new Rules\IsRequestRule(
$engine->getMetadata(),
new Rules\MultiRule([
new Rules\AssembleRule(new Assembler\RequestAssembler()),
new Rules\AssembleRule(new Assembler\ConstructorAssembler(new Assembler\ConstructorAssemblerOptions())),
])
)
)
->addRule(
new Rules\IsResultRule(
$engine->getMetadata(),
new Rules\MultiRule([
new Rules\AssembleRule(new Assembler\ResultAssembler()),
])
)
)
->addRule(
new Rules\IsExtendingTypeRule(
$engine->getMetadata(),
new Rules\AssembleRule(new Assembler\ExtendingTypeAssembler())
)
)
->addRule(
new Rules\IsAbstractTypeRule(
$engine->getMetadata(),
new Rules\AssembleRule(new Assembler\AbstractClassAssembler())
)
)
;
Expected behavior
CountryType should either be properly merged, which would probably results in a disaster if the types are anywhere close to different (one is an int and one it a enum of strings), or the namespaces of the XML need to somehow be part of the generated classes?
base/v4:CountryType
```xmlmodel/v1:CountryType
<xs:simpleType name="CountryType">
<xs:restriction base="xs:string">
<xs:enumeration value="AT">
<xs:annotation>
<xs:documentation>Austria</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BE">
<xs:annotation>
<xs:documentation>Belgium</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="BG">
<xs:annotation>
<xs:documentation>Bulgaria</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="CY">
<xs:annotation>
<xs:documentation>Cyprus</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="CZ">
<xs:annotation>
<xs:documentation>Czech Republic</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="DE">
<xs:annotation>
<xs:documentation>Germany</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="DK">
<xs:annotation>
<xs:documentation>Denmark</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="EE">
<xs:annotation>
<xs:documentation>Estonia</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="ES">
<xs:annotation>
<xs:documentation>Spain</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="FI">
<xs:annotation>
<xs:documentation>Finland</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="FR">
<xs:annotation>
<xs:documentation>France</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="GR">
<xs:annotation>
<xs:documentation>Greece</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HR">
<xs:annotation>
<xs:documentation>Croatia</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="HU">
<xs:annotation>
<xs:documentation>Hungary</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="IE">
<xs:annotation>
<xs:documentation>Ireland</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="IT">
<xs:annotation>
<xs:documentation>Italy</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LT">
<xs:annotation>
<xs:documentation>Lithuania</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LU">
<xs:annotation>
<xs:documentation>Luxembourg</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="LV">
<xs:annotation>
<xs:documentation>Latvia</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="MT">
<xs:annotation>
<xs:documentation>Malta</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NL">
<xs:annotation>
<xs:documentation>Netherlands</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="PL">
<xs:annotation>
<xs:documentation>Poland</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="PT">
<xs:annotation>
<xs:documentation>Portugal</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RO">
<xs:annotation>
<xs:documentation>Romania</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="SE">
<xs:annotation>
<xs:documentation>Sweden</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="SI">
<xs:annotation>
<xs:documentation>Slovenia</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="SK">
<xs:annotation>
<xs:documentation>Slovakia (Slovak Republic)</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="XI">
<xs:annotation>
<xs:documentation>United Kingdom (Northern Ireland)</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
The intersection strategy indeed has some drawbacks. Until we got a system like #571, we won't be able to cover every scenario with it. I suppose we could improve the strategy the prefer enums over simple types or even merge enums.
I tried to do an Upgrade from 1.x to 4.2 and also ran into this issue. Instead of returning a valid class instance I got a MixedResult where getResult returned a string just containing all text nodes concatenated.
For now I only migrate from 1.x to 3.4.1 to use the ext-soap decoding which works for me.
If you need some more Data (wsdl + response xml) to test I would be able to provide it.
@RafaelKr I'm not sure what you mention is related to the main issue reported here. Feel free to open up a new issue with all the information you have about the issue. It would be nice to have all data required to reproduce the issue: wsdl, response payload, code generation config, factory config, ...
Closing for now. We'll keep track of this in #571