added wsdl:include to WsdlDownloader (and also the wsdl:import,

xs:import)
This commit is contained in:
Andreas Schamberger 2011-11-20 18:13:42 +01:00
parent 7b1e2eef93
commit 7b4b832d61
6 changed files with 121 additions and 23 deletions

View File

@ -241,19 +241,17 @@ class SoapClient extends \SoapClient
*/ */
private function loadWsdl($wsdl, array $options) private function loadWsdl($wsdl, array $options)
{ {
// option to resolve xsd includes // option to resolve wsdl/xsd includes
$resolveXsdIncludes = true; $resolveRemoteIncludes = true;
if (isset($options['resolve_xsd_includes'])) if (isset($options['resolve_wsdl_remote_includes'])) {
{ $resolveRemoteIncludes = $options['resolve_wsdl_remote_includes'];
$resolveXsdIncludes = $options['resolve_xsd_includes'];
} }
// option to enable cache // option to enable cache
$wsdlCache = WSDL_CACHE_DISK; $wsdlCache = WSDL_CACHE_DISK;
if (isset($options['cache_wsdl'])) if (isset($options['cache_wsdl'])) {
{
$wsdlCache = $options['cache_wsdl']; $wsdlCache = $options['cache_wsdl'];
} }
$wsdlDownloader = new WsdlDownloader($this->curl, $resolveXsdIncludes, $wsdlCache); $wsdlDownloader = new WsdlDownloader($this->curl, $resolveRemoteIncludes, $wsdlCache);
try { try {
$cacheFileName = $wsdlDownloader->download($wsdl); $cacheFileName = $wsdlDownloader->download($wsdl);
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {

View File

@ -54,23 +54,23 @@ class WsdlDownloader
private $curl; private $curl;
/** /**
* Resolve XSD includes. * Resolve WSDl/XSD includes.
* *
* @var boolean * @var boolean
*/ */
protected $resolveXsdIncludes = true; protected $resolveRemoteIncludes = true;
/** /**
* Constructor. * Constructor.
* *
* @param \BeSimple\SoapClient\Curl $curl Curl instance * @param \BeSimple\SoapClient\Curl $curl Curl instance
* @param boolean $resolveXsdIncludes XSD include enabled? * @param boolean $resolveRemoteIncludes WSDL/XSD include enabled?
* @param boolean $cacheWsdl Cache constant * @param boolean $cacheWsdl Cache constant
*/ */
public function __construct(Curl $curl, $resolveXsdIncludes = true, $cacheWsdl = WSDL_CACHE_DISK) public function __construct(Curl $curl, $resolveRemoteIncludes = true, $cacheWsdl = WSDL_CACHE_DISK)
{ {
$this->curl = $curl; $this->curl = $curl;
$this->resolveXsdIncludes = $resolveXsdIncludes; $this->resolveRemoteIncludes = $resolveRemoteIncludes;
// get current WSDL caching config // get current WSDL caching config
$this->cacheEnabled = (bool)ini_get('soap.wsdl_cache_enabled'); $this->cacheEnabled = (bool)ini_get('soap.wsdl_cache_enabled');
if ($this->cacheEnabled === true if ($this->cacheEnabled === true
@ -96,7 +96,7 @@ class WsdlDownloader
// download and cache remote WSDL files or local ones where we want to // download and cache remote WSDL files or local ones where we want to
// resolve remote XSD includes // resolve remote XSD includes
$isRemoteFile = $this->isRemoteFile($wsdl); $isRemoteFile = $this->isRemoteFile($wsdl);
if ($isRemoteFile === true || $this->resolveXsdIncludes === true) { if ($isRemoteFile === true || $this->resolveRemoteIncludes === true) {
$cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . 'wsdl_' . md5($wsdl) . '.cache'; $cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . 'wsdl_' . md5($wsdl) . '.cache';
if ($this->cacheEnabled === false if ($this->cacheEnabled === false
|| !file_exists($cacheFile) || !file_exists($cacheFile)
@ -107,8 +107,8 @@ class WsdlDownloader
// get content // get content
if ($responseSuccessfull === true) { if ($responseSuccessfull === true) {
$response = $this->curl->getResponseBody(); $response = $this->curl->getResponseBody();
if ($this->resolveXsdIncludes === true) { if ($this->resolveRemoteIncludes === true) {
$this->resolveXsdIncludes($response, $cacheFile, $wsdl); $this->resolveRemoteIncludes($response, $cacheFile, $wsdl);
} else { } else {
file_put_contents($cacheFile, $response); file_put_contents($cacheFile, $response);
} }
@ -117,7 +117,7 @@ class WsdlDownloader
} }
} elseif (file_exists($wsdl)) { } elseif (file_exists($wsdl)) {
$response = file_get_contents($wsdl); $response = file_get_contents($wsdl);
$this->resolveXsdIncludes($response, $cacheFile); $this->resolveRemoteIncludes($response, $cacheFile);
} else { } else {
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'"); throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'");
} }
@ -149,20 +149,38 @@ class WsdlDownloader
} }
/** /**
* Resolves remote XSD includes within the WSDL files. * Resolves remote WSDL/XSD includes within the WSDL files.
* *
* @param string $xml * @param string $xml
* @param string $cacheFile * @param string $cacheFile
* @param unknown_type $parentIsRemote * @param unknown_type $parentIsRemote
* @return string * @return string
*/ */
private function resolveXsdIncludes($xml, $cacheFile, $parentFile = null) private function resolveRemoteIncludes($xml, $cacheFile, $parentFile = null)
{ {
$doc = new \DOMDocument(); $doc = new \DOMDocument();
$doc->loadXML($xml); $doc->loadXML($xml);
$xpath = new \DOMXPath($doc); $xpath = new \DOMXPath($doc);
$xpath->registerNamespace(Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA); $xpath->registerNamespace(Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA);
$query = './/' . Helper::PFX_XML_SCHEMA . ':include'; $xpath->registerNamespace('wsdl', 'http://schemas.xmlsoap.org/wsdl/'); // TODO add to Helper
// WSDL include/import
$query = './/wsdl:include | .//wsdl:import';
$nodes = $xpath->query($query);
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$location = $node->getAttribute('location');
if ($this->isRemoteFile($location)) {
$location = $this->download($location);
$node->setAttribute('location', $location);
} elseif (!is_null($parentFile)) {
$location = $this->resolveRelativePathInUrl($parentFile, $location);
$location = $this->download($location);
$node->setAttribute('location', $location);
}
}
}
// XML schema include/import
$query = './/' . Helper::PFX_XML_SCHEMA . ':include | .//' . Helper::PFX_XML_SCHEMA . ':import';
$nodes = $xpath->query($query); $nodes = $xpath->query($query);
if ($nodes->length > 0) { if ($nodes->length > 0) {
foreach ($nodes as $node) { foreach ($nodes as $node) {

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<wsdl:types xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://test.sample">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<wsdl:documentation>wsdlincludetest</wsdl:documentation>
<wsdl:include location="http://localhost:8000/wsdl_include.wsdl"/>
</wsdl:definitions>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<wsdl:documentation>wsdlincludetest</wsdl:documentation>
<wsdl:include location="../wsdl_include.wsdl"/>
</wsdl:definitions>

View File

@ -115,6 +115,63 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($method->invoke($wd, '../dir/test.html')); $this->assertFalse($method->invoke($wd, '../dir/test.html'));
} }
public function testResolveWsdlIncludes()
{
$this->startPhpWebserver();
$curl = new Curl();
$wd = new WsdlDownloader($curl);
$class = new \ReflectionClass($wd);
$method = $class->getMethod('resolveRemoteIncludes');
$method->setAccessible(true);
$cacheDir = ini_get('soap.wsdl_cache_dir');
if (!is_dir($cacheDir)) {
$cacheDir = sys_get_temp_dir();
$cacheDirForRegExp = preg_quote( $cacheDir );
}
$remoteUrlAbsolute = 'http://localhost:8000/wsdlinclude/wsdlinctest_absolute.xml';
$remoteUrlRelative = 'http://localhost:8000/wsdlinclude/wsdlinctest_relative.xml';
$tests = array(
'localWithAbsolutePath' => array(
'source' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/wsdlinclude/wsdlinctest_absolute.xml',
'cacheFile' => $cacheDir.'/cache_local_absolute.xml',
'remoteParentUrl' => null,
'assertRegExp' => '~.*'.$cacheDirForRegExp.'\\\wsdl_.*\.cache.*~',
),
'localWithRelativePath' => array(
'source' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/wsdlinclude/wsdlinctest_relative.xml',
'cacheFile' => $cacheDir.'/cache_local_relative.xml',
'remoteParentUrl' => null,
'assertRegExp' => '~.*\.\./wsdl_include\.wsdl.*~',
),
'remoteWithAbsolutePath' => array(
'source' => $remoteUrlAbsolute,
'cacheFile' => $cacheDir.'/cache_remote_absolute.xml',
'remoteParentUrl' => $remoteUrlAbsolute,
'assertRegExp' => '~.*'.$cacheDirForRegExp.'\\\wsdl_.*\.cache.*~',
),
'remoteWithAbsolutePath' => array(
'source' => $remoteUrlRelative,
'cacheFile' => $cacheDir.'/cache_remote_relative.xml',
'remoteParentUrl' => $remoteUrlRelative,
'assertRegExp' => '~.*'.$cacheDirForRegExp.'\\\wsdl_.*\.cache.*~',
),
);
foreach ($tests as $name => $values) {
$wsdl = file_get_contents( $values['source'] );
$method->invoke($wd, $wsdl, $values['cacheFile'],$values['remoteParentUrl']);
$result = file_get_contents($values['cacheFile']);
$this->assertRegExp($values['assertRegExp'],$result,$name);
unlink($values['cacheFile']);
}
$this->stopPhpWebserver();
}
public function testResolveXsdIncludes() public function testResolveXsdIncludes()
{ {
$this->startPhpWebserver(); $this->startPhpWebserver();
@ -123,7 +180,7 @@ class WsdlDownloaderTest extends \PHPUnit_Framework_TestCase
$wd = new WsdlDownloader($curl); $wd = new WsdlDownloader($curl);
$class = new \ReflectionClass($wd); $class = new \ReflectionClass($wd);
$method = $class->getMethod('resolveXsdIncludes'); $method = $class->getMethod('resolveRemoteIncludes');
$method->setAccessible(true); $method->setAccessible(true);
$cacheDir = ini_get('soap.wsdl_cache_dir'); $cacheDir = ini_get('soap.wsdl_cache_dir');