Good morning @fernando2amigos ,
let me have a try. The last time I used NuSoap I used to write my code with PHP 4. If you really want to migrate from NuSoap to laminas/laminas-soap
, you can say goodbye to most of the concepts that NuSoap offered you. From my point of view, it will be much easier for you in the future.
Let us begin with the complex type. Complex types are just PHP data objects you will use with your soap client. Before sending a request you 'll initialize them with the values you want.
<?php
declare(strict_types=1);
namespace Marcel\ComplexType;
readonly class Persona
{
public function __construct(
public string $tipoDocumento,
public string $nombre,
public array $email = [],
) {}
}
That 's all what we need for the complex type. As you can see the property $tipoDocumento
is type hinted as string. That is not invalid, because your simple type restricts from a string base. So if you want to go the easy way this is all what you have to do. The PHP soap implementation will validate the given value for the $tipoDocumento
property as seen as you send a request.
If you want it more precise we can define the simple type tipoDocumento
as an enumeration. Since PHP 8 you can use the BackedEnum interface for this type of simple element.
<?php
declare(strict_types=1);
namespace Marcel\SimpleType;
enum TipoDocumento: string
{
case DNI = 'DNI';
case LE = 'LE';
case LC = 'LC';
case CI = 'CI';
case PASSPORT = 'PASSPORT';
}
This would change the type hint in your complex type PHP data object as follows:
<?php
declare(strict_types=1);
namespace Marcel\ComplexType;
use Marcel\SimpleType\TipoDocumento;
readonly class Persona
{
public function __construct(
public TipoDocumento $tipoDocumento,
public string $nombre,
public array $email = [],
) {}
}
The PHP SoapClient class, which is used by laminas/laminas-soap
knows nothing about backed enums. Requests and responses will definitely fail and potentially end up in a fault. So we have to teach the soap client how to handle enums. The PHP SoapClient has an classmap option. It is recommended to use this option when mapping complex types as PHP data objects.
<?php
declare(strict_types=1);
namespace Marcel;
use DOMDocument;
use SoapClient;
use SoapFault;
try {
$doc = new DOMDocument();
$wsdl = __DIR__ . '/path/to/your/webservice.wsdl';
$client = new SoapClient($wsdl, [
'classmap' => [
'persona' => \Marcel\ComplexType\Persona::class,
],
'exceptions' => true,
'trace' => true,
'typemap' => [
[
'type_ns' => 'http://www.namespace.uri',
'type_name' => 'tipoDocumento',
'from_xml' => function(string $xml) use ($doc): TipoDocumento {
$doc->loadXML($xml);
return TipoDocumento::tryFrom($doc->documentElement->nodeValue);
}
'to_xml' => function(TipoDocumento $enum) use ($doc): string {
$element = $doc->createElement('tipoDocumento', $enum->value);
return $doc->saveElement($element);
}
],
],
]);
} catch (SoapFault $fault) {
// error handling
}
Since we know the name of your simple type, we use the typemap option. Yeah, it looks messy and it is for sure not that type of encapsulation we usually want. But it will decode an xml string into a backed enum instance and vice versa.
If you don 't want all that mess in your client options there is a really useful hint in the PHP documentation for the classmap option.
Note that when creating a class, the constructor will not be called, but magic __set() and __get() methods for individual properties will be.
This is important, when you don 't want to use the typemap
option. Just add a magic method in your complex type PHP data object.
<?php
declare(strict_types=1);
namespace Marcel\ComplexType;
use Marcel\SimpleType\TypoDocumento;
readonly class Persona
{
public function __construct(
public TypoDocumento $tipoDocumento,
public string $nombre,
public array $email = [],
) {}
public function __get(string $name): mixed
{
if ($name === 'tipoDocumento') {
return $this->tipoDocumento->value;
}
return $this->{$name};
}
public function __set($name, $value): void {
if ($name === 'tipoDocumento') {
$value = TipoDocument::tryFrom($value);
}
$this->{$name} = $value;
}
}
As you can see, there are several ways to display simple types defined as enumerations for the PHP SoapClient. All of them are completely different from what you 're used to use with NuSoap.