4
votes

I am trying to write my own SOAP server and to call methods via SoapClient(wsdl mode). I created methods in php, added an auto-generated wsdl file. I send request via SoapClient and server should work with Mysql and return results, but i am always getting empty response. I checked logs in MySQL and they show correct request that should return the data.

public function getCarMakes()
{
    $carMakesArr = array();
    $sql = "SELECT * FROM cars order by make";
    try
    {
        foreach($this->conn->query($sql) as $row)
        {
            $carMakesArr[] = array( $row[0], $row[1], $row[2]);
        }
    }
    catch(Exception $e)
    {
        echo $e->getMessage();
    }

        return $carMakesArr;
}

My WSDL file:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is Metro/2.3.1-b419 (branches/2.3.1.x-7937; 2014-08-04T08:11:03+0000) JAXWS-RI/2.2.10-b140803.1500 JAXWS-API/2.2.11 JAXB-RI/2.2.10-b140802.1033 JAXB-API/2.2.12-b140109.1041 svn-revision#unknown. -->
<definitions targetNamespace="http://wsdl.example.org/" name="ServerWS" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:tns="http://wsdl.example.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://wsdl.example.org/" schemaLocation="ServerWS_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="buyCar">
    <part name="parameters" element="tns:buyCar"/>
  </message>
  <message name="buyCarResponse">
    <part name="parameters" element="tns:buyCarResponse"/>
  </message>
  <message name="getCarMakes">
    <part name="parameters" element="tns:getCarMakes"/>
  </message>
  <message name="getCarMakesResponse">
    <part name="parameters" element="tns:getCarMakesResponse"/>
  </message>
  <message name="getCarDetailsById">
    <part name="parameters" element="tns:getCarDetailsById"/>
  </message>
  <message name="getCarDetailsByIdResponse">
    <part name="parameters" element="tns:getCarDetailsByIdResponse"/>
  </message>
  <message name="searchByParams">
    <part name="parameters" element="tns:searchByParams"/>
  </message>
  <message name="searchByParamsResponse">
    <part name="parameters" element="tns:searchByParamsResponse"/>
  </message>
  <portType name="ServerWS">
    <operation name="buyCar">
      <input wsam:Action="http://wsdl.example.org/ServerWS/buyCarRequest" message="tns:buyCar"/>
      <output wsam:Action="http://wsdl.example.org/ServerWS/buyCarResponse" message="tns:buyCarResponse"/>
    </operation>
    <operation name="getCarMakes">
      <input wsam:Action="http://wsdl.example.org/ServerWS/getCarMakesRequest" message="tns:getCarMakes"/>
      <output wsam:Action="http://wsdl.example.org/ServerWS/getCarMakesResponse" message="tns:getCarMakesResponse"/>
    </operation>
    <operation name="getCarDetailsById">
      <input wsam:Action="http://wsdl.example.org/ServerWS/getCarDetailsByIdRequest" message="tns:getCarDetailsById"/>
      <output wsam:Action="http://wsdl.example.org/ServerWS/getCarDetailsByIdResponse" message="tns:getCarDetailsByIdResponse"/>
    </operation>
    <operation name="searchByParams">
      <input wsam:Action="http://wsdl.example.org/ServerWS/searchByParamsRequest" message="tns:searchByParams"/>
      <output wsam:Action="http://wsdl.example.org/ServerWS/searchByParamsResponse" message="tns:searchByParamsResponse"/>
    </operation>
  </portType>
  <binding name="ServerWSPortBinding" type="tns:ServerWS">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="buyCar">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="getCarMakes">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="getCarDetailsById">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="searchByParams">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="ServerWS">
    <port name="ServerWSPort" binding="tns:ServerWSPortBinding">
      <soap:address location="http://localhost/soap/server.php"/>
    </port>
  </service>
</definitions>

My XML schema:

<xs:complexType name="getCarMakes">
    <xs:sequence>
      <xs:element name="id_array1" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="getCarMakesResponse">
    <xs:sequence>
      <xs:element name="return" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

My request via SoapClient:

