1

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>

2 Answers 2

2

You can fix this by enabling SOAP_SINGLE_ELEMENT_ARRAYS on your SoapServer:

$server = new SoapServer('wsdl.xml', [
    'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
]);
Sign up to request clarification or add additional context in comments.

Comments

0

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?

1 Comment

Hi, thanks. I just use the SoapServer class of PHP, so there is nog generator class. But i did fix it with your code. Visual Studio was still complaining that I couldn't use the array encodingtype is WS-I-mode. After long a long search i found that I also had to change the encoding type in the <binding> section to "encoded" instead of "literal".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.