From YiPs Wiki (i powered)

I5: SOAP 101 I 5 Call

(click to open)

Quick Page Table of Contents

Scanning…

SOAP 101

Introduction

In this case we replaced the PHP view and control elements of the previous 101 examples with a SOAP service and we keep the same RPG back-end SRVPGM model.

What is SOAP?

(see the REST tutorial)

How does REST and SOAP compare?

(see the REST tutorial)

Is REST or SOAP better?

(see the REST tutorial)

Does PHP actively use WSDL at runtime?

Yes. In fact, the WSDL document plays an active role in parsing SOAP message data in/out of PHP variables. I generated my wsdl by hand, but you will likely use one of the many tools available to generate wsdl.

In PHP the type “xsd:array” works very well, but I am not exactly sure how well this type exports to/from language to language client/server. Anyway, if you can actually read the wsdl below, you probably don’t need this introductory tutorial at all (Dude!).

<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='SearchDvd'
  targetNamespace='http://example.org/SearchDvd'
  xmlns:tns=' http://example.org/SearchDvd '
  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/'>

<message name='soap_searchRequest'>
  <part name='browsetype' type='xsd:string'/>
  <part name='browse_title' type='xsd:string'/>
  <part name='browse_actor' type='xsd:string'/>
  <part name='browse_category' type='xsd:string'/>
  <part name='limit_num' type='xsd:integer'/>
</message>
<message name='soap_searchResponse'>
  <part name='items' type='xsd:array'/>
</message>

<portType name='SearchDvdPortType'>
  <operation name='soap_search'>
    <input message='tns:soap_searchRequest'/>
    <output message='tns:soap_searchResponse'/>
  </operation>
</portType>

<binding name='SearchDvdBinding' type='tns:SearchDvdPortType'>
  <soap:binding style='rpc'
    transport='http://schemas.xmlsoap.org/soap/http'/>
  <operation name='soap_search'>
    <soap:operation soapAction='urn:xmethods-delayed-search#soap_search'/>
    <input>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-search'
        encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-search'
        encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
</binding>

<service name='SearchDvdService'>
  <port name='SearchDvdPort' binding='SearchDvdBinding'>
    <soap:address location='http://myi5:89/qiwikiCode/anyserver.php'/>
  </port>
</service>
</definitions>

How do I turn my *SRVPGM into a SOAP service?

Our MVC pattern followed in the previous DVD example, makes a switch to SOAP web services fairly straight forward. We really just need to replace the PHP view/control code with a web services SOAP front-end instead of a user HTML front-end.

However, we are going to need both a SOAP client and a SOAP server to demonstrated the whole client/server cycle.

How do I make a SOAP server using the i5 toolkit to my RPG SRVPGM?

The SOAP server in this example will feedback a xsd:array to the SOAP client program. Using our MVC methods creating the server looks nearly identical to all of the other browser based clients.

As you can see we have removed all MVC reference to HTML and replaced the view/control with SOAP server components. However, we are keeping the i5 model to our RPG SRVPGM to search for DVD data (cool right?).

define('APP_BASE_DIR', '');
include_once APP_BASE_DIR.'101Config.php';            /* Site:    site configuration         */
include_once APP_BASE_DIR.'101Connecti5.php';         /* Model:   i5 toolkit connect         */
include_once APP_BASE_DIR.'101RPGModel.php';          /* Model:   i5 toolkit call RPG SRVPGM */
                                                      /* View:    no view                    */
include_once APP_BASE_DIR.'101SoapServerControl.php'; /* Control: main SoapServer handler    */

We also changed include_once HTML control to SOAP server control. It looks much the same as the browser version, except there is no view element, because the data returned is a raw PHP associative array.

