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

array resolved as Dt

Open dakorpar opened this issue 5 years ago β€’ 10 comments

Bug Report

Q A
BC Break yes
Version dev-master

Summary

I am not sure if this is issue in soap service or soap generator, this is in wsdl:

  <xs:complexType name="getAvailableFreeBoxesForMachineResponse">
    <xs:sequence>
      <xs:element maxOccurs="unbounded" minOccurs="0" name="availableBoxes" type="tns:dtAvailableBoxes"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="dtAvailableBoxes">
    <xs:sequence>
      <xs:element minOccurs="0" name="boxSize" type="tns:boxSize"/>
      <xs:element minOccurs="0" name="comfortZone" type="tns:comfortZone"/>
      <xs:element name="freeCount" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>

Current behavior

Response generated:


	public function getAvailableBoxes(): DtAvailableBoxes
	{
		return $this->availableBoxes;
	}

Expected behavior

Response should be:

	/**
	 * @return DtAvailableBoxes[]
	 */
	public function getAvailableBoxes(): array
	{
		return $this->availableBoxes;
	}

What's the proper way to handle this? Currently I'm manually changing this to array but this is not good approach...

dakorpar avatar Apr 02 '19 08:04 dakorpar

I think this can be achieved by changing the wsdl as described in this article

janvernieuwe avatar Apr 19 '19 07:04 janvernieuwe

Feedback was provided. Feel free to re-open a issue if this doesn't resolve your problem.

veewee avatar Jun 21 '19 06:06 veewee

This doesn't resolve anything ofcours. Sorry I didn't replied to this, but changing wsdl is never an option. WSDL is not something in our control. @veewee I cannot reopen this, you have to do it.

dakorpar avatar Jun 26 '19 08:06 dakorpar

@dakorpar

Would it be a solution to use the IteratorAssembler for this? https://github.com/phpro/soap-client/blob/master/docs/code-generation/assemblers.md#iteratorassembler

I'll have to investigate what the ext-soap SoapClient::__getFunctions() for this looks like for this specific request to see if there's anything we can do from within this package to improve this.

veewee avatar Jun 26 '19 08:06 veewee

@veewee I'll take a look, thanks

dakorpar avatar Jun 26 '19 08:06 dakorpar

Could you confirm that I understand the function of IteratorAssembler correctly? There is not much documentation in the docs nor the code, but this is what I think it is true:

  1. I need to hardcode which types contain other types by applying the assembler only on particular classes.

  2. The owning type can only have one array of other types.

  3. The property to be iterated on must be the first in the array of properties (judging from this).

  4. The type hint will still not show that the type is an array. And the type mapping has no knowledge of that being an array either.

If the above are true, then this solution is unfortunately not enough for me, as we are using the code generation step to also generate a database mapping and serialization configuration files, where we need to treat arrays differently.

Can this issue be solved in the land of this library, or is that a problem with the underlying ext-soap extension? Just checking whether there is any point in me trying to implement this and submitting a PR.

melkamar avatar Nov 04 '19 17:11 melkamar

Hi @dakorpar,

Thanks for answering. Looks like you are working on something fancy.

You are right: we could improve the documentation on the topic. To answer your questions:

Example

https://github.com/veewee/demo-soap-client

            <s:complexType name="ArrayOfWeatherDescription">
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="unbounded" name="WeatherDescription" type="tns:WeatherDescription" />
                </s:sequence>
            </s:complexType>
$config
    ->addRule(
        new Rules\TypenameMatchesRule(
            new Rules\MultiRule([
                new Rules\AssembleRule(new Assembler\IteratorAssembler()),
                new Rules\AssembleRule(new Assembler\GetterAssembler(new Assembler\GetterAssemblerOptions()))
            ]),
            '/^ArrayOf/i'
        )
    );

Result:

<?php

namespace WeatherService\Type;

use IteratorAggregate;

class ArrayOfWeatherDescription implements IteratorAggregate
{

    /**
     * @var \WeatherService\Type\WeatherDescription
     */
    private $WeatherDescription;

