简体   繁体   中英

WSDL PHP Soapserver array and complex type request

I have created a soap server in php with PHP Soapserver. I have created a function 'addItems' to add multiple items as an array in the first argument and a corresponding wsdl document. In the wsdl I've created an array object 'items' like this:

<s:complexType name="items"> 
        <s:sequence> 
            <s:element nillable="true" name="item" type="tns:item" minOccurs="0" maxOccurs="unbounded"/> 
        </s:sequence> 
     </s:complexType> 

The php function is just a simple class method passed to the php soapserver like this:

<?php
class Test
{
     public function addItems($items) {
         print_r($items);
     }
}
$service = new Test();
$server = new SoapServer('wsdl.xml');
$server->setObject();
print($server->handle());  

The problem it the way php soapserver handles the array. When I add just one item the items list isn't returned as an array. When i add two items the array of items is stored in a an item element instead of the expected items argument.

I tried using soapenc:array, but that seems incompatible with WS-I compliance as mentioned in http://www.ws-i.org/Profiles/BasicProfile-1.0-2004-04-16.html#refinement16556272 and also it fails when I want the add the service to visual studio when I use this type of encoding.

So what I'm doing wrong? I think i have to change the wsdl somewhere but couldn't find a working example. Or do I have to set some options for soapserver? I'm lost.

Below follows the request, actual result and expected result:

Request with one item:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:addItems" xmlns:wsdl="http://base.shopzonline.com/soap/api/test/?wsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:addItems>
         <items>
            <!--Zero or more repetitions:-->
            <wsdl:item>
               <wsdl:id>1</wsdl:id>
               <wsdl:name>a</wsdl:name>
            </wsdl:item>

         </items>
      </urn:addItems>
   </soapenv:Body>
</soapenv:Envelope>

actual result for $items argument

    Array
    (
        [item] => Array
        (
             [id] => 1
             [name] => a
        )
    )

expected result for $items argument

Array
    [0] => (
        Array
           (
                [id] => 1
                [name] => a
            )
    )

Request with multiple:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:addItems" xmlns:wsdl="http://base.shopzonline.com/soap/api/test/?wsdl">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:addItems>
         <items>
            <!--Zero or more repetitions:-->
            <wsdl:item>
               <wsdl:id>1</wsdl:id>
               <wsdl:name>a</wsdl:name>
            </wsdl:item>

            <wsdl:item>
               <wsdl:id>2</wsdl:id>
               <wsdl:name>b</wsdl:name>
            </wsdl:item>          
         </items>
      </urn:addItems>
   </soapenv:Body>
</soapenv:Envelope>

actual result for $items argument

Array
(
    [item] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => a
                )

            [1] => Array
                (
                    [id] => 2
                    [name] => b
                )

        )
)

expected result

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => a
        )

    [1] => Array
        (
            [id] => 2
            [name] => b
        )
)

Below the full WSDL:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions  name="LocalhostTestWebservice"
 targetNamespace="http://localhost/soap/api/test/?wsdl" 
 xmlns="http://schemas.xmlsoap.org/wsdl/"
 xmlns:tns="http://localhost/soap/api/test/?wsdl"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:s="http://www.w3.org/2001/XMLSchema"
   >
   <wsdl:types>
      <s:schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://localhost/soap/api/test/?wsdl">
         <s:complexType name="addItemsResponseElement">
            <s:sequence>
               <s:element name="result" minOccurs="0" type="s:int"/>
            </s:sequence>
         </s:complexType>
         <s:element name="addItemsResponseElement" nillable="true" type="tns:addItemsResponseElement"  />
         <s:complexType name="item">
            <s:sequence>
               <s:element name="id" type="s:string" /> 
               <s:element name="name" type="s:string" /> 
            </s:sequence>
         </s:complexType>
         <s:element name="item" type="tns:item" />
         <s:complexType name="items"> 
            <s:sequence> 
                <s:element nillable="true" name="item" type="tns:item" minOccurs="0" maxOccurs="unbounded"/> 
            </s:sequence> 
         </s:complexType>
         <s:element name="items" type="tns:items" />
      </s:schema>
  </wsdl:types>
  <wsdl:message name="addItemsRequest">
     <wsdl:part name="items" type="tns:items" />
  </wsdl:message>
  <wsdl:message name="addItemsResponse">
     <wsdl:part name="parameters" type="tns:addItemsResponseElement"/>
  </wsdl:message>
  <wsdl:portType name="TestPortType">
    <wsdl:operation name="addItems">
      <wsdl:input message="tns:addItemsRequest" />
      <wsdl:output message="tns:addItemsResponse" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="LocalhostTestWebserviceBinding" type="tns:TestPortType">
 <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="addItems">
         <soap:operation soapAction="addItems" />
         <wsdl:input>
             <soap:body use="literal" namespace="urn:addItems" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
         </wsdl:input>
         <wsdl:output>
             <soap:body use="literal" namespace="urn:addItems" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
         </wsdl:output>
     </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="LocalhostTestWebservice">
    <wsdl:port name="LocalhostTestWebservicePort" binding="tns:LocalhostTestWebserviceBinding">
      <soap:address location="http://localhost/api/soap/test/" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

You can fix this by enabling SOAP_SINGLE_ELEMENT_ARRAYS on your SoapServer:

$server = new SoapServer('wsdl.xml', [
    'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
]);

I didn't test this solution, but you can check:

In your message part:

<message name="getItemsResponse">
    <part name="items" type="ns:ArrayOfItems"/>
</message>

Types part:

<xsd:schema targetNamespace="http://foo.bar/objectsoapserver/types"
            xmlns="http://foo.bar/objectsoapserver/types">
    <xsd:complexType name="ArrayOfItems">
        <xsd:complexContent>
            <xsd:restriction base="soapenc:Array">
                <xsd:attribute ref="soapenc:arrayType" soap:arrayType="ns:Items[]"/>
            </xsd:restriction>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:complexType name="Items">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:element name="id" type="xsd:int"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:element name="Items" nillable="true" type="ns:Items"/>
</xsd:schema>

BTW. Why don't you use the library to generate WSDL automatically?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM