Skip to content

Instantly share code, notes, and snippets.

@kaylarose
Created February 8, 2011 23:01
Show Gist options
  • Save kaylarose/817482 to your computer and use it in GitHub Desktop.
Save kaylarose/817482 to your computer and use it in GitHub Desktop.
Basic SOAP Client with Debugging Features and Dynamic API Method Invocation
/**
* Basic SOAP Debugging and Service Discovery Methods for Programming Against SOAP Services
*/
abstract class ADebuggable_Soap_Client extends SoapClient
{
protected $_cached_apis;
/**
* Output some useful info about this SoapClient Instnace or State
*/
public abstract function debug();
/**
* Verify Whether the Specified API is actually available at the SOAP Service
* @param string $api_name
* @return BOOL
*/
public function api_exists($api_name)
{
$apis = $this->apis();
return (isset($apis[trim($api_name)]));
}
/**
* Get all API methods that we can execute on this service
*
* This will return a hash of available APIs and their contracts as defined in the WSDL
* e.g array(
* 'myMethodName' => 'myMethodName(int $nameOfparam1)',
* 'myComplexMethodName' => 'myMethodName(myMethodName $argHash)' //the arg should be a stdClass or hash array
* );
*
* Note: This is particularly useful for reflection of objects to PHP Classes
* @return array
*/
public function apis()
{
if(!$this->_cached_apis || empty($this->_cached_apis))
{
$functions = $this->__getFunctions();
$api_hash = array();
foreach($functions as $info)
{
//Funtion info looks like 'registerForSystemEventsResponse registerForSystemEvents(registerForSystemEvents $parameter)'
$pos = strpos($info, " ");
//So split it into classname and defined contract ino
$method = trim(substr($info, 0, $pos));
$contract = trim(substr($info, $pos));
if(!isset($api_hash[$method]))
{
$api_hash[$method] = $contract;
}
}
$this->_cached_apis = (!empty($api_hash)) ? $api_hash : array();
}
return $this->_cached_apis;
}
/**
* Get the Last SOAP Request
* @return array('header' => ..., 'body' => ...)
*/
public function last_request()
{
$request = array();
$request['header'] = $this->__getLastRequestHeaders();
$request['body'] = $this->__getLastRequest();
return $request;
}
/**
* Get the Last SOAP Response
* @return array('header' => ..., 'body' => ...)
*/
public function last_response()
{
$response = array();
$response['header'] = $this->__getLastResponseHeaders();
$response['body'] = $this->__getLastResponse();
return $response;
}
/**
* Get Info about the API Methods this Services Responds to
*
* @alias SoapClient#__getFunctions
*
* @return array
*/
public function functions()
{
return $this->__getFunctions();
}
/**
* Get all Objects this Service can return
* Note: This is mostly useful for reflection of objects to PHP Classes
* @alias SoapClient#__getTypes
*
* @return array
*/
public function types()
{
return $this->__getTypes();
}
/**
* Disallow Serialization of resources
*/
public function __sleep()
{
throw new Exception('Fancy Soap Client Resources cannot be serialized.');
}
public function __wakeup()
{
throw new Exception('Fancy Soap Client Resources cannot be unserialized.');
}
}
//Load or __autoload ADebuggable_Soap_Client.php
require_once 'ADebuggable_Soap_Client.php'
/**
* Basic SOAP Client with Debugging Features and Dynamic API Method Invocation
*/
class Fancy_Soap_Client extends ADebuggable_Soap_Client
{
protected $_options;
public function __construct($wsdl, $options = array())
{
$client = NULL;
//Turn off error_reporting because the SoapClient constructor throws fatal error when it can't connect on some environments
//see http://bugs.php.net/bug.php?id=38703 && ?id=34657
$prev_report_level = error_reporting();
//Disable any other error interceptors (xdebug etc) here
try
{
$client = parent::__construct($wsdl, $options);
}
catch(SoapFault $e)
{
//Turn error reporting back on
error_reporting($prev_report_level);
throw $e;
return NULL;
}
//Turn error reporting back on
error_reporting($prev_report_level);
//Re-enable any other error interceptors (xdebug etc) here
return $client;
}
/*
* Use __call magic method to dynamically call a soap method, without having to explicitly define the method
*
* To use custom implementations of API method calls,
* explicitly declare a public method of the same name as the SOAP API name.
*/
public function __call($method, $arguments)
{
if($this->api_exists())
{
try
{
return $this->__soapCall($method, $arguments);
}
catch(SoapFault $e)
{
error_log($e->getMessage());
error_log($e->getTraceAsString());
$this->debug();
}
}
else
{
return parent::__call($method, $arguments);
}
}
/**
* Set the Location of the WSDL
* @alias SoapClient#__setLocation
*
* @param string $url : new endpoint location
* @return string : old enpoint location
*/
public function set_location($url)
{
return $this->__setLocation($url);
}
/**
* Set soap request headers on client
* @alias SoapClient#__setSoapHeaders
*
* @param array $headers
*/
public function set_headers($namespace, $headers = array())
{
$soap_headers = array();
if(is_array($headers))
{
foreach($headers as $header_name => $header_value)
{
$soap_headers[] = new SoapHeader($namespace, $header_name, $header_value);
}
}
$this->__setSoapHeaders($soap_headers);
}
/**
* Dump Last Request and Response Info to Logs
* @return string $debug_msg
*/
public function debug()
{
$request = $this->last_request();
$response = $this->last_response();
$dbg_msg = "********Fancy Soap Client Debug Output********\n\n";
$dbg_msg .= "LAST REQUEST:\n\n";
$dbg_msg .= "--Header--\n";
$dbg_msg .= $request['header'];
$dbg_msg .= "--Body--\n";
$dbg_msg .= $request['body'];
$dbg_msg .= "\n\nLAST Response:\n\n";
$dbg_msg .= "--Header--\n";
$dbg_msg .= $response['header'];
$dbg_msg .= "--Body--\n";
$dbg_msg .= $response['body'];
error_log($dbg_msg);
return $dbg_msg;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment