Skip to content

Commit

Permalink
Prefix attribute type-names with parent type name.
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Jan 2, 2025
1 parent 1128124 commit 2d84d9f
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 6 deletions.
16 changes: 13 additions & 3 deletions src/Metadata/Converter/SchemaToTypesConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use GoetasWebservices\XML\XSDReader\Schema\Schema;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
use Soap\Engine\Metadata\Collection\TypeCollection;
use Soap\WsdlReader\Metadata\Converter\Types\ParentContext;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use Soap\WsdlReader\Metadata\Converter\Types\Visitor\ElementVisitor;
use Soap\WsdlReader\Metadata\Converter\Types\Visitor\TypeVisitor;
Expand All @@ -22,15 +23,24 @@ public function __invoke(Schema $schema, TypesConverterContext $context): TypeCo
...filter_nulls([
...flat_map(
$schema->getTypes(),
static fn (Type $type): TypeCollection => (new TypeVisitor())($type, $context)
static fn (Type $type): TypeCollection => (new TypeVisitor())(
$type,
$context->onParent(new ParentContext($type))
)
),
...flat_map(
$schema->getElements(),
static fn (ElementDef $element): TypeCollection => (new ElementVisitor())($element, $context)
static fn (ElementDef $element): TypeCollection => (new ElementVisitor())(
$element,
$context->onParent(new ParentContext($element))
)
),
...flat_map(
$schema->getSchemas(),
fn (Schema $childSchema): TypeCollection => $this->__invoke($childSchema, $context)
fn (Schema $childSchema): TypeCollection => $this->__invoke(
$childSchema,
$context->onParent(null)
)
)
])
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php declare(strict_types=1);

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

use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer;
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
use GoetasWebservices\XML\XSDReader\Schema\Item;
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
use Psl\Option\Option;
use function Psl\Option\none;
use function Psl\Option\some;

final class AttributeDeclaringParentTypeDetector
{
/**
* This class detects the declaring parent type of an attribute.
* It can be used together with the ParentContext and works as followed
*
* - If the parent is an AttributeContainer, it will check if the parent has the attribute
* - If the parent is not declaring the attribute, it will check if the parent is extending another type and test this extended type.
*
* @return Option<Type>
*/
public function __invoke(AttributeItem $item, ?SchemaItem $parent): Option
{
$parent = match(true) {
$parent instanceof Item => $parent->getType(),
default => $parent,
};

if (!$parent instanceof Type) {
return none();
}

if ($parent instanceof AttributeContainer) {
foreach ($parent->getAttributes() as $parentAttribute) {
if ($parentAttribute->getName() === $item->getName()) {
/** @var Option<Type> */
return some($parent);
}
}
}

$extensionBase = $parent->getExtension()?->getBase();
if ($extensionBase) {
return $this->__invoke($item, $extensionBase);
}

return none();
}
}
13 changes: 13 additions & 0 deletions src/Metadata/Converter/Types/ParentContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace Soap\WsdlReader\Metadata\Converter\Types;

use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;

final class ParentContext
{
public function __construct(
public readonly SchemaItem $item,
) {
}
}
14 changes: 14 additions & 0 deletions src/Metadata/Converter/Types/TypesConverterContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ final class TypesConverterContext
*/
private array $visited = [];

private ?ParentContext $parentContext = null;

private function __construct(
public readonly Namespaces $knownNamespaces
) {
Expand Down Expand Up @@ -57,4 +59,16 @@ public function visit(Schema $schema, callable $visitor): TypeCollection

return $visitor($schema);
}

public function onParent(?ParentContext $parentContext): self
{
$this->parentContext = $parentContext;

return $this;
}

