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:
<!-- 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.
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.
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 class. You can initialize it as follows:
$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.
$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 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.