About the Author

author photo

Adam Trachtenberg is the Director of the LinkedIn Developer Network, where he oversees developer relations and marketing for the LinkedIn Platform. Before LinkedIn, Adam worked at eBay in platform product management and marketing. Even earlier, he co-founded Student.Com and TVGrid.com. Adam is the author of PHP Cookbook and Upgrading to PHP 5. He lives in San Francisco.

See All Posts by This Author

eBay SOAP Update: Syntax Matters

I saw a request for some actual SOAP code, so I will try and oblige. I don’t want to publish the entire code because there’s lots of messy stuff that’s specific to eBay’s SOAP API. I’ll talk about that some other time, but for now, those details just get in the way.

Therefore, I’ll pull out a few lines, combine that with some hand waving, and just hope for the best. Here’s the before:


$wsdl = 'http://developer.ebay.com/webservices/latest/eBaySvc.wsdl';
$client = new SoapClient($wsdl);

$params = array('Query' => 'ipod');
$results = $client->GetSearchResults($params);

foreach ($results->SearchResultItemArray->SearchResultItem as $item) {
  print $item->Item->Title . "\n";
}

Without the classmap option, I create a SoapClient, make my request, and then iterate through the results to print out the titles of the matching items. This isn’t complex; however, the iteration is a little klunky due to limitations of SOAP and the design of eBay’s Web service.

For example, the SearchResultItemArray only contains SearchResultItem, so it’s kludgy to reference SearchResultItemArray->SearchResultItem. Likewise, when I’m just getting a quick dump of Item information, it’s not so nice to specifically access the Title element.

By defining a couple of classes and telling the SoapClient object map them to the return data, I can clean this up:


class eBaySearchResultItemArrayType implements IteratorAggregate {
  public function getIterator( ) {
    return new ArrayObject($this->SearchResultItem);
  }
}

class eBaySearchResultItemType {
  public function __toString() {
    return $this->Item->Title . "\n";
  }
}

$wsdl = 'http://developer.ebay.com/webservices/latest/eBaySvc.wsdl';
$options = array('classmap' => array(
  'SearchResultItemArrayType' => 'eBaySearchResultItemArrayType',
  'SearchResultItemType' => 'eBaySearchResultItemType',
  ),
);

$client = new SoapClient($wsdl, $options);

$params = array('Query' => 'ipod');
$results = $client->GetSearchResults($params);

foreach ($results->SearchResultItemArray as $item) {
  print $item;
}

To solve my first problem, the iteration, I make eBaySearchResultItemArrayType implement the IteratorAggregate interface. When a PHP 5 class implements this interface, PHP will invoke the getIterator() method during a foreach loop.

In this case, I return $this->SearchResultItem, wrapping it inside an ArrayObject to make the array iterable.

For the pretty-printing issue, I define a __toString() method inside of eBaySearchResultItemType. Now, when I print an instance of this class, PHP calls that method instead.

With my classes defined, I use the classmap option to map the PHP classes to the SOAP complexTypes, and pass this mapping along as part of the second parameter to the SoapClient constructor.

Once this is set up, everything else in the request is identical. However, when I print out the results, the syntax is clean:


foreach ($results->SearchResultItemArray as $item) {
  print $item;
}

At one level, this is just syntax and icing. However, I don’t think you should dismiss syntax with a wave of your hand. To quote Sam Ruby on C# and LINQ:

[S]yntax matters. Very much so.

So, I am convinced that this is a good thing to spend time on. There are a couple other tricks I’ve pulled out, such as:


class eBayFeesType implements ArrayAccess {

  public function offsetGet($offset) {
    foreach ($this->Fee as $value) {
      if ($value->Name == $offset) {
        return $value;
      }
    }
  }

  /* and the other interface methods... */
}

class eBayFeeType {
  public function __toString() {
    return (string) $this->Fee->_;
  }
}

This lets me do:


echo "Listing fee is: ", $results->Fees['ListingFee'], "\n";

Which I must say is far nicer than either iterating in place or even calling out to a utility method.

I was interested to discover that I needed to manually cast $this->Fee->_ to a string because I thought it was a string. Actually, it is a float, and PHP won’t autocast floats to strings in this instance.

Personally, I think if PHP should autocast here, but I can see the logic. If you’re promising to return a string, you should actually return one.

At first, I was writing each class by hand. But that got boring and wasn’t scalable. Therefore, my new goal is to automate this process. I am writing a script to read the WSDL file, parse out the complexTypes, and then convert them to PHP classes.

My original script was using the SoapClient::__getTypes() method as a pre-processor, but I needed to parse that output again to get it into a usable format. After a little digging, I discovered that PEAR::SOAP implements its own parsing routines and gives me a far more flexible PHP data structure to manipulate. So, I am going in that direction instead.

Since this is a one-time action, speed isn’t vital, so it’s okay that PEAR::SOAP is written in PHP.

If you’re interested in more details on these new PHP 5 features, they’re documented in the PHP Manual. Alternatively, in a shameless plug, you can check out my book Upgrading to PHP 5.

Popularity: 6% [?]

There Are 4 Responses So Far. »

  1. Aww….no direct link to me? :)

  2. Oops. I fixed the link. It should have gone directly to you. :)

  3. I am having some difficulty with getting values out of an array pulled from the FindItemsAdvanced ebay call and wondered if you had a minute to help me? May I contact you directly?

  4. boudga –

    I have not spent that much time using our Shopping APIs.

    Therefore, I think the best thing is for you to post a message to the eBay Developer Forums (http://developer.ebay.com/forums/) and ask your question there. There are a number of eBay and non-eBay developers who monitor those boards.

    If you don’t get an answer in three days, drop me a line and I’ll try to give you a hand. My e-mail address is my first name at my last name dot com.

Post a Response