Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using PHP SoapClient classmap option with WSDL containing an element and complexType with the same name

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???

like image 335
stereoscott Avatar asked Sep 24 '10 04:09

stereoscott


1 Answers

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')));
like image 151
Kayla Rose Avatar answered Sep 22 '22 09:09

Kayla Rose