-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from veewee/wsdl-flattener
Wsdl flattener
- Loading branch information
Showing
63 changed files
with
1,633 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phive xmlns="https://phar.io/phive"> | ||
<phar name="psalm" version="^4.13.1" installed="4.13.1" location="./tools/psalm.phar" copy="true"/> | ||
<phar name="psalm" version="^4.19.0" installed="4.19.0" location="./tools/psalm.phar" copy="true"/> | ||
<phar name="php-cs-fixer" version="^3.3.2" installed="3.3.2" location="./tools/php-cs-fixer.phar" copy="true"/> | ||
</phive> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Soap\Wsdl\Loader\Context; | ||
|
||
use DOMElement; | ||
use Soap\Wsdl\Exception\UnloadableWsdlException; | ||
use Soap\Wsdl\Loader\WsdlLoader; | ||
use Soap\Wsdl\Xml\Configurator\FlattenTypes; | ||
use Soap\Wsdl\Xml\Flattener; | ||
use Soap\Xml\Xpath\WsdlPreset; | ||
use VeeWee\Xml\Dom\Document; | ||
use VeeWee\Xml\Exception\RuntimeException; | ||
use function VeeWee\Xml\Dom\Mapper\xml_string; | ||
|
||
final class FlatteningContext | ||
{ | ||
/** | ||
* XSD import catalog of location => raw (not flattened) xml | ||
* | ||
* @var array<string, string> | ||
*/ | ||
private $catalog = []; | ||
|
||
public static function forWsdl( | ||
string $location, | ||
Document $wsdl, | ||
WsdlLoader $loader, | ||
): self { | ||
$new = new self($wsdl, $loader); | ||
$new->catalog[$location] = $wsdl->map(xml_string()); | ||
|
||
return $new; | ||
} | ||
|
||
private function __construct( | ||
private Document $wsdl, | ||
private WsdlLoader $loader | ||
) { | ||
} | ||
|
||
/** | ||
* This function can be used to detect if the context knows about a part of the WSDL. | ||
* It knows about a part from the moment that the raw XML version has been loaded once, | ||
* even if the flattening process is still in an underlying import / include. | ||
*/ | ||
public function knowsAboutPart(string $location): bool | ||
{ | ||
return array_key_exists($location, $this->catalog); | ||
} | ||
|
||
/** | ||
* Imports and include only need to occur once. | ||
* This function determines if an import should be done. | ||
* | ||
* It either returns null if the import already was done or the flattened XML if it still requires an import. | ||
*/ | ||
public function import(string $location): ?string | ||
{ | ||
return $this->knowsAboutPart($location) | ||
? null | ||
: $this->loadFlattenedXml($location); | ||
} | ||
|
||
/** | ||
* Returns the base WSDL document that can be worked on by flattener configurators. | ||
*/ | ||
public function wsdl(): Document | ||
{ | ||
return $this->wsdl; | ||
} | ||
|
||
/** | ||
* This method searches for a single <wsdl:types /> tag | ||
* If no tag exists, it will create an empty one. | ||
* If multiple tags exist, it will merge those tags into one. | ||
* | ||
* @throws RuntimeException | ||
*/ | ||
public function types(): DOMElement | ||
{ | ||
$doc = Document::fromUnsafeDocument($this->wsdl->toUnsafeDocument(), new FlattenTypes()); | ||
$xpath = $doc->xpath(new WsdlPreset($doc)); | ||
|
||
/** @var DOMElement $types */ | ||
$types = $xpath->querySingle('//wsdl:types'); | ||
|
||
return $types; | ||
} | ||
|
||
/** | ||
* This function will take care of the import catalog! | ||
* It will first load the raw xml from the remote source and store that internally. | ||
* | ||
* Next it will apply the XML flattening on the loaded xml and return the flattened string. | ||
* We keep track of all nested flattening locations that are in progress. | ||
* This way we can prevent circular includes as well. | ||
* | ||
* @throws UnloadableWsdlException | ||
* @throws RuntimeException | ||
*/ | ||
private function loadFlattenedXml(string $location): string | ||
{ | ||
if (!array_key_exists($location, $this->catalog)) { | ||
$this->catalog[$location] = ($this->loader)($location); | ||
} | ||
|
||
$document = Document::fromXmlString($this->catalog[$location]); | ||
|
||
return (new Flattener())($location, $document, $this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Soap\Wsdl\Loader; | ||
|
||
use Soap\Wsdl\Exception\UnloadableWsdlException; | ||
use Soap\Wsdl\Loader\Context\FlatteningContext; | ||
use Soap\Wsdl\Xml\Flattener; | ||
use VeeWee\Xml\Dom\Document; | ||
use VeeWee\Xml\Exception\RuntimeException; | ||
|
||
final class FlatteningLoader implements WsdlLoader | ||
{ | ||
public function __construct( | ||
private WsdlLoader $loader, | ||
) { | ||
} | ||
|
||
/** | ||
* @throws RuntimeException | ||
* @throws UnloadableWsdlException | ||
*/ | ||
public function __invoke(string $location): string | ||
{ | ||
$currentDoc = Document::fromXmlString(($this->loader)($location)); | ||
$context = FlatteningContext::forWsdl($location, $currentDoc, $this->loader); | ||
|
||
return (new Flattener())($location, $currentDoc, $context); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Soap\Wsdl\Uri; | ||
|
||
use League\Uri\Uri; | ||
use League\Uri\UriModifier; | ||
use League\Uri\UriResolver; | ||
|
||
final class IncludePathBuilder | ||
{ | ||
public static function build(string $relativePath, string $fromFile): string | ||
{ | ||
return UriModifier::removeEmptySegments( | ||
UriModifier::removeDotSegments( | ||
UriResolver::resolve( | ||
Uri::createFromString($relativePath), | ||
Uri::createFromString($fromFile) | ||
) | ||
) | ||
)->__toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Soap\Wsdl\Xml\Configurator; | ||
|
||
use DOMDocument; | ||
use DOMElement; | ||
use Soap\Xml\Xmlns; | ||
use Soap\Xml\Xpath\WsdlPreset; | ||
use VeeWee\Xml\Dom\Configurator\Configurator; | ||
use VeeWee\Xml\Dom\Document; | ||
use VeeWee\Xml\Exception\RuntimeException; | ||
use function VeeWee\Xml\Dom\Builder\namespaced_element; | ||
use function VeeWee\Xml\Dom\Locator\Node\children; | ||
use function VeeWee\Xml\Dom\Manipulator\append; | ||
use function VeeWee\Xml\Dom\Manipulator\Node\remove; | ||
|
||
/** | ||
* This class transforms multiple wsdl:types elements into 1 single element. | ||
* This makes importing xsd's easier (and prevents some bugs in some soap related tools) | ||
*/ | ||
final class FlattenTypes implements Configurator | ||
{ | ||
/** | ||
* @throws RuntimeException | ||
*/ | ||
public function __invoke(DOMDocument $document): DOMDocument | ||
{ | ||
$xml = Document::fromUnsafeDocument($document); | ||
$xpath = $xml->xpath(new WsdlPreset($xml)); | ||
/** @var list<DOMElement> $types */ | ||
$types = [...$xpath->query('wsdl:types')]; | ||
|
||
// Creates wsdl:types if no matching element exists yet | ||
if (!count($types)) { | ||
$document->documentElement->append( | ||
namespaced_element(Xmlns::wsdl()->value(), 'types')($document) | ||
); | ||
|
||
return $document; | ||
} | ||
|
||
// Skip if only one exists | ||
$first = array_shift($types); | ||
if (!count($types)) { | ||
return $document; | ||
} | ||
|
||
// Flattens multiple wsdl:types elements. | ||
foreach ($types as $additionalTypes) { | ||
$children = children($additionalTypes); | ||
if (count($children)) { | ||
append(...$children)($first); | ||
} | ||
|
||
remove($additionalTypes); | ||
} | ||
|
||
return $document; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Soap\Wsdl\Xml\Configurator; | ||
|
||
use DOMDocument; | ||
use DOMElement; | ||
use Soap\Wsdl\Exception\UnloadableWsdlException; | ||
use Soap\Wsdl\Loader\Context\FlatteningContext; | ||
use Soap\Wsdl\Uri\IncludePathBuilder; | ||
use Soap\Xml\Xpath\WsdlPreset; | ||
use VeeWee\Xml\Dom\Configurator\Configurator; | ||
use VeeWee\Xml\Dom\Document; | ||
use VeeWee\Xml\Exception\RuntimeException; | ||
use function VeeWee\Xml\Dom\Locator\document_element; | ||
use function VeeWee\Xml\Dom\Locator\Node\children; | ||
use function VeeWee\Xml\Dom\Manipulator\Node\remove; | ||
use function VeeWee\Xml\Dom\Manipulator\Node\replace_by_external_nodes; | ||
|
||
final class FlattenWsdlImports implements Configurator | ||
{ | ||
public function __construct( | ||
private string $currentLocation, | ||
private FlatteningContext $context | ||
) { | ||
} | ||
|
||
/** | ||
* This method flattens wsdl:import locations. | ||
* It loads the WSDL and adds the definitions replaces the import tag with the definition children from the external file. | ||
* | ||
* For now, we don't care about the namespace property on the wsdl:import tag. | ||
* Future reference: | ||
* @link http://itdoc.hitachi.co.jp/manuals/3020/30203Y2310e/EY230669.HTM#ID01496 | ||
* | ||
* @throws RuntimeException | ||
* @throws UnloadableWsdlException | ||
*/ | ||
public function __invoke(DOMDocument $document): DOMDocument | ||
{ | ||
$xml = Document::fromUnsafeDocument($document); | ||
$xpath = $xml->xpath(new WsdlPreset($xml)); | ||
|
||
$imports = $xpath->query('wsdl:import'); | ||
$imports->forEach(fn (DOMElement $import) => $this->importWsdlImportElement($import)); | ||
|
||
return $document; | ||
} | ||
|
||
/** | ||
* @throws RuntimeException | ||
* @throws UnloadableWsdlException | ||
*/ | ||
private function importWsdlImportElement(DOMElement $import): void | ||
{ | ||
$location = IncludePathBuilder::build( | ||
$import->getAttribute('location'), | ||
$this->currentLocation | ||
); | ||
|
||
$result = $this->context->import($location); | ||
if (!$result) { | ||
remove($import); | ||
return; | ||
} | ||
|
||
$imported = Document::fromXmlString($result); | ||
$definitions = $imported->map(document_element()); | ||
|
||
replace_by_external_nodes( | ||
$import, | ||
children($definitions) | ||
); | ||
} | ||
} |
Oops, something went wrong.