Snippets

Create an account or login to be able to add, comment and rate snippets.

Navigation

Soap server

This has been tested with the version ( 1.0.0beta4 ), I had a bit different structure for older version.

Ok ... here we go... how to create a soap server and take advatage of symfony's models and actions.

First we need the soap environment file, this will be the file that will initiate the soap API environment and the soap server:

name: /web/soapapi.php (soap server)

<?php
 
define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
define('SF_APP',         'fo');
define('SF_ENVIRONMENT', 'soap');
define('SF_DEBUG',       true);
 
require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');
 
ini_set("soap.wsdl_cache_enabled", "0");
$server = new SoapServer('http://www.example.com/soapapi.wsdl'); //this file is defined in the next step
$server->setClass("mySoapController"); // more to come on this one
$server->handle();
 
?>

Now we need a wsdl file that will take advantage of the environment above.

name: /web/soapapi.wsdl (soap server definition)

<?xml version='1.0' encoding='UTF-8'?>
<definitions name="soapapi" targetNamespace="urn:soapapi" xmlns:typens="urn:soapapi" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/">
   <message name="getFactorial">
      <part name="user" type="xsd:string">user name</part>
      <part name="password" type="xsd:string">user password</part>
      <part name="number" type="xsd:float">user password</part>
   </message>
   <message name="getFactorialResponse">
      <part name="return" type="xsd:float"/>
   </message>   
   <portType name="soapapiPortType">
      <operation name="getFactorial">
         <documentation>
            user            required
            password            required
 
            Generates the factorial of a passed number.
         </documentation>
         <input message="typens:getFactorial"/>
         <output message="typens:getFactorialResponse"/>
      </operation>
   </portType>
   <binding name="soapapiBinding" type="typens:soapapiPortType">
      <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="getFactorial">
         <soap:operation soapAction="urn:soapapiAction"/>
         <input>
            <soap:body namespace="urn:soapapi" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
         </input>
 
         <output>
            <soap:body namespace="urn:soapapi" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
         </output>
      </operation>      
   </binding>
   <service name="soapapiService">
      <port name="soapapiPort" binding="typens:soapapiBinding">
         <soap:address location="http://www.example.com/soapapi.php"/>
      </port>
   </service>
</definitions>

Now we need to write our soap cotroller layer and that is the class that is asssigned by the soap server above.

name: /apps/fo/lib/mySoapController.class.php

<?php
 
class mySoapController extends sfController {
 
   public $request;
 
   public function __construct(){
      /**
       * Since we're bypassing Symfony's action dispatcher, we have to initialize manually.
       */
      $this->context = sfContext::getInstance();
      $this->request = $this->context->getRequest();
   }
 
   protected function soapAuth($domain,$password){
     try {
 
       $c = new Criteria();
       $c->add(UserPeer::USERNAME ,$domain);
       $c->add(UserPeer::PASSWORD ,$password);
 
       $check = UserPeer::doSelectOne($c);
 
       if($check){
         $user = $this->context->getUser();
         $user->addCredential($check->getCredential());
         $user->setAuthenticated(true);
       }else{
         throw new Exception('Soap Authentication failed');
       }
     }catch (Exception $e){       
       throw new SoapFault("1",$e->getMessage());
     }
   }
 
   function getFactorial($user, $password, $number){
 
     $this->soapAuth($user, $password); //I call this at the start of each function call in the soap controller (You can choose not to do it)
     $this->request->setParameter('number',$number);
 
     $action = $this->getAction('soapapi','getFactorial');
     $result = $action->executeGetFactorial();
 
     return $result;
   }
}
?>

We are almost there ... Next we need action and view

name: /apps/fo/modules/soapapi/actions.class.php

<?php
 
class soapapiActions extends sfActions
{
  public function __construct(){
    if(SF_ENVIRONMENT == 'soap') $this->initialize(sfContext::getInstance());
  }
 
  public function executeIndex()
  {
    $this->forward('default', 'module');
  }
 
  public function executeGetFactorial(){
 
    $num = $this->getRequestParameter('number');
 
    $result = 1;
    for($i=1;$i<$num;$i++) $result = $result + ($result * $i);
 
    if(SF_ENVIRONMENT == 'soap') return $result; //you can return the view or just a number... usually for soap you want to return simple stuff ... so you need to do the check
 
    $this->result = $result;
 
  }
}
 
?>

finally the view...

name: /apps/fo/modules/soapapi/getFactorialSuccess.php

<?php
 