<?php
// ------------------------
// Control: main
// ------------------------
post_mandatory 
( array 
  ( 'error', 'action', 'browsetype', 
    'browse_title', 'browse_actor', 
    'browse_category', 'limit_num'
  )
);
post_mandatory_array 
( array 
  ( 'selected_item', 'item' 
  ) 
);
function soap_search($browsetype, $browse_title, $browse_actor, $browse_category, $limit_num)
{ $items = array();
  $_POST['browsetype']      = $browsetype;
  $_POST['browse_title']    = $browse_title;
  $_POST['browse_actor']    = $browse_actor;
  $_POST['browse_category'] = $browse_category;
  $_POST['limit_num']       = $limit_num;
  model_search($browsetype, $browse_title, $browse_actor, $browse_category, $limit_num, $items);
  if ($_POST ['browsetype']) 
  { if (! model_search 
        ( $_POST ['browsetype'], 
          $_POST ['browse_title'], 
          $_POST ['browse_actor'], 
          $_POST ['browse_category'], 
          $_POST ['limit_num'], 
          $search_item 
         ))
    { $_POST ['error'] = model_error ();
      $items = array('error'=>$_POST ['error']);
    }
    else
    { $items = $search_item;
    }
  }
  else
  { $items = array('error'=>"no search data specified");
  }
  return $items;
}
?>

A key difference in the SOAP server over the browser versions is the server→handle() function that “handles” method call requests. We could have many methods callable from this single web service, but in this case we have only soap_search, which calls model_search for whatever model was included (i5/RPG, ibm_db2, etc.).

ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache
$server = new SoapServer("101soap_search.wsdl");
$server->addFunction("soap_search");
$server->handle();

Note: You may have noticed the “new” and “→” operator. Unfortunately SOAP applications are largely written in OO style, so you will have to get with OO to get with SOAP on PHP 5. If you find OO undesirable, I suggest you try REST style web services (previous tutorial).

How I do make a client to call a SOAP service?

Using our MVC pattern we can easily switch out a one of the other models (i5, ibm_db2, etc.), and replaced it with a SOAP client model that will “call” data from the SOAP server above.

Just like previous examples the browser will see HTML forms for search and list, completely unaware that we have actually called across the web to get the data from a SOAP server (cool). In fact, we just change to the SOAP client model, and leave all the other HTML control/view code “as is” (are you a MVC believer yet?).

<?php
define('APP_BASE_DIR', '');
$SOAPSERVER = "/qiwikiCode/101RPGSoapServer.php";
include_once APP_BASE_DIR.'101Config.php';            /* Site:    site configuration         */
include_once APP_BASE_DIR.'101ConnectSoap.php';       /* Model:   SOAP connect               */
include_once APP_BASE_DIR.'101SoapClientModel.php';   /* Model:   SOAP client                */
include_once APP_BASE_DIR.'101HtmlView.php';          /* View:    plain old generated html   */
include_once APP_BASE_DIR.'101HtmlControl.php';       /* Control: main loop html forms       */
?>

The wsdl often contains a correct location of the web services call, but this wiki is moving around systems so we will override for a more dynamic solution.

The first thing we need to do is figure out our SOAP service URL (location). For compare purposes we will stuff this code in the model_connect, even though it is more model_where (artistic license).

The connect code should produce a URL to call our SOAP service on this same box.

Example:
http://myi5:89/qiwikiCode/101RPGSoapServer.php
<?php
// ---------------------
// Model: connect
// ---------------------
function model_connect() 
{ global $MODEL, $SOAPSERVER;
  $service = "http://".$_SERVER["SERVER_NAME"];
  if (isset($_SERVER["SERVER_PORT"]))
  { $service .= ":".$_SERVER["SERVER_PORT"];
  }
  $service .= $SOAPSERVER;
  $MODEL ['conn'] =  $service; 
  return True;
}
function model_error_soap($error = "") 
{ model_error($error);
}
?>

We now have a fully formed URL to call our SOAP service.

?php
function model_search($browsetype, $browse_title, $browse_actor, $browse_category, $limit_num, &$items) 
{ global $MODEL, $categories;
  if (!model_connect ()) 
  { False;
  }
  $link_id = $MODEL ['conn'];
  $client = new SoapClient("101soap_search.wsdl",array('location' => $link_id));
  try 
  { $items = $client->soap_search($browsetype, $browse_title, $browse_actor, $browse_category, $limit_num);
    if (!isset($items) || isset($items['error']))
    { model_error_soap("soap_search");
      return False;
    }
  } 
  catch (SoapFault $exception) 
  { model_error_soap("soap_search $exception");
    return False;
  } 
  return True;
}
?>

Done!

Retrieved from http://youngiprofessionals.com/wiki/index.php/I5/SOAP101I5Call
Page last modified on January 10, 2013, at 01:37 PM EST