Welcome Guest, Not a member yet? Register   Sign In
Creating SOAP service, issue with Controller
#1

[eluser]stevefink[/eluser]
Hi all,

I created a demo SOAP service that I plan to build out a complete Web API for on top of Code Igniter for my application. My SOAP service works just fine when I slap together some scripts, however, when it comes time to add the stuff into CI, stuff breaks.

An example of my Controller looks like the following:

Code:
<?php

class Soap extends Controller {
    
    function Soap()
    {
        parent::Controller();
        
        /**
         * Start SOAP service
         */                  
        $server = new SoapServer('http://foo/path/to/bar.wsdl');
        $server->addFunction('Demo');
        $server->handle();
    }                    
    
    function Demo($param1)
    {
        return 'Request received with param1 = ' . $param1;
    }  
    
}

When I call my client side code, I get the following error output:

Fatal error: SOAP Fault: (faultcode: SOAP-ENV:Server, faultstring: SoapServer::addFunction() [<a href='function.SoapServer-addFunction'>function.SoapServer-addFunction</a>]: Tried to add a non existant function 'Demo') in /www/ll-prod-api/api/soap.php on line

It appears it doesn't recognize my function Demo() at all.

I've also tried using something similar to:

Code:
$server->addFunction($this->Demo);

It would be great if I can get my SOAP functionality working in this fashion as then I can leverage my models for the business logic of the web service. Then I can create rest.php, xmlrpc.php and so on. The beauty of MVC.

If anyone can point me in the correct direction, that would be sweet.

Thanks all!
#2

[eluser]stevefink[/eluser]
Hate to reply to my own post, but I've made some progress which looks positive. I am indeed getting a respone back from my SOAP server with the right string. However, SOAP still throws an Exception because Code Igniter throws the following output,

Code:
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;404 Page Not Found&lt;/title&gt;
&lt;style type="text/css"&gt;

body {
background-color:    #fff;
margin:                40px;
font-family:        Lucida Grande, Verdana, Sans-serif;
font-size:            12px;
color:                #000;
}

#content  {
border:                #999 1px solid;
background-color:    #fff;
padding:            20px 20px 12px 20px;
}

h1 {
font-weight:        normal;
font-size:            14px;
color:                #990000;
margin:             0 0 4px 0;
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    <div id="content">
        <h1>404 Page Not Found</h1>
        <p>The page you requested was not found.</p>    </div>
&lt;/body&gt;
&lt;/html&gt;

This is what it typically throws out for 404s or whatever. However, in this case, there isn't a URL. I just have the URI convention of http://foo/soap where SOAP is my controller. It is indeed there. Any idea how to correct this behavior?

I'm also seeing the following in CI logs:

ERROR - 2008-06-22 21:09:40 --&gt; 404 Page Not Found --&gt;
ERROR - 2008-06-22 21:09:40 --&gt; Severity: Warning --&gt; Cannot modify header information - headers already sent by (output started at /www/ll-prod-api/system/application/controllers/soap.php:14) /www/ll-prod-api/system/application/errors/error_404.php 1


It doesn't indicate which page is 404 -- as far as the headers already sent, that's the SOAP server doing so.. then CI tries to send additional ones with the 404 page.
#3

[eluser]Unknown[/eluser]
I'm not sure if you figured this out yet or if this is even your problem because you've got a lot of things going on there.

You can't have any headers (i.e. &lt;html&gt;...) or whitespace before your server.

I've only been working with SOAP for about 2 days, so, I really don't know much...

Check this out for a demo:

soapclient.php

Code:
&lt;?php

ini_set("soap.wsdl_cache_enabled", "0");

require_once('lib/nusoap.php');

if ($_GET['line'])
{
    $line = $_GET['line'];
}



$c = new soapClient('http://localhost/soap/soapserv.php?wsdl');


$back = $c->__soapCall('getProductLine', array('line' => $line));


print_r ($back);

?&gt;


soapserv.php

Code:
&lt;?php

//DON'T FORGET TO CHANGE DB USER/PASS

ini_set("soap.wsdl_cache_enabled", "0");
require('lib/nusoap.php');



function getCityState($id) {

    mysql_connect('localhost','root','PASSWORD');
    mysql_select_db('sample');
    $query = "SELECT * FROM customers "
           . "WHERE customerNumber = '$id'";
    $result = mysql_query($query);

    $row = mysql_fetch_assoc($result);

    return $row['city'] . ", " . $row['state'];

}

function getFirstLast($id) {

    mysql_connect('localhost','root','PASSWORD');
    mysql_select_db('sample');
    $query = "SELECT * FROM customers "
           . "WHERE customerNumber = '$id'";
    $result = mysql_query($query);

    $row = mysql_fetch_assoc($result);

    return $row['contactLastName'] . ", " . $row['contactLastName'];
    }

function getProductLine($line) {
    if ($line)
        {
        mysql_connect('localhost','root','PASSWORD');
        mysql_select_db('sample');
        $query = "SELECT * FROM products WHERE"
        . " productLine = '$line'";
        $result = mysql_query($query);
    
            while ($row = mysql_fetch_assoc($result))
            {
                $pline[] = $row;
            }
            if (mysql_num_rows($result) == 0 || mysql_num_rows($result) == NULL)
            {
                return $pline = array("error" => "Please Select Product Line.");
            }
            else
            {
            return $pline;
            }

        }
}



$server = new soap_server();

$server->configureWSDL('GetCityState', 'urn:getcitystate');

$server->register("getCityState",
                array('id' => 'xsd:string'),
                array('return' => 'xsd:string'),
                'urn:getcitystate',
                'urn:getcitystate#getCityState');

$server->register("getFirstLast",
                array('id' => 'xsd:string'),
                array('return' => 'xsd:string'),
                'urn:getfirstlast',
                'urn:getfirstlast#getFirstLast');

$server->register("getProductLine",
                array('line' => 'xsd:string'),
                array('return' => 'xsd:Array'),
                'urn:getproductline',
                'urn:getproductline#getProductLine');
                
                
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA)
                      ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?&gt;