echo "The factorial for ".$sf_params->get('number')." is {$result} ";
 
?>
by Fuad Arafa on 2007-01-18, tagged soap 

Comments on this snippet

gravatar icon
#1 Fuad Arafa on 2007-03-07 at 02:13

Please note: I have also tested this with the stable 1.0 and works like a charm.

gravatar icon
#2 Francois Zaninotto on 2007-03-07 at 10:56

Fuad, I strongly recommend you to package this as a plugin.

gravatar icon
#3 Fuad Arafa on 2007-04-02 at 08:28

Hi Francois,

That is a swell idea... if you can send me some ideas/pointers I would really appreciate it. And if you like to undertake the plugin project yourself I have no issues or objections ;-)...

gravatar icon
#4 Francois Zaninotto on 2007-04-03 at 11:58

Fuad: I can only recommend the book chapter about plugins (Chapter 17 - http://www.symfony-project.com/book/trunk/17-Extending-Symfony) and having a look at existing plugin code (http://trac.symfony-project.com/trac/browser/plugins) for inspiration. If you have a problem, send a mail to the mailing-list and we'll give you a hand.

gravatar icon
#5 Thomas Klopf on 2007-05-16 at 11:39

Hello, this isn't working, I copied verbatim from above and get: PHP Fatal error: Call to a member function get() on a non-object in /usr/share/php/symfony/action/sfComponent.class.php on line 146

This is version 1.0.2 of symfony I'm using. Please can someone update snippet with fix?

gravatar icon
#6 Thomas Klopf on 2007-05-16 at 11:42

Sorry, please ignore above post, I forgot to copy something to action class. Please delete if you can.. Thanks.

gravatar icon
#7 excessive demon on 2008-01-18 at 06:41

Hi Fuad,

thank your for this code! But do you think, there is a way to get the view as a SOAP result? I have just finished a module, that should be available via HTTP as well as via SOAP, but as far as I can see, there's now way to this :-(

Thanx for any hint! Eddie

gravatar icon
#8 Fuad Arafa on 2008-02-21 at 10:36

Hi Excessive demon,

I don't see why not! it will all depend on your wsdl definition e.g. xsd:string response can easily be accomodated. However When you have multiple consumers to the same request, you can only go so far in re-using your code. evidently when you have multiple clients to your application ( e.g. Browser and soap client) and each has a different response needs, you'll need to take care of it :-)

I hope this helps.

gravatar icon
#9 Nicolas MARTIN on 2008-03-18 at 11:25

Hello,

Is there a way to use the action/template system for SOAP results ?

I was thinking about something like that : $result = $this->getPresentationFor('soapApi', 'getFactorial')

instead of : $action = $this->getAction('soapapi','getFactorial'); $result = $action->executeGetFactorial();

Because the current code bypass the template engine.

Unfortunatly I can't find a way to get that work.

Any ideas ?

gravatar icon
#10 excessive demon on 2008-11-18 at 03:06

Hello everybody, I'm a newbie in the Symfony world, I tried to adapt this snippet to my project but i don't find any config.php file in the path: SF_ROOT_DIR./.'apps'./.SF_APP./.'config'./

I'm using Symfony v1.1.4 do you think this snippet is compatible with my version? Has someone a SoapServer included in a Symfony project?

Thanks to Fuad for this snippet and thanks in advance to the community.

gravatar icon
#11 Gabriel Vrabie on 2008-11-27 at 02:06

Hello. I tested this snippet on Symfony 1.1 but I have a problem. The idea is that, in the soapController / constructor method, I have a problem with the context. Symfony tell me that the "default" context does not exists. Well, I believe is true because of the fact that is not really a http request. However, someone have an idea !?

Thank you

gravatar icon
#12 Gabriel Vrabie on 2008-11-27 at 02:28

Actually, to avoid this issue, you have to create the instance, using sfContext object in the file that will initiate the soap API environment, before the sequence where you initiate the SOAP Server

For this use sfContext::createInstance($your_project_configuration);

gravatar icon
#13 dinesh on 2009-02-19 at 05:47

Hi, I implemented the code in symfony 1.2 but I have an issue. The issue is with the line

$action = $this->getAction('soapapi','getFactorial');

I get the following result

<faultcode>SOAP-ENV:Server</faultcode> <faultstring>Call to a member function getConfiguration() on a non-object</faultstring>

It works without this line, but then I cant forward the request to the action method

Any ideas?

You need to create an account or log in to post a comment or rate this snippet.