thekid/rfc — Issue #113: RFC 0113: Include PHP5 SOAP extension
Author: thekid
Created: 2011-10-09 15:10:56+00:00
State: open
Labels: implemented, rfc

Scope of Change
====
To make XP's SOAP implementation co-exist with the PHP5 SOAP extension,
the following classes must be renamed:
. webservices.soap.SoapHeader
. webservices.soap.SoapClient

as they clash with classes brought in by the extension (which we cannot
change).

The following classes will be moved from

webservices.soap.SOAPHeaderElement.class.php
webservices.soap.SOAPMapping.class.php
webservices.soap.SOAPNode.class.php
webservices.soap.SOAPHeader.class.php
webservices.soap.XPSoapClient.class.php

into their own subpackage of webservices.soap

webservices.soap.xp.SOAPHeaderElement.class.php
webservices.soap.xp.SOAPMapping.class.php
webservices.soap.xp.SOAPNode.class.php
webservices.soap.xp.XPSOAPHeader.class.php
webservices.soap.xp.XPSoapClient.class.php

Rationale
====
XP provides its own SOAP support which is enterprise-proven, but is not
a feature-complete SOAP implementation. Furthermore, it makes use of
class names that PHP5 ext/soap also uses. You must not compile PHP with
SOAP and use XP SOAP with the same PHP installation.

Despite of that, it'd be a good addition to provide an interface to let
the programmer decide which SOAP implementation he wants to use as the
back-end without having to care about the decision in what he does.

Functionality
====

Migration steps
----
In the first step - to clear the way - the above mentioned classes will
be prefixed with XP.

Second, the SOAP API will follow the Factory Pattern, so new clients will
not be constructed directly, but instanciated through a factory, or a driver
manager similar to what the XP framework offers in the rdbms package.

Third, it has become a common practice to derive particular SOAP clients
from class SOAPClient when generating or writing the client class. Due to
the changes mentioned before, this is not possible any more then, because
the derivation will bind the class to a certain SOAP implementation.
Instead, clients should become simple objects with a $client member that
gets inserted on object instantiation through the factory.

Implementation details
----

A new class webservices.soap.SoapDriver will be introduced that serves
as a factory for SOAP implementations:

```php
forEndpoint(
'http://somesoapservice/is/here/',
'urn:someSoapMethod'
);
?>
```

This will create an instance of the SoapDriver using the XPSoapClient (which
is the default driver). The SOAP call itself will not be changed.

Generally, SoapDriver is a singleton that also offers to register
additional soap implementations, if available.

The SoapDriver class therefore offers the following public methods:
. getInstance()
. availableDrivers()
. forWsdl($endpoint, $preferred= NULL)
. forEndpoint($endpoint, $preferred= NULL)
. driverName()

The $preferred argument allows to denote a preferred implementation,
which will be used whenever it is available and supports the requested
features (WSDL).
Otherwise the first feature-supporting implementation will be chosen.

The operation mode normal / WSDL mode is switched by using the forWsdl()
method:

```php
fromWsdl('http://somesoapservice/is/here/');
?>
```

WSDL is only supported by the PHP5-soap-extension and not by the XPSoapClient.

Backwards compatibility
----

A) Programming
Due to the renaming of the class SOAPClient to XPSoapClient, there will
be a BC-break.

Generated SOAP-client classes must:
. extend Object (legacy: extend webservices.soap.SOAPClient)
. create a $client member in their constructor through the
SoapDriver factory class
. implement all invocation methods through the $client member

When this is the old constructor call:

```php
registerMapping(
new QName('http://namespace', 'SoapValue'),
XPClass::forName('you.wanna.map.to.this.class')
);
}
?>
```

it will change to:

```php
client= SoapDriver::getInstance()->forEndpoint(
$endpoint,
'urn:SomeThing',
SoapDriver::XP
);

$this->client->registerMapping(
new QName('http://namespace', 'SoapValue'),
XPClass::forName('you.wanna.map.to.this.class')
);
}
?>
```

The third parameter of the fromEndpoint() method is the preferred driver.
Build-in constants for the drivers are XP (for the XPSoapClient) and
NATIVE (for the PHP5 extension). The preferred driver is optional.

Notice that in a manner of while-we're-at-it, XPSOAPClient's constructor
will also be changed and no longer takes a SOAPHTTPTransport object, but
the raw endpoint string, as practice showed that there is no other
transports being actively used.

This is how a standard method call in the client will look:

```php
client->invoke(
'someSoapFunction',
new Parameter('foo', new SoapLong($foo))
);
}
?>
```

B) Data structures
While a lot of effort has been dedicated to creating two equivalent (from
and outside perspective) SOAP implementations, not all details could be
kept compatible.

+ XP's own SOAP implementation turns SOAPStructs into plain PHP arrays,
which provide features other programming languages only know for hashmaps.

+ PHP's SOAP implementation will deserialize a SOAPStruct as a StdClass object.

This means that when exchanging the implementation, one must take care of
this incompatibility. Unfortunately, ext/soap provides a way to map that
SOAPStruct to other classes, there is no way to map it to an plain array.

WSDL
----

```php
client= SoapDriver::getInstance()->forWsdl($endpoint);

$this->registerMapping(
new QName('http://namespace', 'SoapValue'),
XPClass::forName('mapped.class')
);
}
?>
```

Of course the $endpoint string now needs to point to the WSDL-file.

WSDL is only supported in the native soap client, so the SoapDriver
automatically chooses the native Soap Client (if it's was enabled at
PHP compile time).

In the above example SoapDriver will switch automatically to the
NATIVE driver, because XP-Soap is not capable of WSDL.

Security considerations
====
n/a

Speed impact
====
n/a

Dependencies
====
n/a

Related documents
====
- http://experiments.xp-framework.net/?arena,rfc0113/
Reference implementation for this RFC

Comments
====
- kiesel, Wed Feb 7 13:12:36 CET 2007
Should the SoapClient receive an URL as first parameter instead of a
SOAPHTTPTransport in the future? Not like there was ever a need for a
different transport that that.

- rene, Fri Mar 16 13:19:16 CET 2007
Should SOAPHeaderElement also be renamed for consistencies sake?

- kiesel, Mon Apr 9 17:35:58 2007
Maybe all SOAP implementations should implement a single interface
SoapImplementation.