Implementing SOAP on cakePHP

By Shawn Cook aka "scook"
I have recently (last week) started using cakePHP. I choose cake because it works with AMFPHP and because I thought cake had built in support for web services (including soap). I'm not complaining, but I was somewhat disappointed to find out that support for web services is limited to routing, which I could not get to work anyway...

Requirements


So, I set off on my quest to implement soap. In brief, my requirement were:
1.Serve soap
2.Automatically generate and serve wsdl
3.Handle complex types in method calls and return values
4.Work within the cakePHP framework
5.Easy to implement and easy to use

Serve Soap


Since I use php5 and because I plan to generate the wsdl separately, I choose to use the soap server/client included with php5.
http://us2.php.net/manual/en/ref.soap.php

WSDL


For generating wsdl I choose to use Webservice helper from David Kingma:
http://www.jool.nl/new/1,webservice_helper.html

Cake Integration


I began by trying to create a component that would grab soap requests and redirect them to a soap view. While this may work, and it would be very cake-ish, it seemed like a lot of work and not very soap-ish. I immediately ran into problems getting arguments from the soap request into the method I was calling. Soap requests generally do not use separate addresses for each method call, and they send arguments in the soap envelope, which is not parsed into the data (post or get) variable. Based on this, it seems to me that the cake view methodology and the cake component methodology do not mesh nicely with soap.

As a side note; These problems could be overcome if the cake core would parse and return soap envelopes, but that seems like a task for the cake development team rather than a hack like me!

After I beat my head against the wall for a while, I realized that my first course of action was doomed to fail; I decided to try creating one Controller that would handle all soap method calls, and wsdl requests. This seems to work. This technique is very class centric, soap methods will be grouped and accessed by their controller name.

The main challenge here is to get the soap arguments out of the soap envelope so that they can be passed to the controller method. At first glance you might think you could simply use the SoapServer to call the controller method. Like this:
Download code
<?php
$server 
= new SoapServer($wsdlfile);
$server->setClass('MyControllerClass');
$server->handle();
?>

The problem is that this method would NOT call the controller within the cake framework. I'm no cake expert, but I don't think this would produce the expected results.

Somehow we need to get the soap arguments and then call the controller method using the cake requestAction method.
Download code
<?php
$server 
= new SoapServer($wsdlfile);
$server->setClass('HandleSoapClass');
$server->handle();
?>

My handle soap class looks like this:
Download code
<?php
class HandleSoapClass{
    
/** @var AppController */
    
static $controller;

    
/** @var string */
    
static $wsClassName;
    
    function 
__call $func_name$args ){
        return 
self::$controller->requestAction('/'.substr(self::$wsClassName,0,-10).'/'.$func_name.'/soap5/', array('pass'=>$args) );
    }
}
?>

If you are unfamiliar with __call, please see the php site.http://us3.php.net/manual/en/language.oop5.overloading.php

This class basically passes any method call to the appropriate controller class by means of the cake requestAction method. And on the way it sends the soap arguments.

Maybe that seems obvious to you, but I thought it was pretty cool...

The other option would be be to:
  1. Parse the soap envelope
  2. create php vars or objects
  3. run the function
  4. then construct a return soap envelope

Ick...That does not sound like fun!

Below is an overview of the whole process.
Download code
+---soap client request wsdl from uri:mydomain.com/soap5/wsdl/ControllerName
|   |
|   +---soap5Controller's wsdl method requests the wsdl from WebServiceHelper
|       and returns the wsdl document
|   
+---soap client calls soap method from uri: mydomain.com/soap5/serve/ControllerName
    |
    +---soap5Controller's serve method receives the request and passes it to a 
        |php5 SoapServer
        |
        +---SoapServer passes the request to a dummy class
        |
        +---Dummy class parses the soap arguments and uses the cake requestAction 
            |method to call the real soap method
            |
            \---requestAction returns the results back to the dummy file and 
                SoapServer outputs the soap response back to the client

Page 2: Example

Comments 137

CakePHP team comments Author comments

Comment

1 Fantastic

Fantastic article, thanks a lot.

One comment about securty: I've noticed that a lot of the public web services and api's have a login method which returns a "session id" which is then used on every other method. This helps as the login method can be done over SSL and the rest of them will be faster done over normal HTTP. In that way the username and password are not transferred in clear text over HTTP.
posted Wed, Nov 8th 2006, 01:04 by Mladen Mihajlovic

Comment

2 Nice

Hi Shawn,

I've also implemented some SOAP services using CakePHP. But I have slightly different way to do it.

First of all I made the wsdl files manually (using Eclipse tools). It's quite important for me to have full control over my wsdl files.

Each SOAP service (port) has it's own controller, called soap_service_name_controller and there is route to each soap service and wsdl file defined in the `routes.php`.

It's simple way to link SOAP services defined in wsdl file with cake controllers.

When I find some spare time I will put an article describing my way of implementing SOAP services.
posted Fri, Jan 19th 2007, 10:41 by Wojtek Oledzki

Question

3 Code and usage instructions

Are the code and usage instructions available yet? The snippets give me a pretty good idea of how to re-create the setup but something more concrete would be really helpful. Thanks!
posted Wed, Dec 31st 1969, 18:00 by James Kao

Comment

4 Example request

Hi Shawn,

I've also implemented some SOAP services using CakePHP. But I have slightly different way to do it.

First of all I made the wsdl files manually (using Eclipse tools). It's quite important for me to have full control over my wsdl files.

Each SOAP service (port) has it's own controller, called soap_service_name_controller and there is route to each soap service and wsdl file defined in the `routes.php`.

It's simple way to link SOAP services defined in wsdl file with cake controllers.

When I find some spare time I will put an article describing my way of implementing SOAP services.


Can you post your way of doing SOAP service on top of cakePHP? Would be intrested to see that.
posted Tue, May 15th 2007, 08:30 by Leo Jokinen

Login to Submit a Comment