Classes that are used by the classes generated by the PackageGenerator project to ease the SoapClient UX.
The goal is to provide generic and useful classes that are on top of the classes generated by the PackageGenerator project.
For example, it allows to easily loop through the array elements of a SOAP result object property, it allows to easily set HTTP and SOAP headers for a SOAP request and it allows to easily populate an object from its array state representation.
The defined interfaces must be used in order to be able to match the requirements for the PackageGenerator generated classes.
This interface must be used to define a new EnumType class.
There is at least/most one method that must be implemented so it's pretty fast to implement it even if you don't see the goal of it:
$value
is valid. This can be done using the array of string returned by the getValidValues
method always present in the generated Enum classes. If you do not want to implement this method, you can too create your own class that inherits from our AbstractStructEnumBase class.
This interface must be used to define a new StructType class.
There is at least/most one method that must be implemented so it's pretty fast to implement it even if you don't see the goal of it:
If you do not want to implement this method, you can too create your own class that inherits from our AbstractStructBase class.
This interface must be used to define a new ArrayType class. The goal is to provide utility methods around Array Structs defined by the Wsdl in order to ease the handling of its content. Therefore, this interface inherits from our StructInterface interface plus the native ArrayAccess, Iterator and Countable PHP interfaces
The only method that must be implemented would be getAttributeName but be aware that it is implemented in every generated ArrayType class so no need to define it. It's just a reminder of what is available in ArrayType classes.
So, basically, you MUST at least override the methods declared by the PHP interfaces from which this interface inherits
If you do not want to implement all the methods, you can too create your own class that inherits from our AbstractStructArrayBase class.
This interface must be used to define a new SoapClient base class for any ServiceType
class generated by PackageGenerator.
Here are the constants/options defined by this interface and their utility:
location
)true
WSDL_CACHE_NONE
, WSDL_CACHE_DISK
, WSDL_CACHE_MEMORY
or WSDL_CACHE_BOTH
SOAP_1_1
or SOAP_1_2
to select SOAP 1.1 or 1.2, respectively. If omitted, SOAP 1.1 is usedSOAP_SINGLE_ELEMENT_ARRAYS
, SOAP_USE_XSI_ARRAY_TYPE
, SOAP_WAIT_ONE_WAY_CALLS
SOAP_AUTHENTICATION_BASIC
(default) or SOAP_AUTHENTICATION_DIGEST
SOAP_SSL_METHOD_TLS
, SOAP_SSL_METHOD_SSLv2
, SOAP_SSL_METHOD_SSLv3
or SOAP_SSL_METHOD_SSLv23
Here are the methods that must be implemented and why:
If you do not want to implement all these methods, you can too create your own class that inherits from our AbstractSoapClientBase class.
This class is the base class for any EnumType
class generated by PackageGenerator. It implements our StructEnumInterface interface.
It defines two methods:
getValidValues
method.This class is the base class for any StructType
class generated by PackageGenerator. It implements our StructInterface interface.
It defines five methods:
var_export
. It also allows you to ease the instanciation of an object that contains many properties which would be hard to instanciate using the __construct
method. You can see __set_state
as an hydratation method.__set
but used by the __set_state
method. Plus, defining __set
method on used class by the classmap option for the SoapClient breaks the correct hydratation of your received objects.__get
. Used by our AbstractStructArrayBase class.$item = \Api\StructType\Item::__set_state([
'id' => 1,
'name' => 'Entity #1',
'label' => 'Entity #1',
'_href' => 'http://www.entity.com',
]);
// $item is now an \Api\StructType\Item object
This class is the base class for any ArrayType
class generated by PackageGenerator. It implements our StructArrayInterface interface.
As soon as you have an element that is an array of items such as:
$items = \Api\ArrayType\Items::__set_state([
'items' => [
\Api\StructType\Item::__set_state([
'id' => 1,
'name' => 'Entity #1',
'label' => 'Entity #1',
'_href' => 'http://www.entity-1.com',
]),
\Api\StructType\Item::__set_state([
'id' => 2,
'name' => 'Entity #2',
'label' => 'Entity #2',
'_href' => 'http://www.entity-2.com',
]),
\Api\StructType\Item::__set_state([
'id' => 3,
'name' => 'Entity #3',
'label' => 'Entity #3',
'_href' => 'http://www.entity-3.com',
]),
],
]);
// 'items' is the unique property of the object
// Its name is returned by the getAttributeName method
// defined in the generated \Api\ArrayType\Items class
count
, length
methods: gives you the number of items contained by your objectforeach ($items as $item) {
// $items->current() and $item is an \Api\StructType\Item object
// $items->key() is the current index
}
$items->first();
$items->last();
$items->item($index);
$items->add(\Api\StructType\Item::__set_state([
'id' => 4,
'name' => 'Entity #4',
'label' => 'Entity #4',
'_href' => 'http://www.entity-4.com',
]));
This class is the base class for any ServiceType
class generated by PackageGenerator.
Its goal is to provide utility/handful methods by implementing our SoapClientInterface interface.
It's basically a decorator design pattern as the class has the SoapClient object as a static property in order to be able to apply methods on it. It is a static property in order to have a singleton between multiple calls (allowing to send cookies automatically between calls). It can be reset by passing true as the second parameter.
Let's say you have this type of generate ServiceType
class:
namespace Api\ServiceType;
use \WsdlToPhp\PackageBase\AbstractSoapClientBase;
class ApiUpdate extends AbstractSoapClientBase
{
public function UpdateBulkOrder(\Api\StructType\ApiUpdateBulkOrder $parameters)
{
try {
$this->setResult($this->getSoapClient()->UpdateBulkOrder($parameters));
return $this->getResult();
} catch (\SoapFault $soapFault) {
$this->saveLastError(__METHOD__, $soapFault);
return false;
}
}
}
You can do:
use \WsdlToPhp\PackageBase\AbstractSoapClientBase;
$options = [
AbstractSoapClientBase::WSDL_URL => '__WSDL_URL__',
AbstractSoapClientBase::WSDL_CLASSMAP => \Api\ApiClassMap::classMap(),
];
// sets the first instance of SoapClient within AbstractSoapClientBase
$update = new \Api\ServiceType\ApiUpdate($options);
// resets the SoapClient instance
$update = new \Api\ServiceType\ApiUpdate($options, true);
Then call any of these base methods:
DOMDocument
version of the requestDOMDocument
version of the response$this->saveLastError(__METHOD__, $soapFault)
is calledSoapFault
object
$result = $update->UpdateBulkOrder(new \Api\StructType\ApiUpdateBulkOrder())
if ($result !== false) {
echo "\nThis is the result as an object:" . print_r($update->getResult(), true);
// Actually $result is the same data than $update->getResult()
} else {
echo "\nThis is the XML request:" . $update->getLastRequest(false);
echo "\nThese are the request's headers:" . $update->getLastRequestHeaders(false);
echo "\nThis is the XML response:" . $update->getLastResponse(false);
echo "\nThese are the response's headers:" . $update->getLastResponseHeaders(false);
echo "\nThese are the last errors:" . print_r($update->getLastError(), true);
echo "\nThis is the current error:" . print_r($update->getLastErrorForMethod('\Api\ServiceType\ApiUpdate::UpdateBulkOrder'), true);
}
You have additional methods such as:
// A sample of its usage in the generated ServiceType class
public function setSoapHeaderCSPCHD(\Api\StructType\ApiCSPCHD $cSPCHD, $nameSpace = 'http://tempuri.org', $mustUnderstand = false, $actor = null)
{
return $this->setSoapHeader($nameSpace, 'CSPCHD', $cSPCHD, $mustUnderstand, $actor);
}
Feel free to make some pull requests. We'll study them and let you know when it can be integrated.
You can run the unit tests with the following command:
$ cd /path/to/src/WsdlToPhp/PackageBase/
$ composer install
$ composer test
Thanks to the Docker image of phpfarm, tests can be run locally under any PHP version using the cli:
First of all, you need to create your container which you can do using docker-compose by running the below command line from the root directory of the project:
$ docker-compose up -d --build
You then have a container named package_base
in which you can run composer
commands and php cli
commands such as:
# install deps in container (using update ensure it does use the composer.lock file if there is any)
$ docker exec -it package_base php-7.4 /usr/bin/composer update
# run tests in container
$ docker exec -it package_base php-7.4 -dmemory_limit=-1 vendor/bin/phpunit
If you have a question, feel free to create an issue.
The MIT License (MIT). Please see License File for more information.