diff --git a/composer.json b/composer.json index 82d0c93..419347a 100644 --- a/composer.json +++ b/composer.json @@ -15,8 +15,8 @@ "require": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "ext-dom": "*", - "goetas-webservices/xsd-reader": "^0.4.1", - "php-soap/engine": "^2.8", + "goetas-webservices/xsd-reader": "dev-merged-prs as 0.4.4", + "php-soap/engine": "dev-main as 2.8", "php-soap/wsdl": "^1.4", "php-soap/xml": "^1.6.0", "veewee/xml": "^3.0", @@ -38,5 +38,15 @@ "name": "Toon Verwerft", "email": "toonverwerft@gmail.com" } + ], + "repositories": [ + { + "type": "path", + "url": "../engine" + }, + { + "type": "path", + "url": "../xsd-reader" + } ] } diff --git a/src/Metadata/Converter/Methods/Converter/MessageToMetadataTypesConverter.php b/src/Metadata/Converter/Methods/Converter/MessageToMetadataTypesConverter.php index 0d42229..d24092d 100644 --- a/src/Metadata/Converter/Methods/Converter/MessageToMetadataTypesConverter.php +++ b/src/Metadata/Converter/Methods/Converter/MessageToMetadataTypesConverter.php @@ -8,6 +8,9 @@ use Soap\Engine\Metadata\Model\Type as EngineType; use Soap\Engine\Metadata\Model\TypeMeta; use Soap\Engine\Metadata\Model\XsdType; +use Soap\WsdlReader\Metadata\Detector\ApacheMapDetector; +use Soap\WsdlReader\Metadata\Detector\Soap11ArrayDetector; +use Soap\WsdlReader\Metadata\Detector\Soap12ArrayDetector; use Soap\WsdlReader\Model\Definitions\Message; use Soap\WsdlReader\Model\Definitions\Namespaces; use Soap\WsdlReader\Model\Definitions\Part; @@ -55,24 +58,34 @@ private function findXsdType(?QNamed $type): XsdType private function createSimpleTypeByQNamed(QNamed $type): XsdType { - $namespace = $this->namespaces->lookupNamespaceByQname($type); + $namespace = $this->namespaces->lookupNamespaceByQname($type)->unwrapOr(''); return XsdType::guess($type->localName) ->withXmlNamespaceName($type->prefix) - ->withXmlNamespace($namespace->unwrapOr('')) + ->withXmlNamespace($namespace) ->withXmlTypeName($type->localName) ->withMeta( - static fn (TypeMeta $meta): TypeMeta => $meta - ->withIsSimple(true) + fn (TypeMeta $meta): TypeMeta => $meta + ->withIsSimple($this->guessIfQnamedIsSimple($namespace, $type)) ->withIsElement(true) ); } + private function guessIfQNamedIsSimple(string $namespace, QNamed $type): bool + { + return match (true) { + Soap11ArrayDetector::detect($namespace, $type->localName), + Soap12ArrayDetector::detect($namespace, $type->localName), + ApacheMapDetector::detect($namespace, $type->localName) => false, + default => true + }; + } + private function createAnyType(): XsdType { $namespace = Xmlns::xsd()->value(); - return XsdType::guess('anyType') + return XsdType::any() ->withXmlTypeName('anyType') ->withXmlNamespaceName($this->namespaces->lookupNameFromNamespace($namespace)->unwrapOr('')) ->withXmlNamespace($namespace) diff --git a/src/Metadata/Converter/Types/Configurator/SoapEnc/Soap11ArrayConfigurator.php b/src/Metadata/Converter/Types/Configurator/SoapEnc/Soap11ArrayConfigurator.php new file mode 100644 index 0000000..aa24dd5 --- /dev/null +++ b/src/Metadata/Converter/Types/Configurator/SoapEnc/Soap11ArrayConfigurator.php @@ -0,0 +1,134 @@ +getRestriction()?->getBase(); + if (!$xsdType instanceof ComplexType || !$base instanceof ComplexType) { + return $metaType; + } + + $namespace = $base->getSchema()->getTargetNamespace(); + $typeName = $base->getName(); + if (!Soap11ArrayDetector::detect($namespace, $typeName)) { + return $metaType; + } + + return $this->parseFromElement($metaType, $xsdType, $context) + ->or($this->parseFromAttribute($metaType, $xsdType, $context)) + ->unwrapOr($metaType); + } + + /** + * @param ComplexType $xsdType + * @return Option + */ + private function parseFromElement(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): Option + { + if (!$xsdType->getElements()) { + return none(); + } + + $element = $xsdType->getElements()[0]; + if (!$element instanceof ElementSingle) { + return none(); + } + + $type = $element->getType(); + $typeName = $type?->getName(); + if (!$type || !$typeName) { + return none(); + } + + $namespace = $type->getSchema()->getTargetNamespace() ?? ''; + $arrayTypeInfo = new ArrayTypeInfo( + $context->knownNamespaces->lookupNameFromNamespace($namespace)->unwrap(), + $typeName, + '['.($element->getMax() > -1 ? (string) $element->getMax() : '').']' + ); + + return some( + $this->applyArrayTypInfoToMeta($metaType, $arrayTypeInfo, $namespace, $element->getName()) + ); + } + + /** + * @return Option + */ + private function parseFromAttribute(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): Option + { + $attrs = (new NamedAttributesDetector())($xsdType); + $arrayTypeResult = (new AttributeMetaInformationDetector())($attrs, 'arrayType', 'arrayType'); + + if ($arrayTypeResult->isNone()) { + return none(); + } + + $arrayType = $arrayTypeResult->unwrap(); + $arrayTypeInfo = ArrayTypeInfo::parseSoap11($arrayType->getValue()); + if (!$arrayTypeInfo->prefix) { + $arrayTypeInfo = $arrayTypeInfo->withPrefix( + $context->knownNamespaces->lookupNameFromNamespace( + $arrayType->getContextSchema()->getTargetNamespace() ?? '' + )->unwrap() + ); + } + $namespace = $context->knownNamespaces->lookupNamespaceFromName($arrayTypeInfo->prefix)->unwrap(); + + return some($this->applyArrayTypInfoToMeta($metaType, $arrayTypeInfo, $namespace)); + } + + private function applyArrayTypInfoToMeta( + MetaType $metaType, + ArrayTypeInfo $arrayTypeInfo, + string $namespace, + string $arrayNodeName = 'item' + ): MetaType { + return $metaType + ->withBaseType('array') + ->withMemberTypes([$arrayTypeInfo->type]) + ->withMeta( + static fn (TypeMeta $meta): TypeMeta => $meta + ->withIsElement(true) + ->withIsSimple(false) + ->withIsList(true) + ->withIsAlias(true) + ->withMinOccurs(0) + ->withMaxOccurs($arrayTypeInfo->getMaxOccurs()) + ->withUnions( + filter_nulls([ + [ + 'type' => $arrayTypeInfo->type, + 'namespace' => $namespace, + 'isList' => false, + ] + ]) + ) + ->withArrayType([ + 'type' => $arrayTypeInfo->toString(), + 'itemType' => $arrayTypeInfo->itemType(), + 'namespace' => $namespace, + ]) + ->withArrayNodeName($arrayNodeName) + ); + } +} diff --git a/src/Metadata/Converter/Types/Configurator/SoapEnc/Soap12ArrayConfigurator.php b/src/Metadata/Converter/Types/Configurator/SoapEnc/Soap12ArrayConfigurator.php new file mode 100644 index 0000000..0352af9 --- /dev/null +++ b/src/Metadata/Converter/Types/Configurator/SoapEnc/Soap12ArrayConfigurator.php @@ -0,0 +1,141 @@ +getRestriction()?->getBase(); + if (!$xsdType instanceof ComplexType || !$base instanceof ComplexType) { + return $metaType; + } + + $namespace = $base->getSchema()->getTargetNamespace(); + $typeName = $base->getName(); + if (!Soap12ArrayDetector::detect($namespace, $typeName)) { + return $metaType; + } + + return $this->parseFromElement($metaType, $xsdType, $context) + ->or($this->parseFromAttribute($metaType, $xsdType, $context)) + ->unwrapOr($metaType); + } + + /** + * @param ComplexType $xsdType + * @return Option + */ + private function parseFromElement(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): Option + { + if (!$xsdType->getElements()) { + return none(); + } + + $element = $xsdType->getElements()[0]; + if (!$element instanceof ElementSingle) { + return none(); + } + + $type = $element->getType(); + $typeName = $type?->getName(); + if (!$type || !$typeName) { + return none(); + } + + $namespace = $type->getSchema()->getTargetNamespace() ?? ''; + $arrayTypeInfo = new ArrayTypeInfo( + $context->knownNamespaces->lookupNameFromNamespace($namespace)->unwrap(), + $typeName, + '['.($element->getMax() > -1 ? (string) $element->getMax() : '').']' + ); + + return some( + $this->applyArrayTypInfoToMeta($metaType, $arrayTypeInfo, $namespace, $element->getName()) + ); + } + + /** + * @return Option + */ + private function parseFromAttribute(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): Option + { + $attrs = (new NamedAttributesDetector())($xsdType); + + $itemTypeResult = (new AttributeMetaInformationDetector())($attrs, 'itemType', 'itemType'); + $arraySizeResult = (new AttributeMetaInformationDetector())($attrs, 'arraySize', 'arraySize'); + + if (!$itemTypeResult->isSome()) { + return none(); + } + + $itemType = $itemTypeResult->unwrap(); + $arrayTypeInfo = ArrayTypeInfo::parseSoap12( + $itemType->getValue(), + $arraySizeResult->map(static fn (MetaInformation $meta): string => $meta->getValue())->unwrapOr('*') + ); + + if (!$arrayTypeInfo->prefix) { + $arrayTypeInfo = $arrayTypeInfo->withPrefix( + $context->knownNamespaces->lookupNameFromNamespace( + $itemType->getContextSchema()->getTargetNamespace() ?? '' + )->unwrap() + ); + } + $namespace = $context->knownNamespaces->lookupNamespaceFromName($arrayTypeInfo->prefix)->unwrap(); + + return some($this->applyArrayTypInfoToMeta($metaType, $arrayTypeInfo, $namespace)); + } + + private function applyArrayTypInfoToMeta( + MetaType $metaType, + ArrayTypeInfo $arrayTypeInfo, + string $namespace, + string $arrayNodeName = 'item' + ): MetaType { + return $metaType + ->withBaseType('array') + ->withMemberTypes([$arrayTypeInfo->type]) + ->withMeta( + static fn (TypeMeta $meta): TypeMeta => $meta + ->withIsElement(true) + ->withIsSimple(false) + ->withIsList(true) + ->withIsAlias(true) + ->withMinOccurs(0) + ->withMaxOccurs($arrayTypeInfo->getMaxOccurs()) + ->withUnions( + filter_nulls([ + [ + 'type' => $arrayTypeInfo->type, + 'namespace' => $namespace, + 'isList' => false, + ] + ]) + ) + ->withArrayType([ + 'type' => $arrayTypeInfo->toString(), + 'itemType' => $arrayTypeInfo->itemType(), + 'namespace' => $namespace, + ]) + ->withArrayNodeName($arrayNodeName) + ); + } +} diff --git a/src/Metadata/Converter/Types/Configurator/SoapEnc/SoapEncConfigurator.php b/src/Metadata/Converter/Types/Configurator/SoapEnc/SoapEncConfigurator.php new file mode 100644 index 0000000..768d85f --- /dev/null +++ b/src/Metadata/Converter/Types/Configurator/SoapEnc/SoapEncConfigurator.php @@ -0,0 +1,21 @@ + (new Soap11ArrayConfigurator())($metaType, $xsdType, $context), + static fn (MetaType $metaType): EngineType => (new Soap12ArrayConfigurator())($metaType, $xsdType, $context), + )($metaType); + } +} diff --git a/src/Metadata/Converter/Types/Configurator/TypeConfigurator.php b/src/Metadata/Converter/Types/Configurator/TypeConfigurator.php index d9e20fa..2a24cce 100644 --- a/src/Metadata/Converter/Types/Configurator/TypeConfigurator.php +++ b/src/Metadata/Converter/Types/Configurator/TypeConfigurator.php @@ -5,6 +5,7 @@ use GoetasWebservices\XML\XSDReader\Schema\Type\Type as XsdType; use Soap\Engine\Metadata\Model\XsdType as MetaType; +use Soap\WsdlReader\Metadata\Converter\Types\Configurator\SoapEnc\SoapEncConfigurator; use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext; use function Psl\Fun\pipe; @@ -23,6 +24,7 @@ public function __invoke(MetaType $metaType, mixed $xsdType, TypesConverterConte static fn (MetaType $metaType): MetaType => (new AbstractConfigurator())($metaType, $xsdType, $context), static fn (MetaType $metaType): MetaType => (new ExtendsConfigurator())($metaType, $xsdType, $context), static fn (MetaType $metaType): MetaType => (new SimpleTypeConfigurator())($metaType, $xsdType, $context), + static fn (MetaType $metaType): MetaType => (new SoapEncConfigurator())($metaType, $xsdType, $context), )($metaType); } } diff --git a/src/Metadata/Converter/Types/Detector/AttributeMetaInformationDetector.php b/src/Metadata/Converter/Types/Detector/AttributeMetaInformationDetector.php new file mode 100644 index 0000000..6742921 --- /dev/null +++ b/src/Metadata/Converter/Types/Detector/AttributeMetaInformationDetector.php @@ -0,0 +1,36 @@ + $attributes + * @return Option + */ + public function __invoke(array $attributes, string $attributeName, string $metadataName): Option + { + $attribute = $attributes[$attributeName] ?? null; + if (!$attribute instanceof AttributeSingle) { + return none(); + } + + $meta = search( + $attribute->getMeta(), + static fn (MetaInformation $meta): bool => $meta->getName() === $metadataName + ); + + return from_nullable($meta); + } +} diff --git a/src/Metadata/Converter/Types/Detector/NamedAttributesDetector.php b/src/Metadata/Converter/Types/Detector/NamedAttributesDetector.php new file mode 100644 index 0000000..91ec373 --- /dev/null +++ b/src/Metadata/Converter/Types/Detector/NamedAttributesDetector.php @@ -0,0 +1,57 @@ + + */ + public function __invoke(Type $type): array + { + if (!$type instanceof AttributeContainer) { + return []; + } + + return reindex( + flat_map( + $type->getAttributes(), + $this->flattenContainer(...) + ), + static fn (AttributeItem $item): string => $item->getName() + ); + } + + /** + * @return list + */ + private function flattenContainer(AttributeItem $current): array + { + if (!$current instanceof AttributeContainer) { + return [$current]; + } + + return reduce( + $current->getAttributes(), + /** + * @param list $carry + * @param AttributeItem $attribute + * + * @return list + */ + fn (array $carry, AttributeItem $attribute) => [ + ...$carry, + ...$this->flattenContainer($attribute) + ], + [] + ); + } +} diff --git a/src/Metadata/Converter/Types/SoapEnc/ArrayTypeInfo.php b/src/Metadata/Converter/Types/SoapEnc/ArrayTypeInfo.php new file mode 100644 index 0000000..1bb0685 --- /dev/null +++ b/src/Metadata/Converter/Types/SoapEnc/ArrayTypeInfo.php @@ -0,0 +1,135 @@ +\d*)\]$/i'; + + public function __construct( + public readonly string $prefix, + public readonly string $type, + public readonly string $rank + ) { + } + + public static function parseSoap11(string $type): self + { + [$prefix, $arrayType] = (new QnameParser())($type); + $parts = explode('[', $arrayType, 2); + + if (count($parts) !== 2) { + throw new InvalidArgumentException( + 'Invalid arrayType given. Expected format: qname[rank], got: "'.$type.'".' + ); + } + + [$type, $rank] = $parts; + + return new self($prefix, $type, '['.$rank); + } + + /** + * @see https://www.w3.org/TR/soap12-part2/#arraySizeattr + * + * The type of the arraySize attribute information item is enc:arraySize. The value of the arraySize attribute information item MUST conform to the following EBNF grammar + * [1] arraySizeValue ::= ("*" | concreteSize) nextConcreteSize* + * [2] nextConcreteSize ::= whitespace concreteSize + * [3] concreteSize ::= [0-9]+ + * [4] white space ::= (#x20 | #x9 | #xD | #xA)+ + * + * Pattern of value: (\*|(\d+))(\s+\d+)* + * + * The arraySize attribute conveys a suggested mapping of a SOAP array to a multi-dimensional program data structure. The cardinality of the arraySize list represents the number of dimensions, with individual values providing the extents of the respective dimensions. When SOAP encoding multidimensional arrays, nodes are selected such that the last subscript (i.e., the subscript corresponding to the last specified dimension) varies most rapidly, and so on with the first varying most slowly. An asterisk MAY be used only in place of the first size to indicate a dimension of unspecified extent; asterisks MUST NOT appear in other positions in the list. The default value of the arraySize attribute information item is "*", i.e., a single dimension of unspecified extent. + */ + public static function parseSoap12(string $itemType, string $arraySize): self + { + [$prefix, $type] = (new QnameParser())($itemType); + + $parts = filter( + split($arraySize, '/\s+/'), + static fn (string $part): bool => $part !== '' + ); + $partsCount = count($parts); + + $rank = match ($partsCount) { + 0 => '[]', + 1 => '['.($parts[0] === '*' ? '' : $parts[0]).']', + default => '[,]['.($parts[0] === '*' ? '-1' : $parts[0]).']', + }; + + return new self($prefix, $type, $rank); + } + + public function isMultiDimensional(): bool + { + return contains($this->rank, ','); + } + + public function getMaxOccurs(): int + { + $parts = first_match($this->rank, self::PATTERN_A_RANK, shape([ + 'maxOccurs' => optional(string()), + ])); + + $maxOccurs = $parts['maxOccurs'] ?? null; + if (!$maxOccurs) { + return -1; + } + + return int()->coerce($maxOccurs); + } + + public function toString(): string + { + return sprintf( + '%s%s%s', + $this->prefix ? $this->prefix . ':' : '', + $this->type, + $this->rank, + ); + } + + public function itemType(): string + { + return sprintf( + '%s%s%s', + $this->prefix ? $this->prefix . ':' : '', + $this->type, + replace($this->rank, self::PATTERN_A_RANK, ''), + ); + } + + public function withPrefix(string $prefix): self + { + return new self($prefix, $this->type, $this->rank); + } +} diff --git a/src/Metadata/Detector/ApacheMapDetector.php b/src/Metadata/Detector/ApacheMapDetector.php new file mode 100644 index 0000000..140e37b --- /dev/null +++ b/src/Metadata/Detector/ApacheMapDetector.php @@ -0,0 +1,14 @@ +value; + } +} diff --git a/src/Metadata/Detector/Soap12ArrayDetector.php b/src/Metadata/Detector/Soap12ArrayDetector.php new file mode 100644 index 0000000..c656601 --- /dev/null +++ b/src/Metadata/Detector/Soap12ArrayDetector.php @@ -0,0 +1,14 @@ + + */ + public static function listKnownSoap12Version(): array + { + return [ + self::SOAP_12_2001_09->value, + self::SOAP_12_2001_12->value, + self::SOAP_12_2003_05->value + ]; + } + + public static function isSoap12Encoding(string $namespace): bool + { + return in_array($namespace, self::listKnownSoap12Version(), true); + } } diff --git a/tests/PhpCompatibility/schema023.phpt b/tests/PhpCompatibility/schema023.phpt index 3d68bff..55c4e6f 100644 --- a/tests/PhpCompatibility/schema023.phpt +++ b/tests/PhpCompatibility/schema023.phpt @@ -19,4 +19,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema024.phpt b/tests/PhpCompatibility/schema024.phpt index a0b67b6..b9dd5b5 100644 --- a/tests/PhpCompatibility/schema024.phpt +++ b/tests/PhpCompatibility/schema024.phpt @@ -21,4 +21,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema025.phpt b/tests/PhpCompatibility/schema025.phpt index 5376635..70586fd 100644 --- a/tests/PhpCompatibility/schema025.phpt +++ b/tests/PhpCompatibility/schema025.phpt @@ -20,4 +20,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema026.phpt b/tests/PhpCompatibility/schema026.phpt index 94a614d..d699349 100644 --- a/tests/PhpCompatibility/schema026.phpt +++ b/tests/PhpCompatibility/schema026.phpt @@ -21,4 +21,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema027.phpt b/tests/PhpCompatibility/schema027.phpt index ea704d9..656ac9f 100644 --- a/tests/PhpCompatibility/schema027.phpt +++ b/tests/PhpCompatibility/schema027.phpt @@ -19,4 +19,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema028.phpt b/tests/PhpCompatibility/schema028.phpt index bb830e0..b6b6e4b 100644 --- a/tests/PhpCompatibility/schema028.phpt +++ b/tests/PhpCompatibility/schema028.phpt @@ -20,4 +20,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema029.phpt b/tests/PhpCompatibility/schema029.phpt index 7349bb9..96aa840 100644 --- a/tests/PhpCompatibility/schema029.phpt +++ b/tests/PhpCompatibility/schema029.phpt @@ -22,4 +22,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema049.phpt b/tests/PhpCompatibility/schema049.phpt index b05698a..26378e7 100644 --- a/tests/PhpCompatibility/schema049.phpt +++ b/tests/PhpCompatibility/schema049.phpt @@ -31,4 +31,6 @@ Types: int $int int $int2 } - > http://test-uri/:testType extends testType2 + > http://test-uri/:testType extends testType2 { + int $int2 + } diff --git a/tests/PhpCompatibility/schema056.phpt b/tests/PhpCompatibility/schema056.phpt index 5b6a659..1439e30 100644 --- a/tests/PhpCompatibility/schema056.phpt +++ b/tests/PhpCompatibility/schema056.phpt @@ -19,4 +19,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema057.phpt b/tests/PhpCompatibility/schema057.phpt index 1975393..c62f657 100644 --- a/tests/PhpCompatibility/schema057.phpt +++ b/tests/PhpCompatibility/schema057.phpt @@ -21,4 +21,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema058.phpt b/tests/PhpCompatibility/schema058.phpt index bc21649..d91ddf3 100644 --- a/tests/PhpCompatibility/schema058.phpt +++ b/tests/PhpCompatibility/schema058.phpt @@ -20,4 +20,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema059.phpt b/tests/PhpCompatibility/schema059.phpt index bb84d1d..7cc8e75 100644 --- a/tests/PhpCompatibility/schema059.phpt +++ b/tests/PhpCompatibility/schema059.phpt @@ -21,4 +21,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema060.phpt b/tests/PhpCompatibility/schema060.phpt index 2aaf421..97353a2 100644 --- a/tests/PhpCompatibility/schema060.phpt +++ b/tests/PhpCompatibility/schema060.phpt @@ -20,4 +20,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema061.phpt b/tests/PhpCompatibility/schema061.phpt index 6808bfa..b89068b 100644 --- a/tests/PhpCompatibility/schema061.phpt +++ b/tests/PhpCompatibility/schema061.phpt @@ -22,4 +22,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema071.phpt b/tests/PhpCompatibility/schema071.phpt index 93f8c87..81c45f7 100644 --- a/tests/PhpCompatibility/schema071.phpt +++ b/tests/PhpCompatibility/schema071.phpt @@ -19,4 +19,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema072.phpt b/tests/PhpCompatibility/schema072.phpt index c53093c..3011b23 100644 --- a/tests/PhpCompatibility/schema072.phpt +++ b/tests/PhpCompatibility/schema072.phpt @@ -21,5 +21,5 @@ Methods: > test(testElement $testParam): void Types: - > http://test-uri/:testType extends Array - > http://test-uri/:testElement extends Array + > http://test-uri/:testType extends Array = (list) + > http://test-uri/:testElement extends Array = (list) diff --git a/tests/PhpCompatibility/schema073.phpt b/tests/PhpCompatibility/schema073.phpt index a5796ca..175ad42 100644 --- a/tests/PhpCompatibility/schema073.phpt +++ b/tests/PhpCompatibility/schema073.phpt @@ -20,5 +20,5 @@ Methods: > test(testElement $testParam): void Types: - > http://test-uri/:testType extends Array - > http://test-uri/:testElement extends Array + > http://test-uri/:testType extends Array = (list) + > http://test-uri/:testElement extends Array = (list) diff --git a/tests/PhpCompatibility/schema081.phpt b/tests/PhpCompatibility/schema081.phpt index ac3c7a5..3962ec5 100644 --- a/tests/PhpCompatibility/schema081.phpt +++ b/tests/PhpCompatibility/schema081.phpt @@ -19,4 +19,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema082.phpt b/tests/PhpCompatibility/schema082.phpt index 935ffff..6b7e630 100644 --- a/tests/PhpCompatibility/schema082.phpt +++ b/tests/PhpCompatibility/schema082.phpt @@ -21,4 +21,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema083.phpt b/tests/PhpCompatibility/schema083.phpt index 5b33fc8..9b9180b 100644 --- a/tests/PhpCompatibility/schema083.phpt +++ b/tests/PhpCompatibility/schema083.phpt @@ -20,4 +20,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/schema084.phpt b/tests/PhpCompatibility/schema084.phpt index 1b3b964..a1a1a27 100644 --- a/tests/PhpCompatibility/schema084.phpt +++ b/tests/PhpCompatibility/schema084.phpt @@ -21,4 +21,4 @@ Methods: > test(testType $testParam): void Types: - > http://test-uri/:testType extends Array + > http://test-uri/:testType extends Array = (list) diff --git a/tests/PhpCompatibility/test_schema.inc b/tests/PhpCompatibility/test_schema.inc index 31e5391..df55202 100644 --- a/tests/PhpCompatibility/test_schema.inc +++ b/tests/PhpCompatibility/test_schema.inc @@ -64,6 +64,10 @@ function test_schema($schema, $type, $style="rpc",$use="encoded", $attributeForm echo "Types:" . PHP_EOL; echo implode(PHP_EOL, $metadata->getTypes()->map(fn(Type $type) => ' > ' . (new LongTypeFormatter())($type))); echo PHP_EOL . PHP_EOL; + + + //var_dump($metadata->getTypes()->fetchFirstByName('testType')->getXsdType()); + } catch (\Exception $exception) { echo "FATAL (".get_class($exception).'):'. $exception->getMessage(); } diff --git a/tests/Unit/Metadata/Coverter/Types/SoapEnc/ArrayTypeInfoTest.php b/tests/Unit/Metadata/Coverter/Types/SoapEnc/ArrayTypeInfoTest.php new file mode 100644 index 0000000..a838ddf --- /dev/null +++ b/tests/Unit/Metadata/Coverter/Types/SoapEnc/ArrayTypeInfoTest.php @@ -0,0 +1,163 @@ +prefix); + static::assertSame($expectedType, $info->type); + static::assertSame($expectedRank, $info->rank); + static::assertSame($expectedItemType, $info->itemType()); + static::assertSame($expectedIsMultiDimensional, $info->isMultiDimensional()); + static::assertSame($expectedMaxOccurs, $info->getMaxOccurs()); + static::assertSame($raw, $info->toString()); + } + + /** + * + * @dataProvider provideSoap12ArrayTypes + */ + public function test_it_can_parse_array_type_information_from_soap_12_information( + string $itemType, + string $arraySize, + string $expectedPrefix, + string $expectedType, + string $expectedRank, + string $expectedItemType, + bool $expectedIsMultiDimensional, + int $expectedMaxOccurs, + string $expectedSoap11Type + ): void { + $info = ArrayTypeInfo::parseSoap12($itemType, $arraySize); + + static::assertSame($expectedPrefix, $info->prefix); + static::assertSame($expectedType, $info->type); + static::assertSame($expectedRank, $info->rank); + static::assertSame($expectedItemType, $info->itemType()); + static::assertSame($expectedIsMultiDimensional, $info->isMultiDimensional()); + static::assertSame($expectedMaxOccurs, $info->getMaxOccurs()); + static::assertSame($expectedSoap11Type, $info->toString()); + } + + + public function test_it_invalid_format(): void + { + $this->expectException(InvalidArgumentException::class); + + ArrayTypeInfo::parseSoap11('int'); + } + + public static function provideSoap11ArrayTypes(): iterable + { + yield 'regular array' => [ + 'raw' => 'int[]', + 'expectedPrefix' => '', + 'expectedType' => 'int', + 'expectedRank' => '[]', + 'expectedItemType' => 'int', + 'expectedIsMultiDimensional' => false, + 'expectedMaxOccurs' => -1, + ]; + + yield 'prefixed regular array' => [ + 'raw' => 'xsd:int[]', + 'expectedPrefix' => 'xsd', + 'expectedType' => 'int', + 'expectedRank' => '[]', + 'expectedItemType' => 'xsd:int', + 'expectedIsMultiDimensional' => false, + 'expectedMaxOccurs' => -1, + ]; + + yield 'sized regular array' => [ + 'raw' => 'int[5]', + 'expectedPrefix' => '', + 'expectedType' => 'int', + 'expectedRank' => '[5]', + 'expectedItemType' => 'int', + 'expectedIsMultiDimensional' => false, + 'expectedMaxOccurs' => 5, + ]; + + yield 'multi dimensional array comma syntax' => [ + 'raw' => 'int[,][3]', + 'expectedPrefix' => '', + 'expectedType' => 'int', + 'expectedRank' => '[,][3]', + 'expectedItemType' => 'int[,]', + 'expectedIsMultiDimensional' => true, + 'expectedMaxOccurs' => 3, + ]; + } + + public static function provideSoap12ArrayTypes(): iterable + { + yield 'regular array' => [ + 'itemType' => 'int', + 'arraySize' => '*', + 'expectedPrefix' => '', + 'expectedType' => 'int', + 'expectedRank' => '[]', + 'expectedItemType' => 'int', + 'expectedIsMultiDimensional' => false, + 'expectedMaxOccurs' => -1, + 'expectedSoap11Type' => 'int[]', + ]; + + yield 'prefixed regular array' => [ + 'itemType' => 'xsd:int', + 'arraySize' => '*', + 'expectedPrefix' => 'xsd', + 'expectedType' => 'int', + 'expectedRank' => '[]', + 'expectedItemType' => 'xsd:int', + 'expectedIsMultiDimensional' => false, + 'expectedMaxOccurs' => -1, + 'expectedSoap11Type' => 'xsd:int[]', + ]; + + yield 'sized regular array' => [ + 'itemType' => 'int', + 'arraySize' => '5', + 'expectedPrefix' => '', + 'expectedType' => 'int', + 'expectedRank' => '[5]', + 'expectedItemType' => 'int', + 'expectedIsMultiDimensional' => false, + 'expectedMaxOccurs' => 5, + 'expectedSoap11Type' => 'int[5]', + ]; + + yield 'multi dimensional array comma syntax' => [ + 'itemType' => 'int', + 'arraySize' => '3 *', + 'expectedPrefix' => '', + 'expectedType' => 'int', + 'expectedRank' => '[,][3]', + 'expectedItemType' => 'int[,]', + 'expectedIsMultiDimensional' => true, + 'expectedMaxOccurs' => 3, + 'expectedSoap11Type' => 'int[,][3]', + ]; + } +}