My key concept is: create the SOAP server in the Controller and the methods in the Model. Why? Because controller is … (read this) and model is this.
As an example here we gonna make web service for Post of a Blog (see Blog Tutorial) using native SOAP in PHP version 5.
We’ll put the SOAP handler at URL: http://yourhost/posts/service and the WSDL (which is will be used by the SOAP consumer) at URL: http://yourhost/posts/wsdl.
- Create table Post (see the Blog Tutorial for details).
- Create Post model (models/post.php) as usual.
- Create Post controller (controllers/posts_controller.php), see bellow. You need RequestHandler component for create XML-type response on wsdl action.
- Create view for action “wsdl” (views/posts/wsdl.ctp) and define your service method in it. You can publish all of methods in Post model including from its parent (AppModel), eg. findById(), find(), findAll(), etc. Note: you should turning off “short_open_tag” in php.ini to avoid error on rendering the xml of wsdl view. And don’t forget to define your service address in the WSDL to http://yourhost/posts/service.
- Now your service consumer could consume your service by pointing to your WSDL URL (http://yourhost/posts/wsdl).
Here are the sample codes:
models/post.php
<?php
class Post extends AppModel {
/**
* Example method
* @param string
* @return string
*/
function yourMethod($inputParam) {
return "Your input is {$inputParam}";
}
}
?>
controllers/posts_controller.php
<?php
class PostsController extends AppController {
var $components = array('RequestHandler');
function service() {
$this->layout = false;
$this->autoRender = false;
Configure::write('debug', 0);
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
$server = new SoapServer('http://yourhost/posts/wsdl');
$server->setClass("Post");
$server->handle();
}
function wsdl() {
$this->layout = false;
Configure::write('debug', 0);
$this->RequestHandler->respondAs('xml');
}
}
?>
views/posts/wsdl.ctp
<?xml version='1.0' encoding='UTF-8'?>
<definitions name='YourTNS'
targetNamespace='YourTNS'
xmlns:tns='YourTNS'
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/'>
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ecerami.com/schema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<complexType name="ArrayOfString">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="string[]"/>
</restriction>
</complexContent>
</complexType>
</schema>
</types>
<message name='findByIdRequest'>
<part name='PostId' type='xsd:string'/>
</message>
<message name='findByIdResponse'>
<part name='Result' type='xsd:ArrayOfString'/>
</message>
<message name='yourMethodRequest'>
<part name='inputParam' type='xsd:string'/>
</message>
<message name='yourMethodResponse'>
<part name='Result' type='xsd:string'/>
</message>
<portType name='PostPortType'>
<operation name='findById'>
<input message='tns:findByIdRequest'/>
<output message='tns:findByIdResponse'/>
</operation>
<operation name='yourMethod'>
<input message='tns:yourMethodRequest'/>
<output message='tns:yourMethodResponse'/>
</operation>
</portType>
<binding name='PostBinding' type='tns:PostPortType'>
<soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
<operation name='findById'>
<soap:operation soapAction='urn:your-urn'/>
<input>
<soap:body use='encoded' namespace='urn:your-urn'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:your-urn'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
<operation name='yourMethod'>
<soap:operation soapAction='urn:your-urn'/>
<input>
<soap:body use='encoded' namespace='urn:your-urn'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</input>
<output>
<soap:body use='encoded' namespace='urn:your-urn'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
</output>
</operation>
</binding>
<service name='PostService'>
<port name='PostPort' binding='PostBinding'>
<soap:address location='http://yourhost/posts/service'/>
</port>
</service>
</definitions>
Update
I was using CakePHP version 1.2.0.6311 beta and PHP version 5.2.3.
Hi, just found your article and I’m trying to follow it. Which cakephp version did you use?
I’m getting a Fatal error: Call to undefined method RequestHandlerComponent::respondAs() in D:\Web\xampp\htdocs\cake\iwsl\controllers\artigos_controller.php on line 16
Hi, this is a great tutorial. I tried it on my windows system and it worked perfectly. The problem is when i tried to move it to a linux server, i keep getting this error output in the browser.
ML parsing failed: syntax error (Line: 1, Character: 0)
Reparse document as HTML
Error:missing root element
Specification:http://www.w3.org/TR/REC-xml/
I appreciate any help…
@Aaron, where (which URL) you got that error? If it about XML of the WSDL, maybe you didn’t set “Off” the value of “short_open_tag” directive in your php.ini. The value must be “Off” because short_open_tag (<?) violate XML’s open tag.
Looks great – I had the same idea and was wondering, if anybody did it like this… I am still testing – btw there are some smilies in the representation of the code – would you mind offering the code in a separate zip file for downloading to avoid the blog text filter to destroy the code? THANKS!!!