Zend SOAP:在WSDL中将默认数组元素名称“item”更改为复杂类型的类名

this question might be asked, but it is so hard to search for, I just can not find anything about it. Plus it is not easy to ask.

I'm using Zend SOAP's autodiscover to re-create our old SOAP interface (because of switching to micro services and re-working everything).

So far it's working like a charm. But I have one problem in recreating the SOAP response of some services when using lists/arrays.

The old response XML of a SOAP request looked like this. It contains two <SMSEntry>s in the <SMSEntries> list.

<SOAP-ENV:Envelope>
   <SOAP-ENV:Body>
      <ns1:getSMSByTimeSpanResult>
         <AmountOfEntries>2</AmountOfEntries>
         <SMSEntries>
            <SMSEntry></SMSEntry>
            <SMSEntry></SMSEntry>
         </SMSEntries>
      </ns1:getSMSByTimeSpanResult>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

But the recreated response looks like this. It contains two <item>s of type SMSEntry in the <SMSentries> list.

<SOAP-ENV:Envelope>
   <SOAP-ENV:Body>
      <ns1:getSMSByTimeSpanResponse>
         <return xsi:type="ns1:getSMSByTimeSpanResponse">
            <AmountOfEntries xsi:type="xsd:int">2</AmountOfEntries>
            <SMSEntries SOAP-ENC:arrayType="ns1:SMSEntry[2]" xsi:type="ns1:ArrayOfSMSEntry">
               <item xsi:type="ns1:SMSEntry"></item>
               <item xsi:type="ns1:SMSEntry"></item>
            </SMSEntries>
            <DataEx xsi:nil="true"/>
         </return>
      </ns1:getSMSByTimeSpanResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I have no control of the clients. They might be checking for a SMSEntry with comparing the string. I want to use the class name SMSEntry for the XML-tag name.

Second, I would like to leave out the additional, wrapping everything, <return> tag.

I am using the autodiscover like this:

use Zend\Soap\AutoDiscover;
use Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeComplex;

$autoDiscover = new AutoDiscover(new ArrayOfTypeComplex());
$autoDiscover->setClass(new Standard($sm));

The getSMSByTimeSpanResponse is defined like this:

Standard.php

/**
 * Class getSMSByTimeSpanResponse
 *
 * @package LgxServiceManager\Service
 */
class getSMSByTimeSpanResponse
{
    /**
     * @var int
     */
    public $AmountOfEntries;

    /**
     * @var \LgxServiceManager\Service\SMSEntry[]
     */
    public $SMSEntries;
}

/**
 * Class SMSEntry
 *
 * @package LgxServiceManager\Service
 */
class SMSEntry
{
}

Does anybody have any idea on how to this?

I found some code in the library\Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence.php:122 Where the _addSequenceType() method is setting an attribute hardcoded:

$element->setAttribute('name', 'item');

But this is in type "Sequence" not type "Complex" like I'm using...

Thank you in advance, Philipp


\EDIT

oh man... I just discovered another structure which I don't know how to create with Zend SOAP's autodiscover...

 <mainMember1>SERIALNUMBER</mainMember1>
 <mainMember2>NAMEOFPRODUCT</mainMember2>
 <mainMember3>000000-000-0</mainMember3>
 <Rules>
    <RuleEntry>
       <singleValue>allow</singleValue>
       <ResourceList>
          <Name>generic</Name>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
       </ResourceList>
       <ResourceList>
          <Name>default</Name>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
          <ResourceEntry>[...]</ResourceEntry>
       </ResourceList>
    </RuleEntry>
 </Rules>

As you can see, there is a <singleValue> inside the <RuleEntry> but multiple <ResourceList>s. The same structure is used inside the resource lists: One <Name> and multiple <ResourceEntry>...

Is this even possible to handle with autodiscover?

For anyone still having above problem: Default response of stdClass() like this:

$array = ['lets', 'test', 'it'];
$response = new stdClass();
$response->results = $array;

Will be like:

 <return xsi:type="SOAP-ENC:Struct">
    <results SOAP-ENC:arrayType="xsd:string[3]" xsi:type="SOAP-ENC:Array">
       <item xsi:type="xsd:string">lets</item>
       <item xsi:type="xsd:string">test</item>
       <item xsi:type="xsd:string">it</item>
    </results>
 </return>

What we can do - we can change array to ArrayObject():

    $array = ['lets', 'test', 'it'];

    $response = new stdClass();
    $response->results = new ArrayObject();
    foreach($array as $item) {
      $response->results->append($item);
    }

which return:

         <return xsi:type="SOAP-ENC:Struct">
            <results xsi:type="SOAP-ENC:Struct">
               <BOGUS xsi:type="xsd:string">lets</BOGUS>
               <BOGUS xsi:type="xsd:string">test</BOGUS>
               <BOGUS xsi:type="xsd:string">it</BOGUS>
            </results>
         </return>

And finally the icing on the cake:

$array = ['lets', 'test', 'it'];

$response = new stdClass();
$response->results = new ArrayObject();
foreach($array as $item) {
    $soapVar = new SoapVar($item,XSD_STRING,NULL,NULL,'result');
    $response->results->append($soapVar);
}

It will return:

 <return xsi:type="SOAP-ENC:Struct">
    <results xsi:type="SOAP-ENC:Struct">
       <result xsi:type="xsd:string">lets</result>
       <result xsi:type="xsd:string">test</result>
       <result xsi:type="xsd:string">it</result>
    </results>
 </return>

As you can see the fifth argument tells what will be the key of xml element. You need to be aware of second argument too, becaouse it tells which is the type of variable. You can find more here: https://secure.php.net/manual/en/class.soapvar.php