    /**
     * @return \ArrayIterator
     */
    public function getIterator()
    {
        return new \ArrayIterator(is_array($this->WeatherDescription) ? $this->WeatherDescription : []);
    }

    /**
     * @return \WeatherService\Type\WeatherDescription
     */
    public function getWeatherDescription()
    {
        return $this->WeatherDescription;
    }


}

Answers

  1. Not exactly: you could use a regex as in the example above or check if you can use anything else from the metadata
  2. Indeed: it is created for complexTypes which contain a single sequence type. Another option could be to make it based on property.
  3. Currently: yes. See answer above.
  4. Since it is an IteratorAggregate, your IDE will know it is iterable. The typemap and docblocks still remain as before. This could be an addition inside the assembler as well. But is might make more sense to change this information if it is available in the metadata.

Ext-soap is very limited in what information it passes from the WSDL. We are basically limited to:

  • https://www.php.net/manual/en/soapclient.getfunctions.php
  • https://www.php.net/manual/en/soapclient.gettypes.php

We provided a set of parsers to load the maximum amount of information from those functions. See:

  • General metadata parsing: https://github.com/phpro/soap-client/tree/master/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata
  • For list types: https://github.com/phpro/soap-client/blob/master/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitor.php

So if your type is a list, it should already come up as an array. Otherwise we probably won't be able to know from the WSDL if it is an array. It is easier if you can provide a WSDL or scan the generated metadata manually to see if the information you need is available.

Another solution would be to create your own metadata parser based on the actual WSDL file. In that way, you can be more flexible with the data you fetch and pass to the code generation section.

More info:

  • https://github.com/phpro/soap-client/blob/master/docs/drivers/new.md#metadataproviders
  • You might be able to use this WSDL parser: https://packagist.org/packages/goetas-webservices/wsdl-reader

(Do know that the code generation section only uses a subset of the metadata currently, since that part of the application is still much older. It would be nice to upgrade that part as well in the future or to provide alternative drivers / metadata parsers for this pacakge as well.)

Feel free to ask more questions if the above is not clear or if you are thinking of a specific PR which you need help with.

veewee avatar Nov 05 '19 05:11 veewee

Thank you for the extensive answer, @veewee. Much appreciated!

  1. Not exactly: you could use a regex as in the example above or check if you can use anything else from the metadata

The WSDL I consume is unfortunately outside of my control and there are no consistent pre/suffixes that could be matched by a regex :( But thanks for the suggestion

Looks like you are working on something fancy.

I wish, I am working on upgrading soap-client from 0.7.x to the latest version and regenerating the code from a new version of the WSDL we consume, and the person who did this previously and in the process manually fixed the types (arrays, mostly) has left the job.

So I'm just attempting to limit the amount of work needed to be done by hand while keeping the generated code compatible with our existing codebase. Fun times!

Anyways, rant over. I will go over the suggestions you gave and see what is the easiest way to get things working.

Thanks for the library πŸ‘

melkamar avatar Nov 05 '19 08:11 melkamar

Sorry for not replying, I'm allways buisy and when I'm not I completelly forgot on this... I just manually changed this code since lib won't change much and we won't regenerate code often so I forgot on it... If U need some info or whole wsdl I can send it to you and classes that are generated and how it should be, but maybe on some private channel would be more appropriate since it's closed service...

dakorpar avatar Nov 05 '19 08:11 dakorpar

would be super nice if we can use IteratorAssembler for a specific property :sweat_smile: or perhaps be able to specify array properties, and generate the getters accordingly.

ro0NL avatar Mar 11 '20 10:03 ro0NL

Hello,

We noticed this issue got reported many times and want to tackle it at its core! Therefore, we've planned a project that will work on better types support. It’s going to be a huge project, so we are looking for ways to make development possible during our business hours instead of in our developers precious spare time.

In case you want this feature as badly as us: find out how you can support this project here πŸ’š!

veewee avatar Oct 28 '22 07:10 veewee

Closing this one - will be dealt with in #464

veewee avatar Apr 03 '23 14:04 veewee