$client = new SoapClient('http://localhost/soap/ServerWS.wsdl',
                        array('cache_wsdl' => WSDL_CACHE_NONE, 
                              'trace' => 1,
                              'soap_version' => SOAP_1_2)
                             );

try
    {

        $arr = (array)$client->getCarMakes();

        echo "<b>First method:</b> <br>";

    }
    catch(SoapFault $e)
    {
        echo $e->getMessage();
    }
    echo $client->__getLastRequest();
    echo $client->__getLastResponse(); 
     var_dump($arr);

It returns an empty array, however db is there and data is there. Request to db is correct, i initially created server in non-wsdl mode and it worked just fine.

My request:

<!--?xml version="1.0" encoding="UTF-8"?-->
<env:envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://wsdl.example.org/">
<env:body><ns1:getcarmakes></ns1:getcarmakes>
   </env:body></env:envelope>

The response, i get:

  <env:envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://wsdl.example.org/">
    <env:body><ns1:getcarmakesresponse></ns1:getcarmakesresponse>
    </env:body>
  </env:envelope>

Please advise.

2
What happens if you try both sides independantly ? First the getCarMakes() function to see the results it should return, and then the WSDL linked to a unit-test getCarMakes() function returning non-empty fixed data.Iansus

2 Answers

1
votes

There was at least no proper definition of complex types. Below is basic implementation which returns a list of available car makes (as array of strings). If return format should be different, definition of carMakesArray complex type should be adjusted accordingly.

Put the following files on the same level and replace your.host in all of them with the actual base URL at which these files will be accessible.

ServerWS.wsdl

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://your.host/"
             name="ServerWS"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:tns="http://your.host/"
             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:wsam="http://www.w3.org/2007/05/addressing/metadata"
>
    <types>
        <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://your.host/">
            <complexType name="carMakesArray">
                <complexContent>
                    <restriction base="soapenc:Array">
                        <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
                    </restriction>
                </complexContent>
            </complexType>

            <xsd:complexType name="getCarMakesResponse">
                <xsd:sequence>
                    <xsd:element name="return" type="tns:carMakesArray"/>
                </xsd:sequence>
            </xsd:complexType>        
        </xsd:schema>
    </types>

    <message name="getCarMakes" />
    <message name="getCarMakesResponse">
        <part name="parameters" element="tns:getCarMakesResponse"/>
    </message>

    <portType name="ServerWS">
        <operation name="getCarMakes">
            <input wsam:Action="http://your.host/ServerWS/getCarMakesRequest" message="tns:getCarMakes"/>
            <output wsam:Action="http://your.host/ServerWS/getCarMakesResponse" message="tns:getCarMakesResponse"/>
        </operation>
    </portType>

    <binding name="ServerWSPortBinding" type="tns:ServerWS">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="getCarMakes">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
    </binding>

    <service name="ServerWS">
        <port name="ServerWSPort" binding="tns:ServerWSPortBinding">
            <soap:address location="http://your.host/soapServerTest.php"/>
        </port>
    </service>
</definitions>

soapServerTest.php

<?php
require 'CarService.php';

$soapServer = new \SoapServer('http://your.host/ServerWS.wsdl', ['cache_wsdl' => WSDL_CACHE_NONE]);
$soapServer->setClass('CarsService');
$soapServer->handle();

CarService.php

<?php
class CarsService
{
    /**
     * @return string[]
     */
    public function getCarMakes()
    {
        /** Here you may extract data from DB and return instead of hard-coded values */
        return ['BMW', 'Ford', 'Honda'];
    }
}

soapClientTest.php

<?php
$client = new SoapClient(
    'http://your.host/ServerWS.wsdl',
    array(
        'cache_wsdl' => WSDL_CACHE_NONE,
        'soap_version' => SOAP_1_2
    )
);
try {
    $makes = $client->getCarMakes();
    var_dump($makes);
} catch (SoapFault $e) {
    echo $e->getMessage();
}
0
votes

The issue was with auto-generated WSDL:

  • I found the working WSDL.
  • Updated it with my complex types and voila, it worked.