# Problem with WSDL AutoDiscovery

**URL:** <https://discourse.laminas.dev/t/problem-with-wsdl-autodiscovery/3688>\
**Category:** Components & MVC\
**Tags:** laminas-soap\
**Created:** [May 10, 2024, 9:07pm UTC](https://discourse.laminas.dev/t/problem-with-wsdl-autodiscovery/3688 "2024-05-10T21:07:09Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![stefbortolin](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/stefbortolin/32/1703_2.png) [@stefbortolin](https://discourse.laminas.dev/u/stefbortolin)\
**Post date:** [May 10, 2024, 9:07pm UTC](https://discourse.laminas.dev/t/problem-with-wsdl-autodiscovery/3688/1 "2024-05-10T21:07:09Z")

</div>

I am using WSDL AutoDiscovery to generate a WSDL based on my system classes. I have to follow a structure given by an XML, in some cases of this XML, I have an array of objects and I don’t know how to define that in the docblocks, I upload an example:  
\<"AvailDestinations\>  
\<"Destination type = “CTY” code = “BUE”/\>  
\<"Destination type = “CTY” code = “MIA”/\>  
\</"AvailDestinations\>

In that case I would have to create an object that does not have a specific number of destinations defined and each destination must have the structure already defined. If I create the AvailDestinations class, what attributes should it have and what type should they be? It is possible to create an array of defined objects (like Destination[-] or something like that). Any help will be appreciated.

---

<div class="post-metadata">

**Author:** ![ezkimo](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/ezkimo/32/781_2.png) [@ezkimo](https://discourse.laminas.dev/u/ezkimo)\
**Post date:** [May 11, 2024, 10:27pm UTC](https://discourse.laminas.dev/t/problem-with-wsdl-autodiscovery/3688/2 "2024-05-11T22:27:14Z")

</div>

Hey @stefbortolin ,

could you show the xsd definition of the `AvailDestinations` element? Normally it equals a specific type. I guess this type has an element `Destination` defined, that could occur zero or more than one times. In this case the euivalent property of a php class is an array. Without knowing the exact xsd definition it is only guessing. So … it would be nice to see the xsd definition.

---

<div class="post-metadata">

**Author:** ![stefbortolin](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/stefbortolin/32/1703_2.png) [@stefbortolin](https://discourse.laminas.dev/u/stefbortolin)\
**Post date:** [May 11, 2024, 10:58pm UTC](https://discourse.laminas.dev/t/problem-with-wsdl-autodiscovery/3688/3 "2024-05-11T22:58:05Z")

</div>

Hi! I think the definition of AvailDestinations is something like that, i want to know how i do this in php classes and atributes with WSDL AutoDiscovery:  
\<xs:element name=“AvailDestinations”\>  
\<"xs:complexType\>  
\<"xs:sequence\>  
\<"xs:element name=“Destination” minOccurs=“0” maxOccurs=“unbounded”\>  
\<"xs:complexType\>  
\<"xs:attribute name=“type” type=“xs:string” /\>  
\<"xs:attribute name=“code” type=“xs:string” /\>  
\</"xs:complexType\>  
\</"xs:element\>  
\</"xs:sequence\>  
\</"xs:complexType\>  
\</"xs:element\>

I use the " in the start of the xml to evade errors, ignore them.

---

<div class="post-metadata">

**Author:** ![ezkimo](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/ezkimo/32/781_2.png) [@ezkimo](https://discourse.laminas.dev/u/ezkimo)\
**Post date:** [May 13, 2024, 7:18am UTC](https://discourse.laminas.dev/t/problem-with-wsdl-autodiscovery/3688/4 "2024-05-13T07:18:54Z")

</div>

Hey @stefbortolin ,

I 'm sorry for the late reply. But … weekend, barbeque and whisky … you know. 😉

## Edit the wsdl file and store it locally

It is always difficult for autodiscovery to discover anonymous complex type declarations. The results are often unsatisfactory and are not sufficient for smooth implementation. You should save the content of the WSDL file locally so that you can make changes to the definitions. Don’t worry, we will not fundamentally change the web service. We will just give the unnamed complex types a name. The XSD definitions have to be minimally adapted for this. You don 't have to do this. But for your comfort, I 'd suggest, that you keep the xsd pretty much the same as your PHP data objects.

Just change your element definition as follows:

```auto
<!-- element definition with type attribute -->
<xs:element name="AvailDestinations" type="ns:AvailableDestinations" />

<!-- definition for the type AvailableDestinations" -->
<xs:complexType name="AvailableDestinations">
    <xs:sequence>
        <!-- add the type attribut for the Destination complex type -->
        <xs:element name="Destination" type="ns:Destination" minOccurs="0" maxOccurs="unbounded" />
    </xs:sequence>
</xs:complexType>

<!-- definition of the Destination complex type -->
<xs:complexType name="Destination">
    <xs:attribute name="type" type="xs:string" />
    <xs:attribute name="code" type="xs:string" />
</xs:complexType>

```

Please be aware of existing complex types. If there are already declarations with the given namens from the example, just change them. The given example namespace `ns:` must be the target namespace of your document. Somewhere in the wsdl file there should be a `targetNamespace` attribute and a `xmlns:` namespace definition with a shorthand. Use this for your new complex Type definitions.

## The PHP data objects

Since we have edited the definitions a bit, we can code our own PHP data objects.

```auto
readonly class AvailableDestinations
{
    public function __construct(
        public array $Destination = [],
    ) {}
}

```

This is the first data object `AvailableDestinations`. As we can see in the XSD definitions, the element `Destination` inside this object is unbounded. It might occur. It can occure more than one time. Therefore it is always an array on PHP side. The type hint is the PHP data object is `Destination` and follows our xsd declaration.

```auto
readonly class Destination
{
    public function __construct(
        public string $type,
        public string $code,
    ) {}
}

```

The xsd definition for `Destination` defines attributes only. It is a bit misleading on PHP side, because xsd attributes are PHP properties, too. Confusing, because xsd elements of a complex type are also PHP class properties.

BTW: Readonly classes, because they only exist to transport data. Once initialized you won 't change their contents.

## Use it all together with the PHP soap client

Don 't get confused here. The `laminas/laminas-soap` package also uses the native [PHP SoapClient](https://www.php.net/manual/en/class.soapclient.php) class. You can initialize it as follows:

```auto
$wsdl = __DIR__. '/path/to/your/local/wsdl/file.wsdl';
$client = new \SoapClient($wsdl, [
    ...
    'classmap' => [
        ...
        'AvailableDestinations' => \Fully\Qualified\Namespace\AvailableDestinations::class,
        'Destinations' => \Fully\Qualified\Namespace\Destinations::class,
        ...
    ],
    ...
]);

```

The classmap option should take all PHP dataobjects as an associative array. The name of the XSD complex types are the keys. The values are the fully qualified names of the PHP data objects. Initializing the soap client with this option makes it pretty easy from now on.

```auto
$destination1 = new Destination('CTY', 'BUE');
$destination2 = new Destination('CTY', 'MIA');
$availableDestinations = new AvailableDestinations([
    $destination1,
    $destination2,
]);

$result = $client->someWebserviceMethod($availableDestinations);

```

Initialize the PHP data objects with the wanted values and just send them with your webservice method.

## Useful tipps and tricks

Wie Du vielleicht auch schon bemerkt hast, ist PHP SOAP eine Geschichte voller Geheimnisse. Ich möchte Dir ein paar Tipps mit auf den Weg geben.

- Always initialize your soap client with the `exceptions` options on `true`. You can catch every error and exception occuring while executing your webservice action.
- Use the option `trace` and enjoy the comfort of the \_\_lastRequest(), \_\_lastResponse(), \_\_lastRequestHeaders() and \_\_lastResponseHeaders() functions. For example: You can see your last sent XML request from now on.
- Use the `features` option of your soap client, when the response contains unbounded elements, which can appear zero or more times. With `SOAP_SINGLE_ELEMENT_ARRAYS` your PHP property will even be an array, when there are zero or only one element in the response.
- If the attributes aren 't formed well in the request try the [PHP SoapVar](https://www.php.net/manual/de/class.soapvar.php) class with your PHP data objects.
- When using the `classmap` option you should know, that the constructor of your PHP data objects is not used by the soap client. Therefore it uses the magic methods \_\_get() and \_\_set(). If you want to recognize these methods, I 'd suggest a parent class from which the data objects inherit and implements these two methods.
