soap-client icon indicating copy to clipboard operation
soap-client copied to clipboard

Types in different namespaces are not handled properly

Open func0der opened this issue 8 months ago • 1 comments

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 ```xml ISO 3166-1 alpha-2 codes ```
model/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>

func0der avatar Apr 22 '25 14:04 func0der

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.

veewee avatar Apr 23 '25 05:04 veewee

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 avatar Jul 23 '25 10:07 RafaelKr

@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, ...

veewee avatar Jul 23 '25 10:07 veewee

Closing for now. We'll keep track of this in #571

veewee avatar Sep 26 '25 05:09 veewee