-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
namespace Soap\Wsdl\Xml\Visitor; | ||
|
||
use VeeWee\Xml\Dom\Traverser\Action; | ||
use VeeWee\Xml\Dom\Traverser\Visitor; | ||
use function VeeWee\Xml\Dom\Predicate\is_attribute; | ||
|
||
class ReprefixTypeQname extends Visitor\AbstractVisitor | ||
{ | ||
public function __construct( | ||
private readonly string $originalPrefix, | ||
private readonly string $newPrefix, | ||
) { | ||
} | ||
|
||
public function onNodeEnter(\DOMNode $node): Action | ||
{ | ||
if (!is_attribute($node) || $node->localName !== 'type') { | ||
return new Action\Noop(); | ||
} | ||
|
||
$value = $node->nodeValue; | ||
if (!str_contains($value, ':')) { | ||
Check failure on line 24 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.1 @ ubuntu-latestPossiblyNullArgument
Check failure on line 24 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.2 @ ubuntu-latestPossiblyNullArgument
Check failure on line 24 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.3 @ ubuntu-latestPossiblyNullArgument
|
||
return new Action\Noop(); | ||
} | ||
|
||
[$currentPrefix, $currentTypeName] = explode(':', $value, 2); | ||
Check failure on line 28 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.1 @ ubuntu-latestPossiblyUndefinedArrayOffset
Check failure on line 28 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.1 @ ubuntu-latestPossiblyNullArgument
Check failure on line 28 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.2 @ ubuntu-latestPossiblyUndefinedArrayOffset
Check failure on line 28 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.2 @ ubuntu-latestPossiblyNullArgument
Check failure on line 28 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.3 @ ubuntu-latestPossiblyUndefinedArrayOffset
Check failure on line 28 in src/Xml/Visitor/ReprefixTypeQname.php GitHub Actions / PHP 8.3 @ ubuntu-latestPossiblyNullArgument
|
||
if ($currentPrefix !== $this->originalPrefix) { | ||
return new Action\Noop(); | ||
} | ||
|
||
$node->nodeValue = $this->newPrefix . ':'.$currentTypeName; | ||
|
||
return new Action\Noop(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace Soap\Wsdl\Xml\Xmlns; | ||
|
||
/** | ||
* @see https://gist.github.com/veewee/32c3aa94adcf878700a9d5baa4b2a2de | ||
* | ||
* PHP does an optimization of namespaces during `importNode()`. | ||
* In some cases, this causes the root xmlns to be removed from the imported node which could lead to xsd qname errors. | ||
* | ||
* This function tries to re-add the root xmlns if it's available on the source but not on the target. | ||
* | ||
* It will most likely be solved in PHP 8.4's new spec compliant DOM\XMLDocument implementation. | ||
* @see https://github.com/php/php-src/pull/13031 | ||
* | ||
* For now, this will do the trick. | ||
*/ | ||
final class FixRemovedDefaultXmlnsDeclarationsDuringImport | ||
{ | ||
public function __invoke(\DOMElement $target, \DOMElement $source): void | ||
{ | ||
if (!$source->getAttribute('xmlns') || $target->hasAttribute('xmlns')) { | ||
return; | ||
} | ||
|
||
$target->setAttribute('xmlns', $source->getAttribute('xmlns')); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<?php | ||
|
||
namespace Soap\Wsdl\Xml\Xmlns; | ||
|
||
use Soap\Wsdl\Xml\Visitor\ReprefixTypeQname; | ||
use VeeWee\Xml\Dom\Collection\NodeList; | ||
use VeeWee\Xml\Dom\Document; | ||
use function VeeWee\Xml\Dom\Builder\xmlns_attribute; | ||
use function VeeWee\Xml\Dom\Locator\Xmlns\linked_namespaces; | ||
|
||
/** | ||
* Cross-import schemas can contain namespace conflicts. | ||
* | ||
* For example: import1 requires import2: | ||
* | ||
* - Import 1 specifies xmlns:ns1="urn:1" | ||
* - Import 2 specifies xmlns:ns1="urn:2". | ||
* | ||
* This method will detect conflicting namespaces and resolve them. | ||
* Namespaces will be renamed to a unique name and the "type" argument with QName's will be re-prefixed. | ||
*/ | ||
final class RegisterNonConflictingXmlnsNamespaces | ||
{ | ||
public function __invoke(\DOMElement $existingSchema, \DOMElement $newSchema): void | ||
{ | ||
$existingLinkedNamespaces = linked_namespaces($existingSchema); | ||
Check failure on line 26 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestMissingThrowsDocblock
Check failure on line 26 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestMissingThrowsDocblock
Check failure on line 26 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestMissingThrowsDocblock
|
||
linked_namespaces($newSchema)->forEach(function (\DOMNameSpaceNode $xmlns) use ($existingSchema, $newSchema, $existingLinkedNamespaces) { | ||
Check failure on line 27 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestMissingThrowsDocblock
Check failure on line 27 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestMissingThrowsDocblock
Check failure on line 27 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestMissingThrowsDocblock
|
||
// Skip non-named xmlns attributes: | ||
if (!$xmlns->prefix) { | ||
return; | ||
} | ||
|
||
// Check for duplicates: | ||
if ($existingSchema->hasAttribute($xmlns->nodeName) && $existingSchema->getAttribute($xmlns->nodeName) !== $xmlns->prefix) { | ||
if ($this->tryUsingExistingPrefix($existingLinkedNamespaces, $newSchema, $xmlns)) { | ||
return; | ||
} | ||
|
||
if ($this->tryUsingUniquePrefixHash($existingSchema, $newSchema, $xmlns)) { | ||
return; | ||
} | ||
|
||
throw new \RuntimeException('Could not resolve conflicting namespace declarations whilst flattening your WSDL file.'); | ||
} | ||
|
||
xmlns_attribute($xmlns->prefix, $xmlns->namespaceURI)($existingSchema); | ||
Check failure on line 46 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestPossiblyNullArgument
Check failure on line 46 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestPossiblyNullArgument
Check failure on line 46 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestPossiblyNullArgument
|
||
}); | ||
|
||
(new FixRemovedDefaultXmlnsDeclarationsDuringImport())($existingSchema, $newSchema); | ||
} | ||
|
||
/** | ||
* @param NodeList<\DOMNameSpaceNode> $existingLinkedNamespaces | ||
Check failure on line 53 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestInvalidTemplateParam
Check failure on line 53 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestInvalidTemplateParam
Check failure on line 53 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestInvalidTemplateParam
|
||
*/ | ||
private function tryUsingExistingPrefix( | ||
NodeList $existingLinkedNamespaces, | ||
\DOMElement $newSchema, | ||
\DOMNameSpaceNode $xmlns | ||
): bool { | ||
$existingPrefix = $existingLinkedNamespaces->filter( | ||
Check failure on line 60 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestInvalidTemplateParam
Check failure on line 60 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestInvalidTemplateParam
Check failure on line 60 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestInvalidTemplateParam
|
||
static fn (\DOMNameSpaceNode $node) => $node->namespaceURI === $xmlns->namespaceURI | ||
)->first()?->prefix; | ||
|
||
if (!$existingPrefix) { | ||
Check failure on line 64 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestRiskyTruthyFalsyComparison
Check failure on line 64 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestRiskyTruthyFalsyComparison
Check failure on line 64 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestRiskyTruthyFalsyComparison
|
||
return false; | ||
} | ||
|
||
$this->reprefixTypeDeclarations($newSchema, $xmlns->prefix, $existingPrefix); | ||
|
||
return true; | ||
} | ||
|
||
private function tryUsingUniquePrefixHash(\DOMElement $existingSchema, \DOMElement $newSchema, \DOMNameSpaceNode $xmlns): bool | ||
{ | ||
$uniquePrefix = 'ns' . substr(md5($xmlns->namespaceURI), 0, 8); | ||
Check failure on line 75 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.1 @ ubuntu-latestPossiblyNullArgument
Check failure on line 75 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.2 @ ubuntu-latestPossiblyNullArgument
Check failure on line 75 in src/Xml/Xmlns/RegisterNonConflictingXmlnsNamespaces.php GitHub Actions / PHP 8.3 @ ubuntu-latestPossiblyNullArgument
|
||
if ($existingSchema->hasAttribute('xmlns:'.$uniquePrefix)) { | ||
|
||
|
||
|
||
var_dump($xmlns->namespaceURI); | ||
var_dump($existingSchema->ownerDocument->lookupPrefix($xmlns->namespaceURI)); | ||
var_dump($existingSchema->ownerDocument->lookupNamespaceURI($uniquePrefix)); | ||
|
||
echo $existingSchema->ownerDocument->saveXML(); | ||
|
||
die($uniquePrefix . 'already exists'); | ||
|
||
return false; | ||
} | ||
|
||
$this->copyXmlnsDeclaration($existingSchema, $xmlns->namespaceURI, $uniquePrefix); | ||
$this->rePrefixTypeDeclarations($newSchema, $xmlns->prefix, $uniquePrefix); | ||
|
||
return true; | ||
} | ||
|
||
private function copyXmlnsDeclaration(\DOMElement $existingSchema, string $namespaceUri, string $prefix): void | ||
{ | ||
xmlns_attribute($prefix, $namespaceUri)($existingSchema); | ||
} | ||
|
||
private function rePrefixTypeDeclarations(\DOMElement $newSchema, string $originalPrefix, string $newPrefix): void | ||
{ | ||
Document::fromUnsafeDocument($newSchema->ownerDocument)->traverse(new ReprefixTypeQname( | ||
$originalPrefix, | ||
$newPrefix | ||
)); | ||
} | ||
} |