Recently I wrapped a class up and provided it as a SOAP service. Getting it working was a bit of a struggle and its clearly not something that people are doing a lot of, so here's a quick roundup of the main issues and how I tackled each one.
Start Small - Build and Check A Class
I firstly built some unit tests using PHPUnit (more about that another day perhaps, but let me say it is excellent and I tumbled to it really easily once I'd started), then wrote my class and verified the tests were passing. This was to avoid trying to debug the PHP functionality through the added layer of the SOAP.
Simple SOAP Starting Point
My next step was to get a working SOAP service. This isn't remotely tricky except that PHP can't generate its own WSDL file (for extremely valid reasons but that doesn't help me), so you either need to write it by hand or you need to generate it somehow.
As my starting point I took the whole working code from this fantastic example and checked that it worked for me.
SOAP setClass() and WSDL Fiddling
Having got this far I changed my SOAP server code to use the setClass() method and pointed it at my own original class. I then hand-edited the WSDL (one function at a time) to reflect the data types and arguments that would be moving through the service.
The actual service code looks like this:
require_once('lib/myClass.php'); ini_set("soap.wsdl_cache_enabled", "0"); $server = new SoapServer("service.wsdl"); $server->setClass("MyClass"); $server->handle();
The example WSDL supplied by the JimmyZ tutorial has a single function in it at the early stages, and I started with that, then adapted it for one single function from the class. This is perfectly valid providing you don't try calling anything else! The PHP function declaration took this form:
The function returns two variables - it passes back the account ID and also returns information about the number of credits on the account. The accountID is a string of up to 8 characters, the other variable is a number. Here is the WSDL adapted for this purpose:
<?xml version ='1.0' encoding ='UTF-8' ?> <definitions name='MyClass' targetNamespace='urn:MyClassInventory' xmlns:tns='urn:MyClassInventory' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/' xmlns='http://schemas.xmlsoap.org/wsdl/'> <message name='getAccountStatusRequest'> <part name='accountID' type='xsd:string'/> </message> <message name='getAccountStatusResponse'> <part name='accountID' type='xsd:string'/> <part name='counter' type='xsd:float' /> </message> <portType name='MyClassPortType'> <operation name='getAccountStatus'> <input message='tns:getAccountStatusRequest'/> <output message='tns:getAccountStatusResponse'/> </operation> </portType> <binding name='MyClassBinding' type='tns:MyClassPortType'> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='getAccountStatus'> <soap:operation soapAction='urn:xmethods-delayed-quotes#getAccountStatus'/> <input> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </input> <output> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </output> </operation> </binding> <service name='MyClassService'> <port name='MyClassPort' binding='tns:MyClassBinding'> <soap:address location='http://rivendell.local:10002/MyClassServiceServer.php'/> </port> </service> </definitions>
Once I discovered that WSDLs are best read from end to beginning, I was able to expand the example above for all the other various functions I needed.
Hopefully this helps someone get started. There are various tools available for generating the WSDL, in particular try either George's suggestion, the offering from phpclasses.org, or check out the automatic generator in ZDE. Certainly there are tools available, but I didn't manage to find one that did the trick for me.
If you are writing, or have written, a SOAP service in PHP5 then drop a comment and let me know - I certainly felt like I was in a minority on this project. Similarly if I've missed anything then I'd appreciate comments so I know for next time.