public function parent(): ?ParentContext
{
return $this->parentContext;
}
}
25 changes: 23 additions & 2 deletions src/Metadata/Converter/Types/Visitor/AttributeContainerVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeSingle;
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
use Psl\Option\Option;
use Soap\Engine\Metadata\Collection\PropertyCollection;
use Soap\Engine\Metadata\Model\Property;
use Soap\Engine\Metadata\Model\TypeMeta;
use Soap\Engine\Metadata\Model\XsdType as EngineType;
use Soap\WsdlReader\Metadata\Converter\Types\Configurator;
use Soap\WsdlReader\Metadata\Converter\Types\Detector\AttributeDeclaringParentTypeDetector;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use function Psl\Fun\pipe;
use function Psl\Option\from_nullable;
use function Psl\Result\wrap;
use function Psl\Type\instance_of;
use function Psl\Vec\flat_map;
Expand Down Expand Up @@ -88,8 +91,26 @@ private function parseAttribute(AttributeItem $attribute, TypesConverterContext
return $this->parseAttributes($attribute, $context);
}

// Detecting the type-name for an attribute is complex.
// We first try to use the type name,
// Next up is the base type of the restriction if there aren't any restriction checks configured.
// Finally there is a fallback to the attribute name
$attributeType = $attribute instanceof AttributeSingle ? $attribute->getType() : null;
$typeName = $attributeType?->getName() ?: $attribute->getName();
$attributeRestriction = $attributeType?->getRestriction();
$attributeTypeName = $attributeType?->getName();
$attributeRestrictionName = ($attributeRestriction && !$attributeRestriction->getChecks()) ? $attributeRestriction->getBase()?->getName() : null;

$typeName = $attributeTypeName ?: ($attributeRestrictionName ?: $attribute->getName());
$engineType = EngineType::guess($typeName);

// If a name cannot be determined from the type, we fallback to the attribute name:
// Prefix the attribute name with the parent element name resulting in a more unique type-name.
if (!$attributeTypeName && !$attributeRestrictionName) {
$engineType = (new AttributeDeclaringParentTypeDetector())($attribute, $context->parent()?->item)
->andThen(static fn (Type $parent): Option => from_nullable($parent->getName()))
->map(static fn (string $parentName): EngineType => $engineType->copy($parentName . ucfirst($typeName)))
->unwrapOr($engineType);
}

$configure = pipe(
static fn (EngineType $engineType): EngineType => (new Configurator\AttributeConfigurator())($engineType, $attribute, $context),
Expand All @@ -98,7 +119,7 @@ private function parseAttribute(AttributeItem $attribute, TypesConverterContext
return new PropertyCollection(
new Property(
$attribute->getName(),
$configure(EngineType::guess($typeName))
$configure($engineType)
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
use Soap\Engine\Metadata\Collection\TypeCollection;
use Soap\WsdlReader\Metadata\Converter\Types\ParentContext;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use function Psl\Vec\flat_map;

Expand Down Expand Up @@ -62,6 +63,6 @@ private function detectInlineTypes(ElementItem $element, TypesConverterContext $
return new TypeCollection();
}

return $elementVisitor($element, $context);
return $elementVisitor($element, $context->onParent(new ParentContext($element)));
}
}
32 changes: 32 additions & 0 deletions tests/PhpCompatibility/schema1013.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
SOAP XML Schema 1001: Prepend element name before attribute type names for more unique type-names.
--FILE--
<?php
include __DIR__."/test_schema.inc";
$schema = <<<EOF
<complexType name="VehicleCoreType">
<sequence>
<element name="VehType" minOccurs="0" type="string" />
</sequence>
<attribute name="DriveType" use="optional">
<simpleType>
<restriction base="NMTOKEN">
<enumeration value="AWD" />
<enumeration value="4WD" />
<enumeration value="Unspecified" />
</restriction>
</simpleType>
</attribute>
</complexType>
EOF;
test_schema($schema,'type="tns:VehicleCoreType"');
?>
--EXPECT--
Methods:
> test(VehicleCoreType $testParam): void

Types:
> http://test-uri/:VehicleCoreType {
?string $VehType
@?VehicleCoreTypeDriveType in (AWD|4WD|Unspecified) $DriveType
}

0 comments on commit 2d84d9f

Please sign in to comment.