StephenCuppett.com

Helpful Notes and Major Milestones

Using SOAP (non-REST) web services with CakePHP

leave a comment »

I recently had a need to support a complex SOAP web service from CakePHP.  Cake provides some built-in support for REST based web services; however, this situation required more.  This post should show how to set this up on your own projects and still utilize all your normal controller and model goodness without too much screwing around.

Pleas see this attachment for the source code described in this article.

The method I will outline here requires the php-soap module.

First, the WSDL.  For my project, I started with a WSDL created in another tool.  My WSDL specifies a slightly different object set than my CakePHP application.  I’m sure with PHP5 and some finessing of the Model classes, you could probably use the same set; however, it was easy enough to just create some really vanilla objects to house the transport objects and use those to communicate with the webservice.  Both the WSDL and the receiving controller are present in the attachment.

What you will notice is that the *DTO objects defined in the controller file reciprocate the structure of the objects in the WSDL and the methods also are represented in the controller.  I put them in the controller file because it wasn’t really obvious to me where in Cake’s structure “outside code” should really go.  I have a separate configs.inc.php I pull in up the class hierarchy, but that’s about as non-conventional as I want to get.  Also, this controller is dedicated to just handling webservice requests and I only need these *DTO objects in that case, so locality wins and they are here.  No real engineering genius here, their structure mimics what is defined in the WSDL file.

The real magic is in the controller.  The controller’s remote() method is what handles the POST from the web via the port binding in the WSDL file.  The remote() function sets up some of the basic stuff for SoapServer and is easily identified in the PHP manual.  It’s even pretty easy to deduce we’re going to need to use SoapServer->setClass() somewhere and plug the name of our Controller in.   However, there was one tidbit in the comments section of the manual regarding SoapServer->setObject().  It wasn’t documented (at the time), but after experimenting and looking at the PHP source, it does exactly what we need here, sets the handling class to an instantiated (aka existing) class object instead of trying to spawn a new one.  Because we are already inside the CakePHP framework and running the remote() function, we already have the variables we want from beforeFilter(), we have our models loaded up, we may even have a user context from mod_auth_something.  Perfect!!!  So, we tell SoapServer to use our instantiated Controller.  Once the *DTO classes are mapped and SoapServer is configured, it’s as simple as having it handle STDIN to tickle the rest of the methods in your Controller with the parameters populated.  Two more tricks/problems remain:  debug level & autoRender.

First, debug level.  There’s bound to be a way around it; however, since I test with a web service client, when I do have a problem, I have to debug with lots of $this->log() calls.  Turning up debugging to 1 or 2 is problematic because then CakePHP doesn’t spit back properly formed XML to the web service client and usually the client takes a SoapFault when that happens.  I stick to debug level of 0 during development and deployment wrt the web service stuff.

Second, autoRender.  Because SoapServer does the actual outputting of XML response to the client, I set the layout in the Controller to Ajax and also explicitly call exit() at the end of the remote() method.  This ensures that CakePHP doesn’t send back a “Missing View”, half rendered $layout, or any other kind of automatic goodies.

I hope this article is helpful for anybody who might want/need to integrate a more elegant/esoteric webservice into their CakePHP architectures.  I’m sure there are probably cleaner ways to put this into custom View classes, utilize Components, etc… however, this was a straightforward approach I found has been working really well for one of my applications.


Written by cuppett

July 27, 2009 at 8:51 pm

Posted in Development, Research

Leave a Reply