Adding schema types in auto-generate WSDL

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi guys,

First off, apologies for the length of this post, but this is a weird problem that I need to fix pretty soon, I've exhausted my other options and I thought it best to supply slightly too much detail than not enough. In fact, I've written a whole new mini-web service just to facilitate this post! :-)

I'm using PHP/PEAR to develop quite a complicated web service, and I've run into a bit of a problem. Basically, I'm auto-generating the WSDL but I'm returning what are really complexTypes in my data that client code (well behaved .NET code that is fully RPC/encoded aware - so it's not a document/literal problem) is barfing on. I think I can fix it just by adding a schema to handle arrays in the <types> section of the auto-generated WSDL. However, the addSchemaFromMap is undocumented and I'm not sure if that's what I need.

Here's a sample piece of code (not what my real code is, as that's much more complicated, and you don't need to see it) implementing a user lookup function that takes a userid for a particular user, but if that is sent as zero, all users are returned:

<?php
require_once 'SOAP/Server.php';

// Then the class here
class MemberDatabase {
    var $__dispatch_map = array();

function MemberDatabase() {

// Define the signature of the dispatch map

        $this->__dispatch_map['GetUsers'] =
           array('in' => array('Userid' => 'integer'),
                 'out' => array('Member' => 'string'));
     }

     	// NOTE: I'm saying I'm returning a string, but I'm actually 		
	// going to return an array - this is needed because I have
	// several member "items" coming back...

function GetUsers($Userid){

          // Do my SQL lookup based on $Userid
          $stmt = "SELECT * FROM Users";
          if($Userid != 0)
              $stmt .= " WHERE Userid = '$Userid'";

          $link = mysql_connect("mymachine", "myusername", "mypass");
          mysql_select_db("StaffDB");
          $result = mysql_query($stmt);  // Do my query

	  $User = array();  // I'm going to fill this array with data...
          $ThisUser = array();
          while($row = mysql_fetch_array($result, MYSQL_ASSOC)){
              $ThisUser['Userid'] = $row['Userid'];
	      $ThisUser['Name'] = $row['Name'];
              $ThisUser['Email'] = $row['Email'];
              $ThisUser['Department'] = $row['Department'];

	       $User[] = $ThisUser;
          }
          mysql_close();  // Tidy up before leaving here
          return $User;
      }
}
// Fire up PEAR::SOAP_Server
$server = new SOAP_Server;

// Get the class in here
$MemberDatabaseServer = new MemberDatabase();

// Add the object to SOAP server
$server->addObjectMap($MemberDatabaseServer,'urn:MemberDatabase');

// Handle SOAP requests coming is as POST data
if (isset($_SERVER['REQUEST_METHOD']) &&
    $_SERVER['REQUEST_METHOD']=='POST') {
    $server->service($HTTP_RAW_POST_DATA);
} else {
    // Deal with WSDL / Disco here
    require_once 'SOAP/Disco.php';

    // Create the Disco server
    $disco = new SOAP_DISCO_Server($server,'MemberDatabase');
    header("Content-type: text/xml");
    if (isset($_SERVER['QUERY_STRING']) &&
        strcasecmp($_SERVER['QUERY_STRING'],'wsdl')==0) {
        echo $disco->getWSDL(); // this doles out wsdl when ?wsdl on end
    } else {
        echo $disco->getDISCO();
    }
    exit;
}
?>

This is all based on code grabbed from PhpPatterns in an article on auto-generating WSDL. If the above code lives at say, http://my.url/memberdb.php then I can get WSDL by accessing http://my.url/memberdb.php?wsdl - and the above code would work and would generate:

<?xml version="1.0" ?>
<definitions name="MemberDatabase" targetNamespace="urn:MemberDatabase" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"; xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"; xmlns:tns="urn:MemberDatabase" xmlns:xsd="http://www.w3.org/2001/XMLSchema"; xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"; xmlns="http://schemas.xmlsoap.org/wsdl/";>
<types xmlns="http://schemas.xmlsoap.org/wsdl/"; />
<portType name="MemberDatabasePort">
<operation name="GetUsers">
<input message="tns:GetUsersRequest" />
<output message="tns:GetUsersResponse" />
</operation>
</portType>
<binding name="MemberDatabaseBinding" type="tns:MemberDatabasePort">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"; />
<operation name="GetUsers">
<soap:operation soapAction="urn:MemberDatabase#memberdatabase#GetUsers" />
<input>
<soap:body use="encoded" namespace="urn:MemberDatabase" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
</input>
<output>
<soap:body use="encoded" namespace="urn:MemberDatabase" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
</output>
</operation>
</binding>
<service name="MemberDatabaseService">
<documentation />
<port name="MemberDatabasePort" binding="tns:MemberDatabaseBinding">
<soap:address location="http://www.iconoplex.co.uk/testusenet.php"; />
</port>
</service>
<message name="GetUsersRequest">
<part name="Userid" type="xsd:integer" />
</message>
<message name="GetUsersResponse">
<part name="Member" type="xsd:string" />
</message>
</definitions>


That's all great, and if you start up XMLSPY and tell it to use that, it parses just fine, and it will even generate a SOAP Request for you:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"; xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xmlns:xsd="http://www.w3.org/2001/XMLSchema";>
<SOAP-ENV:Body>
<m:GetUsers xmlns:m="urn:MemberDatabase" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";>
<Userid xsi:type="xsd:integer">0</Userid>
</m:GetUsers>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Now, remember I was telling the dispatch_map function I was returning a string, but really it was an array? Look what I get back when I send a request:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"; xmlns:xsd="http://www.w3.org/2001/XMLSchema"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"; xmlns:ns4="urn:MINTALF" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";>
<SOAP-ENV:Body>
<ns4:GetUsersResponse>
<return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="Struct[2]" SOAP-ENC:offset="[0]">
<item>
<Userid xsi:type="xsd:string">1</Userid>
<Name xsi:type="xsd:string">Paul Robinson</Name>
<Email xsi:type="xsd:string">paul@iconoplex.co.uk</Email>
<Department xsi:type="xsd:string">1</Department>
</item>
<item>
<Userid xsi:type="xsd:string">2</Userid>
<Name xsi:type="xsd:string">Another Paul Robinson</Name>
<Email xsi:type="xsd:string">paul@iconoplex.co.uk</Email>
<Department xsi:type="xsd:string">1</Department>
</item>
</return>
</ns4:GetUsersResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>


The line that seems to be confusing the client code we're testing with is:

<return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="Struct[2]" SOAP-ENC:offset="[0]">

What I'm thinking is how to add something into the WSDL defintion defining an array, and then setting the 'out' array to have
"Members" => "MyDefinedArray" instead of "string"


Suggestions please? If the correct answer helps me out and fixes the client code, if the sender should have an amazon wish list knocking around, I'm sure a small Christmas present would not be out of the question... it would be worth it to make this problem go away.

--
Paul Robinson

--
PHP Soap Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [PHP Users]     [Kernel Newbies]     [PHP Database]     [Yosemite]

  Powered by Linux