diff --git a/src/Encoder/OptionalElementEncoder.php b/src/Encoder/OptionalElementEncoder.php index edeaef9..3f08d82 100644 --- a/src/Encoder/OptionalElementEncoder.php +++ b/src/Encoder/OptionalElementEncoder.php @@ -4,10 +4,13 @@ namespace Soap\Encoding\Encoder; use Soap\Encoding\Xml\Node\Element; +use Soap\Encoding\Xml\Node\ElementList; use Soap\Encoding\Xml\Writer\NilAttributeBuilder; use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter; use VeeWee\Reflecta\Iso\Iso; use VeeWee\Xml\Xmlns\Xmlns; +use function count; +use function is_string; /** * @template T of mixed @@ -31,6 +34,7 @@ public function iso(Context $context): Iso $type = $context->type; $meta = $type->getMeta(); $elementIso = $this->elementEncoder->iso($context); + $isList = $meta->isList()->unwrapOr(false); if (!$meta->isNullable()->unwrapOr(false)) { return $elementIso; @@ -48,17 +52,27 @@ public function iso(Context $context): Iso /** * @return T|null */ - static function (Element|string $xml) use ($elementIso) : mixed { + static function (ElementList|Element|string $xml) use ($elementIso, $isList) : mixed { if ($xml === '') { return null; } - $documentElement = ($xml instanceof Element ? $xml : Element::fromString($xml))->element(); - if ($documentElement->getAttributeNS(Xmlns::xsi()->value(), 'nil') === 'true') { + $parsedXml = match(true) { + $isList && is_string($xml) => ElementList::fromString(''.$xml.''), + is_string($xml) => Element::fromString($xml), + default => $xml, + }; + + $documentElement = match (true) { + $parsedXml instanceof ElementList && count($parsedXml) === 1 => $parsedXml->elements()[0]->element(), + $parsedXml instanceof Element => $parsedXml->element(), + default => null + }; + if ($documentElement && $documentElement->getAttributeNS(Xmlns::xsi()->value(), 'nil') === 'true') { return null; } - /** @var Iso $elementIso */ + /** @var Iso $elementIso */ return $elementIso->from($xml); } ); diff --git a/src/Xml/Node/ElementList.php b/src/Xml/Node/ElementList.php index 806afba..0740e28 100644 --- a/src/Xml/Node/ElementList.php +++ b/src/Xml/Node/ElementList.php @@ -4,10 +4,12 @@ namespace Soap\Encoding\Xml\Node; use Closure; +use Countable; use DOMElement; use Soap\Encoding\Xml\Reader\DocumentToLookupArrayReader; use Stringable; use VeeWee\Xml\Dom\Document; +use function count; use function Psl\Iter\reduce; use function Psl\Vec\map; use function VeeWee\Xml\Dom\Locator\Element\children as readChildren; @@ -15,7 +17,7 @@ /** * @psalm-import-type LookupArray from DocumentToLookupArrayReader */ -final class ElementList implements Stringable +final class ElementList implements Countable, Stringable { /** @var list */ private array $elements; @@ -111,4 +113,9 @@ public function __toString() { return $this->value(); } + + public function count(): int + { + return count($this->elements); + } } diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema009Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema009Test.php new file mode 100644 index 0000000..85a5c33 --- /dev/null +++ b/tests/PhpCompatibility/Implied/ImpliedSchema009Test.php @@ -0,0 +1,66 @@ + + + + + + + + + + + + EOXML; + protected string $type = 'type="tns:testType"'; + + protected function calculateParam(): mixed + { + return (object)[ + 'Company' => [ + (object)['ID' => 0], + (object)['ID' => 1], + ], + ]; + } + + protected function expectXml(): string + { + return << + + + + + 0 + + + 1 + + + + + + XML; + } +} diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema010Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema010Test.php new file mode 100644 index 0000000..87b5e9c --- /dev/null +++ b/tests/PhpCompatibility/Implied/ImpliedSchema010Test.php @@ -0,0 +1,57 @@ + + + + + + + + + + + + EOXML; + protected string $type = 'type="tns:testType"'; + + protected function calculateParam(): mixed + { + return (object) [ + 'Company' => null, + ]; + } + + protected function expectXml(): string + { + return << + + + + + + + + + XML; + } +} diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema011Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema011Test.php new file mode 100644 index 0000000..0d13376 --- /dev/null +++ b/tests/PhpCompatibility/Implied/ImpliedSchema011Test.php @@ -0,0 +1,55 @@ + + + + + + + + + + + + EOXML; + protected string $type = 'type="tns:testType"'; + + protected function calculateParam(): mixed + { + return (object) [ + 'Company' => [], + ]; + } + + protected function expectXml(): string + { + return << + + + + + + + XML; + } +} diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema012Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema012Test.php new file mode 100644 index 0000000..1813457 --- /dev/null +++ b/tests/PhpCompatibility/Implied/ImpliedSchema012Test.php @@ -0,0 +1,62 @@ + + + + + + + + + + + + EOXML; + protected string $type = 'type="tns:testType"'; + + protected function calculateParam(): mixed + { + return (object) [ + 'Company' => [ + (object)['ID' => 0], + ], + ]; + } + + protected function expectXml(): string + { + return << + + + + + 0 + + + + + + XML; + } +} diff --git a/tests/Unit/Xml/Node/ElementListTest.php b/tests/Unit/Xml/Node/ElementListTest.php index 277984b..ca3a914 100644 --- a/tests/Unit/Xml/Node/ElementListTest.php +++ b/tests/Unit/Xml/Node/ElementListTest.php @@ -55,4 +55,12 @@ public function test_it_can_load_nested_list(): void static::assertSame([$hello, $list1, $list2], $list->elements()); } + + public function test_it_can_be_countded(): void + { + $list = new ElementList(Element::fromString('world')); + + static::assertCount(1, $list->elements()); + static::assertCount(1, $list); + } }