diff --git a/.github/workflows/analyzers.yaml b/.github/workflows/analyzers.yaml index fbdbd31..f8f7ef5 100644 --- a/.github/workflows/analyzers.yaml +++ b/.github/workflows/analyzers.yaml @@ -7,7 +7,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: [ '8.3', '8.4', '8.5' ] + php-versions: [ '8.4', '8.5' ] composer-options: [ '--ignore-platform-req=php+' ] fail-fast: false name: PHP ${{ matrix.php-versions }} @ ${{ matrix.operating-system }} diff --git a/.github/workflows/code-style.yaml b/.github/workflows/code-style.yaml index fb19bca..a0a18b6 100644 --- a/.github/workflows/code-style.yaml +++ b/.github/workflows/code-style.yaml @@ -7,7 +7,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: [ '8.3', '8.4', '8.5' ] + php-versions: [ '8.4', '8.5' ] composer-options: [ '--ignore-platform-req=php+' ] fail-fast: false name: PHP ${{ matrix.php-versions }} @ ${{ matrix.operating-system }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f8cde3d..ec74651 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -7,7 +7,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: [ '8.3', '8.4', '8.5' ] + php-versions: [ '8.4', '8.5' ] composer-options: [ '--ignore-platform-req=php+' ] dependency-preference: ['current', 'lowest', 'stable'] fail-fast: false diff --git a/composer.json b/composer.json index 954f40c..6f40e36 100644 --- a/composer.json +++ b/composer.json @@ -13,14 +13,25 @@ } }, "require": { - "php": "~8.3.0 || ~8.4.0 || ~8.5.0", + "php": "~8.4.0 || ~8.5.0", "ext-dom": "*", "goetas-webservices/xsd-reader": "^0.4.11", - "php-soap/engine": "^2.19", - "php-soap/wsdl": "^1.18", - "php-soap/xml": "^1.9.0", - "veewee/xml": "^3.6", - "php-standard-library/php-standard-library": "^3.0 || ^4.0 || ^5.0 || ^6.0", + "php-soap/engine": "^2.20", + "php-soap/wsdl": "^1.19", + "php-soap/xml": "^1.10", + "veewee/xml": "^4.10", + "php-standard-library/dict": "^6.1", + "php-standard-library/foundation": "^6.1", + "php-standard-library/fun": "^6.1", + "php-standard-library/iter": "^6.1", + "php-standard-library/json": "^6.1", + "php-standard-library/math": "^6.1", + "php-standard-library/option": "^6.1", + "php-standard-library/regex": "^6.1", + "php-standard-library/result": "^6.1", + "php-standard-library/str": "^6.1", + "php-standard-library/type": "^6.1", + "php-standard-library/vec": "^6.1", "symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0", "webmozart/assert": "^1.11", "php-tui/php-tui": "^0.2.1" diff --git a/psalm.xml b/psalm.xml index 70f4db3..000ad4f 100644 --- a/psalm.xml +++ b/psalm.xml @@ -4,10 +4,14 @@ resolveFromConfigFile="true" findUnusedCode="false" ensureOverrideAttribute="false" + phpVersion="8.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" > + + + diff --git a/src/Parser/Definitions/AddressBindingTypeParser.php b/src/Parser/Definitions/AddressBindingTypeParser.php index 9c01b7d..fb51ca9 100644 --- a/src/Parser/Definitions/AddressBindingTypeParser.php +++ b/src/Parser/Definitions/AddressBindingTypeParser.php @@ -3,13 +3,13 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\AddressBindingType; use VeeWee\Xml\Dom\Document; final class AddressBindingTypeParser { - public function __invoke(Document $wsdl, DOMElement $namespacedElement): AddressBindingType + public function __invoke(Document $wsdl, Element $namespacedElement): AddressBindingType { return AddressBindingType::from($namespacedElement->namespaceURI ?? ''); } diff --git a/src/Parser/Definitions/BindingOperationMessageParser.php b/src/Parser/Definitions/BindingOperationMessageParser.php index 6bc746e..4bf0ec7 100644 --- a/src/Parser/Definitions/BindingOperationMessageParser.php +++ b/src/Parser/Definitions/BindingOperationMessageParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Psl\Type; use Soap\WsdlReader\Model\Definitions\BindingOperationMessage; use Soap\WsdlReader\Model\Definitions\BindingOperationMessages; @@ -16,7 +16,7 @@ final class BindingOperationMessageParser { - public function __invoke(Document $wsdl, DOMElement $message, StrategyInterface $strategy): BindingOperationMessage + public function __invoke(Document $wsdl, Element $message, StrategyInterface $strategy): BindingOperationMessage { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); @@ -28,29 +28,29 @@ public function __invoke(Document $wsdl, DOMElement $message, StrategyInterface public static function tryParseFromOptionalSingleOperationMessage( Document $wsdl, - DOMElement $operation, + Element $operation, string $message, StrategyInterface $strategy ): ?BindingOperationMessage { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); return wrap( - static fn (): DOMElement => assert_element($xpath->querySingle('./wsdl:'.$message, $operation)) + static fn (): Element => assert_element($xpath->querySingle('./wsdl:'.$message, $operation)) )->proceed( - static fn (DOMElement $messageElement): BindingOperationMessage => + static fn (Element $messageElement): BindingOperationMessage => (new self())($wsdl, $messageElement, $strategy), static fn () => null ); } /** - * @param NodeList $list + * @param NodeList $list */ public static function tryParseList(Document $wsdl, NodeList $list, StrategyInterface $strategy): BindingOperationMessages { return new BindingOperationMessages( ...$list->map( - static fn (DOMElement $message): BindingOperationMessage => (new self)($wsdl, $message, $strategy) + static fn (Element $message): BindingOperationMessage => (new self)($wsdl, $message, $strategy) ) ); } diff --git a/src/Parser/Definitions/BindingOperationParser.php b/src/Parser/Definitions/BindingOperationParser.php index 2187037..d8b2769 100644 --- a/src/Parser/Definitions/BindingOperationParser.php +++ b/src/Parser/Definitions/BindingOperationParser.php @@ -3,28 +3,28 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\BindingOperation; use Soap\WsdlReader\Parser\Strategy\StrategyInterface; use Soap\Xml\Xpath\WsdlPreset; use VeeWee\Xml\Dom\Document; -use function VeeWee\Xml\Dom\Locator\Element\locate_by_tag_name; +use function VeeWee\Xml\Dom\Locator\Element\locate_by_namespaced_tag_name; final class BindingOperationParser { - public function __invoke(Document $wsdl, DOMElement $operation, StrategyInterface $strategy): BindingOperation + public function __invoke(Document $wsdl, Element $operation, StrategyInterface $strategy): BindingOperation { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); - $soapOperation = locate_by_tag_name($operation, 'operation')->expectFirst('Unable to locate the operation implementation in a WSDL operation element!'); + $soapOperation = locate_by_namespaced_tag_name($operation, '*', 'operation')->expectFirst('Unable to locate the operation implementation in a WSDL operation element!'); return new BindingOperation( - name: $operation->getAttribute('name'), + name: $operation->getAttribute('name') ?? '', implementation: $strategy->parseOperationImplementation($wsdl, $soapOperation), input: BindingOperationMessageParser::tryParseFromOptionalSingleOperationMessage($wsdl, $operation, 'input', $strategy), output: BindingOperationMessageParser::tryParseFromOptionalSingleOperationMessage($wsdl, $operation, 'output', $strategy), fault: BindingOperationMessageParser::tryParseList( $wsdl, - $xpath->query('./wsdl:fault', $operation)->expectAllOfType(DOMElement::class), + $xpath->query('./wsdl:fault', $operation)->expectAllOfType(Element::class), $strategy ), ); diff --git a/src/Parser/Definitions/BindingParser.php b/src/Parser/Definitions/BindingParser.php index b6e1823..eb610b3 100644 --- a/src/Parser/Definitions/BindingParser.php +++ b/src/Parser/Definitions/BindingParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\Binding; use Soap\WsdlReader\Model\Definitions\BindingOperations; use Soap\WsdlReader\Model\Definitions\Bindings; @@ -11,28 +11,28 @@ use Soap\WsdlReader\Parser\Strategy\StrategySelector; use Soap\Xml\Xpath\WsdlPreset; use VeeWee\Xml\Dom\Document; -use function VeeWee\Xml\Dom\Locator\Element\locate_by_tag_name; +use function VeeWee\Xml\Dom\Locator\Element\locate_by_namespaced_tag_name; final class BindingParser { - public function __invoke(Document $wsdl, DOMElement $binding): Binding + public function __invoke(Document $wsdl, Element $binding): Binding { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); - $soapBinding = locate_by_tag_name($binding, 'binding')->expectFirst('Unable to locate the SOAP binding in a WSDL binding element!'); + $soapBinding = locate_by_namespaced_tag_name($binding, '*', 'binding')->expectFirst('Unable to locate the SOAP binding in a WSDL binding element!'); $addressBindingType = (new AddressBindingTypeParser())($wsdl, $soapBinding); $strategy = (new StrategySelector())($addressBindingType); return new Binding( - name: $binding->getAttribute('name'), - type: QNamed::parse($binding->getAttribute('type')), + name: $binding->getAttribute('name') ?? '', + type: QNamed::parse($binding->getAttribute('type') ?? ''), addressBindingType: $addressBindingType, implementation: $strategy->parseBindingImplementation($wsdl, $soapBinding), operations: new BindingOperations( ...$xpath->query('./wsdl:operation', $binding) - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $operation) => (new BindingOperationParser())($wsdl, $operation, $strategy) + static fn (Element $operation) => (new BindingOperationParser())($wsdl, $operation, $strategy) ) ), ); @@ -45,9 +45,9 @@ public static function tryParse(Document $wsdl): Bindings return new Bindings( ...$xpath->query('/wsdl:definitions/wsdl:binding') - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $binding): Binding => $parse($wsdl, $binding) + static fn (Element $binding): Binding => $parse($wsdl, $binding) ) ); } diff --git a/src/Parser/Definitions/MessageParser.php b/src/Parser/Definitions/MessageParser.php index 25720e1..fd7a237 100644 --- a/src/Parser/Definitions/MessageParser.php +++ b/src/Parser/Definitions/MessageParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\Message; use Soap\WsdlReader\Model\Definitions\Messages; use Soap\WsdlReader\Model\Definitions\Part; @@ -14,25 +14,25 @@ final class MessageParser { - public function __invoke(Document $wsdl, DOMElement $message): Message + public function __invoke(Document $wsdl, Element $message): Message { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); return new Message( - name: $message->getAttribute('name'), + name: $message->getAttribute('name') ?? '', parts: new Parts( ...$xpath->query('./wsdl:part', $message) - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static function (DOMElement $part) { + static function (Element $part) { $element = match (true) { - $part->hasAttribute('element') => QNamed::parse($part->getAttribute('element')), - $part->hasAttribute('type') => QNamed::parse($part->getAttribute('type')), + $part->hasAttribute('element') => QNamed::parse($part->getAttribute('element') ?? ''), + $part->hasAttribute('type') => QNamed::parse($part->getAttribute('type') ?? ''), default => null }; return new Part( - name: $part->getAttribute('name'), + name: $part->getAttribute('name') ?? '', element: $element, ); } @@ -48,9 +48,9 @@ public static function tryParse(Document $wsdl): Messages return new Messages( ...$xpath->query('/wsdl:definitions/wsdl:message') - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $message) => $parse($wsdl, $message) + static fn (Element $message) => $parse($wsdl, $message) ) ); } diff --git a/src/Parser/Definitions/NamespacesParser.php b/src/Parser/Definitions/NamespacesParser.php index 9686f9d..443d2b2 100644 --- a/src/Parser/Definitions/NamespacesParser.php +++ b/src/Parser/Definitions/NamespacesParser.php @@ -3,10 +3,11 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMNameSpaceNode; +use Dom\NamespaceInfo; use Soap\WsdlReader\Model\Definitions\Namespaces; use VeeWee\Xml\Dom\Document; use function Psl\Dict\merge; +use function Psl\Iter\reduce; use function VeeWee\Xml\Dom\Locator\document_element; use function VeeWee\Xml\Dom\Locator\Xmlns\recursive_linked_namespaces; @@ -18,22 +19,24 @@ public static function tryParse(Document $wsdl): Namespaces $allNamespaces = recursive_linked_namespaces($root); return new Namespaces( - $allNamespaces->reduce( + reduce( + $allNamespaces, /** * @param array $map * @return array */ - static fn (array $map, DOMNameSpaceNode $node): array - => merge($map, [(string)$node->localName => (string)$node->namespaceURI]), + static fn (array $map, NamespaceInfo $node): array + => merge($map, [(string)$node->prefix => (string)$node->namespaceURI]), [] ), - $allNamespaces->reduce( + reduce( + $allNamespaces, /** * @param array $map * @return array */ - static fn (array $map, DOMNameSpaceNode $node): array - => merge($map, [(string)$node->namespaceURI => (string)$node->localName]), + static fn (array $map, NamespaceInfo $node): array + => merge($map, [(string)$node->namespaceURI => (string)$node->prefix]), [] ) ); diff --git a/src/Parser/Definitions/OperationParamParser.php b/src/Parser/Definitions/OperationParamParser.php index d77f3b9..1b5fb24 100644 --- a/src/Parser/Definitions/OperationParamParser.php +++ b/src/Parser/Definitions/OperationParamParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Psl\Type; use Soap\WsdlReader\Model\Definitions\Param; use Soap\WsdlReader\Model\Definitions\Params; @@ -16,7 +16,7 @@ final class OperationParamParser { - public function __invoke(Document $wsdl, DOMElement $operation): Param + public function __invoke(Document $wsdl, Element $operation): Param { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); @@ -26,25 +26,25 @@ public function __invoke(Document $wsdl, DOMElement $operation): Param ); } - public static function tryParseOptionally(Document $wsdl, string $message, DOMElement $operation): ?Param + public static function tryParseOptionally(Document $wsdl, string $message, Element $operation): ?Param { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); - return wrap(static fn (): DOMElement => assert_element($xpath->querySingle('./wsdl:'.$message, $operation))) + return wrap(static fn (): Element => assert_element($xpath->querySingle('./wsdl:'.$message, $operation))) ->proceed( - static fn (DOMElement $messageElement): Param => + static fn (Element $messageElement): Param => (new self())($wsdl, $messageElement), static fn () => null ); } /** - * @param NodeList $params + * @param NodeList $params */ public static function tryParseList(Document $wsdl, NodeList $params): Params { return new Params( ...$params->map( - static fn (DOMElement $param): Param => (new self)($wsdl, $param) + static fn (Element $param): Param => (new self)($wsdl, $param) ) ); } diff --git a/src/Parser/Definitions/OperationParser.php b/src/Parser/Definitions/OperationParser.php index 047cfd1..e6753f5 100644 --- a/src/Parser/Definitions/OperationParser.php +++ b/src/Parser/Definitions/OperationParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Psl\Type; use Soap\WsdlReader\Model\Definitions\Operation; use Soap\Xml\Xpath\WsdlPreset; @@ -11,7 +11,7 @@ final class OperationParser { - public function __invoke(Document $wsdl, DOMElement $operation): Operation + public function __invoke(Document $wsdl, Element $operation): Operation { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); @@ -21,7 +21,7 @@ public function __invoke(Document $wsdl, DOMElement $operation): Operation output: OperationParamParser::tryParseOptionally($wsdl, 'output', $operation), fault: OperationParamParser::tryParseList( $wsdl, - $xpath->query('./wsdl:fault', $operation)->expectAllOfType(DOMElement::class) + $xpath->query('./wsdl:fault', $operation)->expectAllOfType(Element::class) ), documentation: $xpath->evaluate('string(./wsdl:documentation)', Type\string(), $operation), ); diff --git a/src/Parser/Definitions/PortParser.php b/src/Parser/Definitions/PortParser.php index 155f2f1..5f3e1cc 100644 --- a/src/Parser/Definitions/PortParser.php +++ b/src/Parser/Definitions/PortParser.php @@ -3,22 +3,22 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Psl\Type; use Soap\WsdlReader\Model\Definitions\Address; use Soap\WsdlReader\Model\Definitions\Port; use Soap\WsdlReader\Model\Definitions\QNamed; use Soap\Xml\Xpath\WsdlPreset; use VeeWee\Xml\Dom\Document; -use function VeeWee\Xml\Dom\Locator\Element\locate_by_tag_name; +use function VeeWee\Xml\Dom\Locator\Element\locate_by_namespaced_tag_name; final class PortParser { - public function __invoke(Document $wsdl, DOMElement $servicePort): Port + public function __invoke(Document $wsdl, Element $servicePort): Port { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); - $address = locate_by_tag_name($servicePort, 'address')->expectFirst('Unable to locate an address section in a service port!'); + $address = locate_by_namespaced_tag_name($servicePort, '*', 'address')->expectFirst('Unable to locate an address section in a service port!'); $type = (new AddressBindingTypeParser())($wsdl, $address); return new Port( diff --git a/src/Parser/Definitions/PortTypeParser.php b/src/Parser/Definitions/PortTypeParser.php index adb648d..37f5a7f 100644 --- a/src/Parser/Definitions/PortTypeParser.php +++ b/src/Parser/Definitions/PortTypeParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\Operations; use Soap\WsdlReader\Model\Definitions\PortType; use Soap\WsdlReader\Model\Definitions\PortTypes; @@ -12,17 +12,17 @@ final class PortTypeParser { - public function __invoke(Document $wsdl, DOMElement $portType): PortType + public function __invoke(Document $wsdl, Element $portType): PortType { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); return new PortType( - name: $portType->getAttribute('name'), + name: $portType->getAttribute('name') ?? '', operations: new Operations( ...$xpath->query('./wsdl:operation', $portType) - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $operation) => (new OperationParser())($wsdl, $operation) + static fn (Element $operation) => (new OperationParser())($wsdl, $operation) ) ), ); @@ -35,9 +35,9 @@ public static function tryParse(Document $wsdl): PortTypes return new PortTypes( ...$xpath->query('/wsdl:definitions/wsdl:portType') - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $portType) => $parse($wsdl, $portType) + static fn (Element $portType) => $parse($wsdl, $portType) ) ); } diff --git a/src/Parser/Definitions/SchemaParser.php b/src/Parser/Definitions/SchemaParser.php index 3d8c2a6..a571813 100644 --- a/src/Parser/Definitions/SchemaParser.php +++ b/src/Parser/Definitions/SchemaParser.php @@ -3,12 +3,17 @@ namespace Soap\WsdlReader\Parser\Definitions; +use DOMDocument; +use DOMElement; +use DOMNode; +use DOMNodeList; +use DOMXPath; use GoetasWebservices\XML\XSDReader\Schema\Schema; use GoetasWebservices\XML\XSDReader\SchemaReader; use Soap\WsdlReader\Parser\Context\ParserContext; use Soap\Xml\Xpath\WsdlPreset; use VeeWee\Xml\Dom\Document; -use function VeeWee\Xml\Dom\Locator\document_element; +use function VeeWee\Xml\ErrorHandling\disallow_libxml_false_returns; final class SchemaParser { @@ -35,13 +40,56 @@ public static function tryParse(Document $wsdl, ParserContext $context): Schema foreach ($context->knownSchemas as $namespace => $location) { $reader->addKnownNamespaceSchemaLocation($namespace, 'file://'.$location); $globalSchema->addSchema( - $reader->readNode(Document::fromXmlFile($location)->locate(document_element()), $namespace) + $reader->readNode(self::legacyDocumentElement($location), $namespace) ); } return $reader->readNodes( - [...$xpath->query('/wsdl:definitions/wsdl:types/schema:schema')], + self::legacySchemaNodes($wsdl), $wsdl->toUnsafeDocument()->documentURI ); } + + /** + * TODO: Can be removed once goetas-webservices/xsd-reader supports Dom\Element. + * + * @return list + */ + private static function legacySchemaNodes(Document $wsdl): array + { + $legacyDoc = $wsdl->toUnsafeLegacyDocument(); + $legacyXpath = new DOMXPath($legacyDoc); + $legacyXpath->registerNamespace('wsdl', 'http://schemas.xmlsoap.org/wsdl/'); + $legacyXpath->registerNamespace('schema', 'http://www.w3.org/2001/XMLSchema'); + + /** @var DOMNodeList $nodes */ + $nodes = disallow_libxml_false_returns( + $legacyXpath->query('/wsdl:definitions/wsdl:types/schema:schema'), + 'Unable to query schema nodes from legacy document' + ); + + $result = []; + foreach ($nodes as $node) { + assert($node instanceof DOMElement); + $result[] = $node; + } + + return $result; + } + + /** + * TODO: Can be removed once goetas-webservices/xsd-reader supports Dom\Element. + */ + private static function legacyDocumentElement(string $location): DOMElement + { + $doc = new DOMDocument(); + disallow_libxml_false_returns( + $doc->load($location), + 'Unable to load XML file: '.$location + ); + + assert($doc->documentElement instanceof DOMElement); + + return $doc->documentElement; + } } diff --git a/src/Parser/Definitions/ServiceParser.php b/src/Parser/Definitions/ServiceParser.php index 7641536..4a77a18 100644 --- a/src/Parser/Definitions/ServiceParser.php +++ b/src/Parser/Definitions/ServiceParser.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\Port; use Soap\WsdlReader\Model\Definitions\Ports; use Soap\WsdlReader\Model\Definitions\Service; @@ -13,17 +13,17 @@ final class ServiceParser { - public function __invoke(Document $wsdl, DOMElement $service): Service + public function __invoke(Document $wsdl, Element $service): Service { $xpath = $wsdl->xpath(new WsdlPreset($wsdl)); return new Service( - name: $service->getAttribute('name'), + name: $service->getAttribute('name') ?? '', ports: new Ports( ...$xpath->query('./wsdl:port', $service) - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $servicePort): Port => (new PortParser())($wsdl, $servicePort) + static fn (Element $servicePort): Port => (new PortParser())($wsdl, $servicePort) ) ) ); @@ -36,9 +36,9 @@ public static function tryParse(Document $wsdl): Services return new Services( ...$xpath->query('/wsdl:definitions/wsdl:service') - ->expectAllOfType(DOMElement::class) + ->expectAllOfType(Element::class) ->map( - static fn (DOMElement $service) => $parse($wsdl, $service) + static fn (Element $service) => $parse($wsdl, $service) ) ); } diff --git a/src/Parser/Definitions/SoapVersionParser.php b/src/Parser/Definitions/SoapVersionParser.php index 853db53..2f80b92 100644 --- a/src/Parser/Definitions/SoapVersionParser.php +++ b/src/Parser/Definitions/SoapVersionParser.php @@ -3,14 +3,14 @@ namespace Soap\WsdlReader\Parser\Definitions; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\SoapVersion; use Soap\Xml\Xmlns; use VeeWee\Xml\Dom\Document; final class SoapVersionParser { - public function __invoke(Document $wsdl, DOMElement $soapNamespacedElement): SoapVersion + public function __invoke(Document $wsdl, Element $soapNamespacedElement): SoapVersion { return match ($soapNamespacedElement->namespaceURI ?? '') { Xmlns::soap()->value() => SoapVersion::SOAP_11, diff --git a/src/Parser/Definitions/TargetNamespaceParser.php b/src/Parser/Definitions/TargetNamespaceParser.php index 74b90a9..cb2a3ff 100644 --- a/src/Parser/Definitions/TargetNamespaceParser.php +++ b/src/Parser/Definitions/TargetNamespaceParser.php @@ -12,8 +12,10 @@ public static function tryParse(Document $wsdl): ?Xmlns { $definitions = $wsdl->locateDocumentElement(); - return $definitions->hasAttribute('targetNamespace') - ? Xmlns::load($definitions->getAttribute('targetNamespace')) + $targetNamespace = $definitions->getAttribute('targetNamespace'); + + return $targetNamespace !== null + ? Xmlns::load($targetNamespace) : null; } } diff --git a/src/Parser/Strategy/HttpStrategy.php b/src/Parser/Strategy/HttpStrategy.php index b6c7f1b..db47b7d 100644 --- a/src/Parser/Strategy/HttpStrategy.php +++ b/src/Parser/Strategy/HttpStrategy.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Strategy; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\Implementation\Binding\BindingImplementation; use Soap\WsdlReader\Model\Definitions\Implementation\Binding\HttpBinding; use Soap\WsdlReader\Model\Definitions\Implementation\Message\HttpMessage; @@ -19,22 +19,22 @@ final class HttpStrategy implements StrategyInterface private const HTTP_NAMESPACE = 'http://schemas.xmlsoap.org/wsdl/http/'; private const MIME_NAMESPACE = 'http://schemas.xmlsoap.org/wsdl/mime/'; - public function parseBindingImplementation(Document $wsdl, DOMElement $binding): BindingImplementation + public function parseBindingImplementation(Document $wsdl, Element $binding): BindingImplementation { return new HttpBinding( - verb: $binding->getAttribute('verb'), + verb: $binding->getAttribute('verb') ?? '', transport: TransportType::tryFrom((string) $binding->namespaceURI) ?? TransportType::HTTP, ); } - public function parseOperationImplementation(Document $wsdl, DOMElement $operation): OperationImplementation + public function parseOperationImplementation(Document $wsdl, Element $operation): OperationImplementation { return new HttpOperation( - location: $operation->getAttribute('location'), + location: $operation->getAttribute('location') ?? '', ); } - public function parseMessageImplementation(Document $wsdl, DOMElement $message): MessageImplementation + public function parseMessageImplementation(Document $wsdl, Element $message): MessageImplementation { $info = children($message)->first(); $fallbackImplementation = new HttpMessage( @@ -53,7 +53,7 @@ public function parseMessageImplementation(Document $wsdl, DOMElement $message): ), self::MIME_NAMESPACE => new HttpMessage( contentType: match($info->localName) { - 'content' => $info->hasAttribute('type') ? $info->getAttribute('type'): 'application/xml', + 'content' => $info->getAttribute('type') ?? 'application/xml', 'mimeXml' => 'application/xml', 'multipartRelated' => 'Multipart/Related', default => 'application/xml' diff --git a/src/Parser/Strategy/SoapStrategy.php b/src/Parser/Strategy/SoapStrategy.php index 0ada2da..9324415 100644 --- a/src/Parser/Strategy/SoapStrategy.php +++ b/src/Parser/Strategy/SoapStrategy.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Strategy; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\BindingStyle; use Soap\WsdlReader\Model\Definitions\BindingUse; use Soap\WsdlReader\Model\Definitions\EncodingStyle; @@ -18,31 +18,31 @@ use Soap\WsdlReader\Parser\Definitions\SoapVersionParser; use VeeWee\Xml\Dom\Document; use VeeWee\Xml\Xmlns\Xmlns; -use function VeeWee\Xml\Dom\Locator\Element\locate_by_tag_name; +use function VeeWee\Xml\Dom\Locator\Element\locate_by_namespaced_tag_name; final class SoapStrategy implements StrategyInterface { - public function parseBindingImplementation(Document $wsdl, DOMElement $binding): BindingImplementation + public function parseBindingImplementation(Document $wsdl, Element $binding): BindingImplementation { return new SoapBinding( version: $this->parseVersionFromNode($wsdl, $binding), - transport: TransportType::from($binding->getAttribute('transport')), - style: BindingStyle::tryFromCaseInsensitive($binding->getAttribute('style')), + transport: TransportType::from($binding->getAttribute('transport') ?? ''), + style: BindingStyle::tryFromCaseInsensitive($binding->getAttribute('style') ?? ''), ); } - public function parseOperationImplementation(Document $wsdl, DOMElement $operation): OperationImplementation + public function parseOperationImplementation(Document $wsdl, Element $operation): OperationImplementation { return new SoapOperation( version: $this->parseVersionFromNode($wsdl, $operation), - action: $operation->getAttribute('soapAction'), - style: BindingStyle::tryFromCaseInsensitive($operation->getAttribute('style')), + action: $operation->getAttribute('soapAction') ?? '', + style: BindingStyle::tryFromCaseInsensitive($operation->getAttribute('style') ?? ''), ); } - public function parseMessageImplementation(Document $wsdl, DOMElement $message): MessageImplementation + public function parseMessageImplementation(Document $wsdl, Element $message): MessageImplementation { - $body = locate_by_tag_name($message, 'body')->item(0); + $body = locate_by_namespaced_tag_name($message, '*', 'body')->item(0); if (!$body) { return new SoapMessage( bindingUse: BindingUse::LITERAL, @@ -51,14 +51,16 @@ public function parseMessageImplementation(Document $wsdl, DOMElement $message): ); } + $namespace = $body->getAttribute('namespace'); + return new SoapMessage( - bindingUse: BindingUse::tryFromCaseInsensitive($body->getAttribute('use')) ?? BindingUse::LITERAL, - namespace: $body->hasAttribute('namespace') ? Xmlns::load($body->getAttribute('namespace')) : null, - encodingStyle: EncodingStyle::tryFrom($body->getAttribute('encodingStyle')), + bindingUse: BindingUse::tryFromCaseInsensitive($body->getAttribute('use') ?? '') ?? BindingUse::LITERAL, + namespace: $namespace !== null ? Xmlns::load($namespace) : null, + encodingStyle: EncodingStyle::tryFrom($body->getAttribute('encodingStyle') ?? ''), ); } - private function parseVersionFromNode(Document $wsdl, DOMElement $element): SoapVersion + private function parseVersionFromNode(Document $wsdl, Element $element): SoapVersion { return (new SoapVersionParser())($wsdl, $element); } diff --git a/src/Parser/Strategy/StrategyInterface.php b/src/Parser/Strategy/StrategyInterface.php index c092dfa..e607959 100644 --- a/src/Parser/Strategy/StrategyInterface.php +++ b/src/Parser/Strategy/StrategyInterface.php @@ -3,7 +3,7 @@ namespace Soap\WsdlReader\Parser\Strategy; -use DOMElement; +use Dom\Element; use Soap\WsdlReader\Model\Definitions\Implementation\Binding\BindingImplementation; use Soap\WsdlReader\Model\Definitions\Implementation\Message\MessageImplementation; use Soap\WsdlReader\Model\Definitions\Implementation\Operation\OperationImplementation; @@ -11,7 +11,7 @@ interface StrategyInterface { - public function parseBindingImplementation(Document $wsdl, DOMElement $binding): BindingImplementation; - public function parseOperationImplementation(Document $wsdl, DOMElement $operation): OperationImplementation; - public function parseMessageImplementation(Document $wsdl, DOMElement $message): MessageImplementation; + public function parseBindingImplementation(Document $wsdl, Element $binding): BindingImplementation; + public function parseOperationImplementation(Document $wsdl, Element $operation): OperationImplementation; + public function parseMessageImplementation(Document $wsdl, Element $message): MessageImplementation; } diff --git a/tests/PhpCompatibility/schema004.phpt b/tests/PhpCompatibility/schema004.phpt index d116be9..a35374e 100644 --- a/tests/PhpCompatibility/schema004.phpt +++ b/tests/PhpCompatibility/schema004.phpt @@ -13,4 +13,4 @@ EOF; test_schema($schema,'type="tns:testType"'); ?> --EXPECT-- -FATAL (GoetasWebservices\XML\XSDReader\Exception\TypeException):Can't find type named {http://test-uri/}#testType2, at line 13 in some.wsdl +FATAL (GoetasWebservices\XML\XSDReader\Exception\TypeException):Can't find type named {http://test-uri/}#testType2, at line 6 in some.wsdl