Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fall back to complexType name when the element is a link to a complexType #546

Merged
merged 1 commit into from
Sep 27, 2024

Conversation

veewee
Copy link
Contributor

@veewee veewee commented Sep 27, 2024

Given following types:

<xs:complexType name="versionResponse">
    <xs:sequence>
        <xs:element minOccurs="0" name="version" type="xs:string" />
    </xs:sequence>
</xs:complexType>
<xs:element name="esfVersionResponse" nillable="true" type="tns:versionResponse"/>

And following operation:

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
    <wsdl:portType name="VersionService">
        <wsdl:operation name="getEsfVersion">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input name="getEsfVersion"><soap:body use="literal"/></wsdl:input>
            <wsdl:output name="getEsfVersionResponse"><soap:body use="literal"/></wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    
    <!-- snap -->
    
    <wsdl:message name="getEsfVersion">
        <wsdl:part element="tns:esfVersionRequest" name="esfVersionRequest">
        </wsdl:part>
    </wsdl:message>
    <wsdl:message name="getEsfVersionResponse">
        <wsdl:part element="tns:esfVersionResponse" name="esfVersionResponse">
        </wsdl:part>
    </wsdl:message>
</wsdl:definitions>

A request to getEsfVersion will result into the complexType VersonResponse.

    /**
     * @param RequestInterface & Type\EsfVersionRequest $esfVersionRequest
     * @return ResultInterface & Type\VersionResponse
     * @throws SoapException
     */
    public function getEsfVersion(\App\Type\EsfVersionRequest $esfVersionRequest) : \App\Type\VersionResponse
    {
        $response = ($this->caller)('getEsfVersion', $esfVersionRequest);

        \Psl\Type\instance_of(\App\Type\VersionResponse::class)->assert($response);
        \Psl\Type\instance_of(\Phpro\SoapClient\Type\ResultInterface::class)->assert($response);

        return $response;
    }

Resulting in:

dump($client->getEsfVersion(
    new \App\Type\EsfVersionRequest()
));
> ^ App\Type\VersionResponse^ {#191
    -version: "InvoiceV2"
}

This is how ext-soap works internally as well, making the generated code compatible with both the vanilla encoder package and ext-soap.

/cc @rauanmayemir This should solve the issue you have with the VersionService.

@veewee veewee added this to the 4.0.0 milestone Sep 27, 2024
@rauanmayemir
Copy link

Let me try this locally.

@rauanmayemir
Copy link

@veewee This works!

However, I can still see ApiVersionResponse and EsfVersionResponse classes being created and added to the classmap.
Is that a normal behaviour?

Also, type-wise EsfVersionRequest and ApiVersionRequest classes are still being created alongside VersionRequest class, but they have no relation to each other.
Would it make sense to not generate those types if they are clearly only using VersionRequest? (this is different from when complex types extend abstract complext types, both of this messages refer to the same type).

@veewee
Copy link
Contributor Author

veewee commented Sep 27, 2024

@rauanmayemir

It's a tricky question:

Since the schema specifies both ApiVersionResponse (element) and VersionRequest (complexType) by name, they should be accessible by name as well. That is why the classmap contains the information and that's why the classes are being generated.

Our meta-data system currently doesn't support an alias type that references to the complex type.
The wsdl-reader package will just read the linked type and use its properties.
I'm not sure if there is much benifit in implementing such system over just generating them as new classes:

Even if such system exists, We'dd still need to generate classes for those elements to make them accessible by name. They would then have to extend the initial type which would maybe introduce new issues.

I think current implementation is probably the easiest way forward.
Sure, it results in some additionally generated classes.
But they should be fairly easy to use in your system.

@rauanmayemir
Copy link

Agreed.

@veewee veewee merged commit b6825d1 into phpro:v4.x Sep 27, 2024
12 checks passed
@rauanmayemir
Copy link

@veewee found another case with a very simple service:

[Psl\Type\Exception\AssertException]
Expected "Gen\Esf\Api\Awp\Type\AwpXsdResponse", got "Phpro\SoapClient\Type\MixedResult".

I wonder if this is because they are using targetNamespace that is not URI?
This agency does that a lot, instead of using uri namespaces they use arbitraty strings like <xs:import namespace="abstractInvoice.esf"/>, <xs:import namespace="awp"/>.

@veewee
Copy link
Contributor Author

veewee commented Sep 27, 2024

@rauanmayemir It doesn't have to do with the namespace, cause that's a valid namespace.

The reason why you get this error is because the AwpXsdResponse does not implement Phpro\SoapClient\Type\ResultInterface. When you add it, it works as expected.
This is because the IsResultRule does not know that it's actually a result with the newly introduced changed.
I'll take a look on how I can fix that.

    ->addRule(
        new Rules\IsResultRule(
            $engine->getMetadata(),
            new Rules\MultiRule([
                new Rules\AssembleRule(new Assembler\ResultAssembler()),
            ])
        )
    )

Maybe easier if you report new bugs in new issues, cause otherwise I might loose track :)

(BTW : A soap service that delivers a list of XSD's ... Wow ... That's a first :) )

@rauanmayemir
Copy link

@veewee Then this might have the same issues as the previous case.

I have these assemblers:

new Rules\IsRequestRule(
    $metadata,
    new Rules\AssembleRule(new Assembler\RequestAssembler()),
),
new Rules\IsResultRule(
    $metadata,
    new Rules\AssembleRule(new Assembler\ResultAssembler()),
)

IsResultRule collects return type from the method, but method return type is mapped to the method name.
I.e generated client correctly expects AwpXsdResponse instead of QueryAwpXsdResponse, but AwpXsdResponse type doesn't implement ResultInterface because it is not recognized as a return type.

@rauanmayemir
Copy link

You're right, I'll create a separate issue.

(BTW : A soap service that delivers a list of XSD's ... Wow ... That's a first :) )

Yes, they create a base service, but then leave a hole for themselves with anyType that is supposed to be on of those XSDs you can pull from a separate service.

@veewee
Copy link
Contributor Author

veewee commented Sep 27, 2024

@rauanmayemir

I provided a fix for that specific case here:
#549

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants