diff --git a/src/BeSimple/SoapClient/SoapClient.php b/src/BeSimple/SoapClient/SoapClient.php index 75c930e..19d5be9 100644 --- a/src/BeSimple/SoapClient/SoapClient.php +++ b/src/BeSimple/SoapClient/SoapClient.php @@ -22,6 +22,27 @@ namespace BeSimple\SoapClient; */ class SoapClient extends \SoapClient { + /** + * Soap version. + * + * @var int + */ + protected $soapVersion = SOAP_1_1; + + /** + * Tracing enabled? + * + * @var boolean + */ + protected $tracingEnabled = false; + + /** + * cURL instance. + * + * @var \BeSimple\SoapClient\Curl + */ + protected $curl = null; + /** * Last request headers. * @@ -51,63 +72,33 @@ class SoapClient extends \SoapClient private $lastResponse = ''; /** - * Copy of the parent class' options array + * Constructor. * - * @var array(string=>mixed) + * @param string $wsdl WSDL file + * @param array(string=>mixed) $options Options array */ - protected $options = array(); - - /** - * Path to WSDL (cache) file. - * - * @var string - */ - private $wsdlFile = null; - - /** - * Extended constructor that saves the options as the parent class' - * property is private. - * - * @param string $wsdl - * @param array(string=>mixed) $options - */ - public function __construct($wsdl, array $options = array(), TypeConverterCollection $converters = null) + public function __construct($wsdl, array $options = array()) { + // tracing enabled: store last request/response header and body + if (isset($options['trace']) && $options['trace'] === true) { + $this->tracingEnabled = true; + } + // store SOAP version + if (isset($options['soap_version'])) { + $this->soapVersion = $options['soap_version']; + } + $this->curl = new Curl($options); + $wsdlFile = $this->loadWsdl($wsdl, $options); // we want the exceptions option to be set $options['exceptions'] = true; - // we want to make sure we have the soap version to rely on it later - if (!isset($options['soap_version'])) { - $options['soap_version'] = SOAP_1_1; - } - // we want to make sure we have the features option - if (!isset($options['features'])) { - $options['features'] = 0; - } - // set default option to resolve xsd includes - if (!isset($options['resolve_xsd_includes'])) { - $options['resolve_xsd_includes'] = true; - } - // add type converters from TypeConverterCollection - if (!is_null($converters)) { - $convertersTypemap = $converters->getTypemap(); - if (isset($options['typemap'])) { - $options['typemap'] = array_merge($options['typemap'], $convertersTypemap); - } else { - $options['typemap'] = $convertersTypemap; - } - } - // store local copy as ext/soap's property is private - $this->options = $options; // disable obsolete trace option for native SoapClient as we need to do our own tracing anyways $options['trace'] = false; // disable WSDL caching as we handle WSDL caching for remote URLs ourself $options['cache_wsdl'] = WSDL_CACHE_NONE; - // load WSDL and run parent constructor - // can't be loaded later as we need it already in the parent constructor - $this->wsdlFile = $this->loadWsdl($wsdl); - parent::__construct($this->wsdlFile, $options); + parent::__construct($wsdlFile, $options); } + /** * Perform HTTP request with cURL. * @@ -120,7 +111,7 @@ class SoapClient extends \SoapClient { // $request is if unmodified from SoapClient not a php string type! $request = (string)$request; - if ($this->options['soap_version'] == SOAP_1_2) { + if ($this->soapVersion == SOAP_1_2) { $headers = array( 'Content-Type: application/soap+xml; charset=utf-8', ); @@ -131,39 +122,35 @@ class SoapClient extends \SoapClient } // add SOAPAction header $headers[] = 'SOAPAction: "' . $action . '"'; - // new curl object for request - $curl = new Curl($this->options); // execute request - $responseSuccessfull = $curl->exec($location, $request, $headers); + $responseSuccessfull = $this->curl->exec($location, $request, $headers); // tracing enabled: store last request header and body - if (isset($this->options['trace']) && $this->options['trace'] === true) { + if ($this->tracingEnabled === true) { $this->lastRequestHeaders = $curl->getRequestHeaders(); $this->lastRequest = $request; } // in case of an error while making the http request throw a soapFault if ($responseSuccessfull === false) { // get error message from curl - $faultstring = $curl->getErrorMessage(); - // destruct curl object - unset($curl); + $faultstring = $this->curl->getErrorMessage(); throw new \SoapFault('HTTP', $faultstring); } // tracing enabled: store last response header and body - if (isset($this->options['trace']) && $this->options['trace'] === true) { - $this->lastResponseHeaders = $curl->getResponseHeaders(); - $this->lastResponse = $curl->getResponseBody(); + if ($this->tracingEnabled === true) { + $this->lastResponseHeaders = $this->curl->getResponseHeaders(); + $this->lastResponse = $this->curl->getResponseBody(); } - $response = $curl->getResponseBody(); + $response = $this->curl->getResponseBody(); // check if we do have a proper soap status code (if not soapfault) // // TODO -// $responseStatusCode = $curl->getResponseStatusCode(); +// $responseStatusCode = $this->curl->getResponseStatusCode(); // if ($responseStatusCode >= 400) { // $isError = 0; // $response = trim($response); // if (strlen($response) == 0) { // $isError = 1; // } else { -// $contentType = $curl->getResponseContentType(); +// $contentType = $this->curl->getResponseContentType(); // if ($contentType != 'application/soap+xml' // && $contentType != 'application/soap+xml') { // if (strncmp($response , "getResponseStatusMessage()); +// throw new \SoapFault('HTTP', $this->curl->getResponseStatusMessage()); // } // } elseif ($responseStatusCode != 200 && $responseStatusCode != 202) { // $dom = new \DOMDocument('1.0'); @@ -181,8 +168,6 @@ class SoapClient extends \SoapClient // throw new \SoapFault('HTTP', 'HTTP response status must be 200 or 202'); // } // } - // destruct curl object - unset($curl); return $response; } @@ -250,12 +235,25 @@ class SoapClient extends \SoapClient * ini settings. Does only file caching as SoapClient only supports a file * name parameter. * - * @param string $wsdl + * @param string $wsdl WSDL file + * @param array(string=>mixed) $options Options array * @return string */ - private function loadWsdl($wsdl) + private function loadWsdl($wsdl, array $options) { - $wsdlDownloader = new WsdlDownloader($this->options); + // option to resolve xsd includes + $resolveXsdIncludes = true; + if (isset($options['resolve_xsd_includes'])) + { + $resolveXsdIncludes = $options['resolve_xsd_includes']; + } + // option to enable cache + $wsdlCache = WSDL_CACHE_DISK; + if (isset($options['cache_wsdl'])) + { + $wsdlCache = $options['cache_wsdl']; + } + $wsdlDownloader = new WsdlDownloader($this->curl, $resolveXsdIncludes, $wsdlCache); try { $cacheFileName = $wsdlDownloader->download($wsdl); } catch (\RuntimeException $e) { diff --git a/src/BeSimple/SoapClient/WsdlDownloader.php b/src/BeSimple/SoapClient/WsdlDownloader.php index 261fd50..540c801 100644 --- a/src/BeSimple/SoapClient/WsdlDownloader.php +++ b/src/BeSimple/SoapClient/WsdlDownloader.php @@ -12,11 +12,14 @@ namespace BeSimple\SoapClient; +// TODO +//use BeSimple\SoapCommon\Helper; + /** - * Downloads WSDL files with cURL. Uses all SoapClient options for - * authentication. Uses the WSDL_CACHE_* constants and the 'soap.wsdl_*' - * ini settings. Does only file caching as SoapClient only supports a file - * name parameter. The class also resolves remote XML schema includes. + * Downloads WSDL files with cURL. Uses the WSDL_CACHE_* constants and the + * 'soap.wsdl_*' ini settings. Does only file caching as SoapClient only + * supports a file name parameter. The class also resolves remote XML schema + * includes. * * @author Andreas Schamberger */ @@ -44,24 +47,34 @@ class WsdlDownloader private $cacheTtl; /** - * Options array + * cURL instance for downloads. * - * @var array(string=>mixed) + * @var unknown_type */ - private $options = array(); + private $curl; + + /** + * Resolve XSD includes. + * + * @var boolean + */ + protected $resolveXsdIncludes = true; /** * Constructor. * - * @param array $options + * @param \BeSimple\SoapClient\Curl $curl Curl instance + * @param boolean $resolveXsdIncludes XSD include enabled? + * @param boolean $cacheWsdl Cache constant */ - public function __construct(array $options = array()) + public function __construct(Curl $curl, $resolveXsdIncludes = true, $cacheWsdl = WSDL_CACHE_DISK) { + $this->curl = $curl; + $this->resolveXsdIncludes = $resolveXsdIncludes; // get current WSDL caching config $this->cacheEnabled = (bool)ini_get('soap.wsdl_cache_enabled'); if ($this->cacheEnabled === true - && isset($options['cache_wsdl']) - && $options['cache_wsdl'] === WSDL_CACHE_NONE) { + && $cacheWsdl === WSDL_CACHE_NONE) { $this->cacheEnabled = false; } $this->cacheDir = ini_get('soap.wsdl_cache_dir'); @@ -70,10 +83,6 @@ class WsdlDownloader } $this->cacheDir = rtrim($this->cacheDir, '/\\'); $this->cacheTtl = ini_get('soap.wsdl_cache_ttl'); - $this->options = $options; - if (!isset($this->options['resolve_xsd_includes'])) { - $this->options['resolve_xsd_includes'] = true; - } } /** @@ -87,20 +96,18 @@ class WsdlDownloader // download and cache remote WSDL files or local ones where we want to // resolve remote XSD includes $isRemoteFile = $this->isRemoteFile($wsdl); - if ($isRemoteFile === true || $this->options['resolve_xsd_includes'] === true) { + if ($isRemoteFile === true || $this->resolveXsdIncludes === true) { $cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . 'wsdl_' . md5($wsdl) . '.cache'; if ($this->cacheEnabled === false || !file_exists($cacheFile) || (filemtime($cacheFile) + $this->cacheTtl) < time()) { if ($isRemoteFile === true) { - // new curl object for request - $curl = new Curl($this->options); // execute request - $responseSuccessfull = $curl->exec($wsdl); + $responseSuccessfull = $this->curl->exec($wsdl); // get content if ($responseSuccessfull === true) { - $response = $curl->getResponseBody(); - if ($this->options['resolve_xsd_includes'] === true) { + $response = $this->curl->getResponseBody(); + if ($this->resolveXsdIncludes === true) { $this->resolveXsdIncludes($response, $cacheFile, $wsdl); } else { file_put_contents($cacheFile, $response); diff --git a/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php b/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php index 326a668..f294a8b 100644 --- a/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php +++ b/tests/BeSimple/Tests/SoapClient/WsdlDownloaderTest.php @@ -13,6 +13,7 @@ namespace BeSimple\SoapClient; use BeSimple\SoapClient\WsdlDownloader; +use BeSimple\SoapClient\Curl; /** * @author Andreas Schamberger @@ -50,10 +51,8 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase { $this->startPhpWebserver(); - $options = array( - 'resolve_xsd_includes' => true, - ); - $wd = new WsdlDownloader($options); + $curl = new Curl(); + $wd = new WsdlDownloader($curl); $cacheDir = ini_get('soap.wsdl_cache_dir'); if (!is_dir($cacheDir)) { @@ -92,7 +91,8 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase public function testIsRemoteFile() { - $wd = new WsdlDownloader(); + $curl = new Curl(); + $wd = new WsdlDownloader($curl); $class = new \ReflectionClass($wd); $method = $class->getMethod('isRemoteFile'); @@ -119,10 +119,8 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase { $this->startPhpWebserver(); - $options = array( - 'resolve_xsd_includes' => true, - ); - $wd = new WsdlDownloader($options); + $curl = new Curl(); + $wd = new WsdlDownloader($curl); $class = new \ReflectionClass($wd); $method = $class->getMethod('resolveXsdIncludes'); @@ -176,7 +174,8 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase public function testResolveRelativePathInUrl() { - $wd = new WsdlDownloader(); + $curl = new Curl(); + $wd = new WsdlDownloader($curl); $class = new \ReflectionClass($wd); $method = $class->getMethod('resolveRelativePathInUrl');