views:

185

answers:

1

I've encountered a few different WSDL files that contain an element and a complexType with the same name. For example, http://soap.search.msn.com/webservices.asmx?wsdl has two entities named "SearchResponse":

In this scenario, I can't figure out how to properly map those entities to PHP classes using the SoapClient() "classmaps" option.

The PHP manual says this:

The classmap option can be used to map some WSDL types to PHP classes. This option must be an array with WSDL types as keys and names of PHP classes as values.

Unfortunately, since there are two WSDL types with the same key ('SearchResponse'), I can't figure out how to differentiate between the two SearchResponse entities and assign them to their corresponding PHP classes.

For example, here is the relevant snippet of the example WSDL:

<xsd:complexType name="SearchResponse">
    <xsd:sequence>
        <xsd:element minOccurs="1" maxOccurs="1" name="Responses" type="tns:ArrayOfSourceResponseResponses"/>
    </xsd:sequence>
</xsd:complexType>

<xsd:element name="SearchResponse">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element minOccurs="1" maxOccurs="1" name="Response" type="tns:SearchResponse"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:element>

And here is the PHP that obviously would not work since the classmaps keys are the same:

<?php $server = new SoapClient("http://soap.search.msn.com/webservices.asmx?wsdl", array('classmap' => array('SearchResponse' => 'MySearchResponseElement', 'SearchResponse' => 'MySearchResponseComplexType'))); ?>

In searching for a solution, I found Java Web Services handles this by allowing you to specify a custom suffix to the "Element" or "ComplexType" entities.

http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.5/tutorial/doc/JAXBUsing4.html#wp149350

So, right now I feel like there is just no way to do it with PHP's SoapClient, but I'm curious if anyone out there can offer any advice. FWIW, I cannot edit the remote WDSL.

Any ideas???

+1  A: 

This is off the top of my head, but I think you could have both SearchResponse types map to MY_SearchResponse and try and abstract the difference between the two. It's kludgy, but something like this maybe?

<?php
//Assuming SearchResponse<complexType> contains SearchReponse<element> which contains and Array of SourceResponses
//You could try abstracting the nested Hierarchy like so:
class MY_SearchResponse
{
   protected $Responses;
   protected $Response;

   /**
    * This should return the nested SearchReponse<element> as a MY_SearchRepsonse or NULL
    **/
   public function get_search_response()
   {
      if($this->Response && isset($this->Response))
      {
         return $this->Response; //This should also be a MY_SearchResponse
      }
      return NULL;
   }

   /**
    * This should return an array of SourceList Responses or NULL
    **/
   public function get_source_responses()
   {
      //If this is an instance of the top SearchResponse<complexType>, try to get the SearchResponse<element> and it's source responses
      if($this->get_search_response() && isset($this->get_search_response()->get_source_responses()))
      {
         return $this->get_search_response()->get_source_responses();
      }
      //We are already the nested SearchReponse<element> just go directly at the Responses
      elseif($this->Responses && is_array($this->Responses)
      {
         return $this->Responses;
      }
      return NULL;
   }
}

class MY_SourceResponse
{
  //whatever properties SourceResponses have
}

$client = new SoapClient("http:/theurl.asmx?wsdl", array('classmap' => array('SearchResponse' => 'MY_SearchResponse', 'SourceResponse' => 'MY_SourceResponse')));
Kayla Rose
This is pretty interesting. I've been playing with this and it's working fairly well. I just had to get past the fact that I have to use the same class for both types of entities.
stereointeractive.com
Also... I think sending Soap requests to the server using class like would not work, but I could imagine creating a method that would output the appropriate parameters for depending on which soap element it is representing and send that instead. Thanks for your detailed example.
stereointeractive.com
Yeah, that's fairly ambiguous naming strategy on the WS providers' part. I'm glad I could be of some help though.
Kayla Rose