Make sure you change the DB user and
Code:
$c = new soapClient('http://localhost/soap/soapserv.php?wsdl');
to where ever you put it.


You'll need the nusoap from sourceforge if you don't have it.


Get the server working and then put one space at the top of the file. You'll get the same error. So you can't wrap the server in html either.

I dunno, hope that helps someone. It would have saved me some time if I found that out yesterday.

Also, you can use the sql file I attached to build a MySQL sample database to work with the server. The data is pretty good, saves me a lot of time creating dummy data.


---Edit: The 150k limit blocked the .sql sample database. I've changed the extension to txt to fix that.
#4

[eluser]Nathan Pitman (Nine Four)[/eluser]
[quote author="stevefink" date="1214199569"]I just have the URI convention of http://foo/soap where SOAP is my controller. It is indeed there. Any idea how to correct this behavior?[/quote]

Have you tried adding the controller/function and intended URL to your routes.php file? Would be interested to know if you got this all working?
#5

[eluser]Unknown[/eluser]
I want to offer simple method for those who'll get here from google, because I haven't seen anything like this when was looking for advice.

Creating SOAP services even with CodeIgniter is easy. You don't need nusoap, don't waste your time.
I'll take code from OP.
Code:
&lt;?php
class Soap extends Controller {
    
    public function Soap()
    {
        parent::Controller();                
        $server = new SoapServer('http://foobar.wsdl');
        $server->setObject($this);
        $server->handle();
    }                    
    
    public function add($a, $b)
    {
        return $a + b;
    }
}

Now you can call any public function from your Soap controller with Soap request. If you need hidden implementation - use private or protected. Anyway you won't be able to call function which wasn't described in WSDL.

And remember that return values must be properly described in WSDL. If you have any difficulties (and you will, I promiseSmile) -- read specs, use gui tools, for example Eclipse plugin which provides gui for designing WSDL (built-in in PDT afaik) and soapUI for testing your service.

Links:
http://wiki.eclipse.org/index.php/Introd...SDL_Editor
http://www.soapui.org/
#6

[eluser]tastatura[/eluser]
Ok, I have one question.

I have to implement SOAP client in Codeigniter. Every xml request has authentication header : user, pass, licenece. There aree several methods on server side which I can call.
I am thinking on creating one model for every method on server side, but how can i do that using DRY principle for Authentication ?


Thanks!!!
#7

[eluser]danmontgomery[/eluser]
Put the authentication in the construct.

Code:
public function __construct() {
    $this->_client = new SoapClient($this->_wsdl, array('login' => $this->_user, 'password' => $this->_passwd));
}

I prefer to make api calls with __call, so that I don't have to define a method for each soap method.

Code:
public function __call($method, $args) {
    if(is_a($this->_client, 'SoapClient')) {
        $response = call_user_func_array(array($this->_client, $method), $args);

        // do something with $response
    }

    return FALSE;
}

If you need to pass authentication in each call, you can skip the construct part and just add those parameters in __call, where you call the method




Theme © iAndrew 2016 - Forum software by © MyBB