Skip to content

Commit

Permalink
[WIP] Read additional meta-information from special soap-enc types
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed May 31, 2024
1 parent 399615a commit ad074aa
Show file tree
Hide file tree
Showing 32 changed files with 741 additions and 26 deletions.
14 changes: 12 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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-restrictions-all 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",
Expand All @@ -38,5 +38,15 @@
"name": "Toon Verwerft",
"email": "[email protected]"
}
],
"repositories": [
{
"type": "path",
"url": "../engine"
},
{
"type": "path",
"url": "../xsd-reader"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);

namespace Soap\WsdlReader\Metadata\Converter\Types\Configurator\SoapEnc;

use GoetasWebservices\XML\XSDReader\Schema\Element\ElementSingle;
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type as XsdType;
use Psl\Option\Option;
use Soap\Engine\Metadata\Model\TypeMeta;
use Soap\Engine\Metadata\Model\XsdType as MetaType;
use Soap\WsdlReader\Metadata\Converter\Types\Detector\AttributeMetaInformationDetector;
use Soap\WsdlReader\Metadata\Converter\Types\Detector\NamedAttributesDetector;
use Soap\WsdlReader\Metadata\Converter\Types\SoapEnc\ArrayTypeInfo;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
use function Psl\Option\none;
use function Psl\Option\some;
use function Psl\Vec\filter_nulls;

final class Soap11ArrayConfigurator
{
public function __invoke(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): MetaType
{
$base = $xsdType->getRestriction()?->getBase();
if (!$xsdType instanceof ComplexType || !$base instanceof ComplexType) {
return $metaType;
}

$namespace = $base->getSchema()->getTargetNamespace();
$typeName = $base->getName();
if ($typeName !== 'Array' || $namespace !== EncodingStyle::SOAP_11->value) {
return $metaType;
}

return $this->parseFromElement($metaType, $xsdType, $context)
->or($this->parseFromAttribute($metaType, $xsdType, $context))
->unwrapOr($metaType);
}

/**
* @param ComplexType $xsdType
* @return Option<MetaType>
*/
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<MetaType>
*/
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
->withIsList(true)
->withIsAlias(true)
->withMinOccurs(0)
->withMaxOccurs($arrayTypeInfo->getMaxOccurs())
->withUnions(
filter_nulls([
[
'type' => $arrayTypeInfo->type,
'namespace' => $namespace,
'isList' => $arrayTypeInfo->isMultiDimensional(),
]
])
)
->withArrayType([
'type' => $arrayTypeInfo->toString(),
'itemType' => $arrayTypeInfo->itemType(),
'namespace' => $namespace,
])
->withArrayNodeName($arrayNodeName)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php
declare(strict_types=1);

namespace Soap\WsdlReader\Metadata\Converter\Types\Configurator\SoapEnc;

use GoetasWebservices\XML\XSDReader\Schema\Element\ElementSingle;
use GoetasWebservices\XML\XSDReader\Schema\MetaInformation;
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type as XsdType;
use Psl\Option\Option;
use Soap\Engine\Metadata\Model\TypeMeta;
use Soap\Engine\Metadata\Model\XsdType as MetaType;
use Soap\WsdlReader\Metadata\Converter\Types\Detector\AttributeMetaInformationDetector;
use Soap\WsdlReader\Metadata\Converter\Types\Detector\NamedAttributesDetector;
use Soap\WsdlReader\Metadata\Converter\Types\SoapEnc\ArrayTypeInfo;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
use function Psl\Option\none;
use function Psl\Option\some;
use function Psl\Vec\filter_nulls;

final class Soap12ArrayConfigurator
{
public function __invoke(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): MetaType
{
$base = $xsdType->getRestriction()?->getBase();
if (!$xsdType instanceof ComplexType || !$base instanceof ComplexType) {
return $metaType;
}

$namespace = $base->getSchema()->getTargetNamespace();
$typeName = $base->getName();
if ($typeName !== 'Array' || !in_array($namespace, EncodingStyle::listKnownSoap12Version(), true)) {
return $metaType;
}

return $this->parseFromElement($metaType, $xsdType, $context)
->or($this->parseFromAttribute($metaType, $xsdType, $context))
->unwrapOr($metaType);
}

/**
* @param ComplexType $xsdType
* @return Option<MetaType>
*/
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<MetaType>
*/
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
->withIsList(true)
->withIsAlias(true)
->withMinOccurs(0)
->withMaxOccurs($arrayTypeInfo->getMaxOccurs())
->withUnions(
filter_nulls([
[
'type' => $arrayTypeInfo->type,
'namespace' => $namespace,
'isList' => $arrayTypeInfo->isMultiDimensional(),
]
])
)
->withArrayType([
'type' => $arrayTypeInfo->toString(),
'itemType' => $arrayTypeInfo->itemType(),
'namespace' => $namespace,
])
->withArrayNodeName($arrayNodeName)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);

namespace Soap\WsdlReader\Metadata\Converter\Types\Configurator\SoapEnc;

use GoetasWebservices\XML\XSDReader\Schema\Type\Type as XsdType;
use Soap\Engine\Metadata\Model\XsdType as EngineType;
use Soap\Engine\Metadata\Model\XsdType as MetaType;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use function Psl\Fun\pipe;

final class SoapEncConfigurator
{
public function __invoke(MetaType $metaType, XsdType $xsdType, TypesConverterContext $context): MetaType
{
return pipe(
static fn (MetaType $metaType): EngineType => (new Soap11ArrayConfigurator())($metaType, $xsdType, $context),
static fn (MetaType $metaType): EngineType => (new Soap12ArrayConfigurator())($metaType, $xsdType, $context),
)($metaType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);

namespace Soap\WsdlReader\Metadata\Converter\Types\Detector;

use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeSingle;
use GoetasWebservices\XML\XSDReader\Schema\MetaInformation;
use Psl\Option\Option;
use function Psl\Iter\search;
use function Psl\Option\from_nullable;
use function Psl\Option\none;

final class AttributeMetaInformationDetector
{
/**
* Detect meta information for a given attribute inside a dictionary of attributes grouped by name.
*
* @param array<string, AttributeItem> $attributes
* @return Option<MetaInformation>
*/
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);
}
}
Loading

0 comments on commit ad074aa

Please sign in to comment.