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 8f73254
Show file tree
Hide file tree
Showing 36 changed files with 812 additions and 31 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-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",
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
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?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\Metadata\Detector\Soap11ArrayDetector;
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 (!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<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
->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)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?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\Metadata\Detector\Soap12ArrayDetector;
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 (!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<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
->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)
);
}
}
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);
}
}
Loading

0 comments on commit 8f73254

Please sign in to comment.