As the title said, I had to create a SOAP Server on a Kohana3 (KO3) Framework recently, and I decided to share my experience. Up until now I was always using NuSoap or just generating the wsdl file by hand, to avoid any problems, but this time I decided to experiment with Zend AutoDiscovery class. This class came a long way from Zend Framework (ZF) 1.7 where it first appeared. Most of the problems are fixed now, and it looks like it can get the job done. I will provide small description of what it does, shamelessly ripped from the documentation for it:
It constructs object similar to object used in SOAP server application, extracts necessary information and generates correct WSDL using this information.
The beauty of Kohana is that is very simple to use classes from Zend Framework, and it is not so big as the aforementioned framework.
Let’s start by downloading ZF from the official site here. Make sure that you will download version which holds all the library files required.
After you download the package, just unzip it and navigate to the “library” folder.Copy the “Zend” folder from it. This is the folder that contains all the additional classes, including our “AutoDiscovery” class.
For those who want to get the bare minimum of files, you need only few of the files from the “Zend” folder to make this work:
/Soap -> The whole folder
Exception.php
Uri.php
Now navigate to the place of your KO3 file system and to put the library files into \application\vendor\Zend
At this point the folder Zend won’t exist, so you will have to either paste the whole folder “Zend” you took from ZF, or create it and place the aforementioned files there.
Now that we have the files, we need to create a controller which will direct our requests, and a model which will supply the data served back to the controller on every request. The controller will include Zend AutoDiscovery class which will create the wsdl on the fly, based on the methods in the model.
So, let’s create controller “Soap” in \application\classes\controller folder and include the files needed from the ZF library. The code for the controller is below.
<?php defined('SYSPATH') or die('No direct script access.'); /** * include the library files and the model */ ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.APPPATH.'vendor/'); include Kohana::find_file('vendor','Zend/Soap/AutoDiscover'); include Kohana::find_file('vendor','Zend/Soap/Server'); include Kohana::find_file('classes','model/service'); class Controller_Soap extends Controller { /** * Soap controller * * @param void * @return void */ public function __construct() { // The default headers are set to html by default Request::$instance->headers['Content-Type'] = 'text/xml; charset='.Kohana::$charset; } /** * Soap service * * @param void * @return void */ public function action_service() { // disable wsdl cache ini_set('soap.wsdl_cache_enabled', '0'); $wsdl = 'http://' . $_SERVER['HTTP_HOST'] . '/soap/wsdl'; $server = new SoapServer($wsdl); $server->setClass('Model_Service'); $server->handle(); } /** * Soap wsdl * * @param void * @return void */ public function action_wsdl() { // disable wsdl cache ini_set('soap.wsdl_cache_enabled', '0'); $wsdl = new Zend_Soap_AutoDiscover(); $wsdl->setOperationBodyStyle(array('use' => 'literal','namespace' => 'http://framework.zend.com')); $wsdl->setUri('http://' . $_SERVER['HTTP_HOST'] . '/soap/service'); $wsdl->setClass('Model_Service'); $wsdl->handle(); } }
Please make a note that Zend AutoDiscovery is not an actual SOAP server. You still need to create the SOAP server by using
$server = new SoapServer($wsdl);
What Zend AutoDiscovery does is to auto generate the wsdl based on the phpdoc blocks found in the registered class
$wsdl->setClass('Model_Service');
where Model_Service serves as a “gateway” to all the available methods in the SOAP server. They will be registered and documented automatically based on the documentation provided for them.
Let’s create the model which will serve the data back to us:
<?php /** * include the library files and the model */ class Model_Service extends Model { /** * default constructor * * @param void * @return void */ public function __construct() { parent::__construct(); } /** * Method Name and Documentation * @param string $foo * * @return string */ public function DoSomething($foo) { return (string) $foo; } } ?>
This will auto generate the wsdl with one registered method (DoSomething
), that will take one argument ($foo
) and return it to the client. All the public functions will be considered as API methods. If you want to add a function that will not be exposed, make sure that you will make it private
.At this point you should have a fully working SOAP Server, which can be consumed by pointing your client to {Sitename}/soap/wsdl
And the last thing you need to do is to create the client for it using the built-in SOAP function:
<?php $wsdl = "http://{Sitename}/soap/wsdl" $client = new SoapClient($wsdl ,array( "trace" => 1, "exceptions" => 0)); $functions = $client->__getFunctions(); foreach($functions as $function) { print_r($function); } $client->DoSomething('test'); print "<pre>"; print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n"; print "Response:\n".htmlspecialchars($client->__getLastResponse())."\n"; print "</pre>"; ?>
The client will display all the available methods for the service with __getFunctions()
and it will execute the only method available at this time DoSomething()
passing a string argument 'test'
Then it will display the last request to the SOAP server and the last response from it.
If you don’t have a php client coded yet, you can always use a third party software like SoapUI to test your server. My personal preference for testing SOAP is a Firefox plugin called “SOA Client” which can be downloaded here.
The only problem I have seen with this approach is that .Net client created by Visual Studio can have a hard time connecting and consuming the service, but that can be fixed using the correct instantiation of the Service class. More on the subject here.