Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow not setting optional objects and arrays whilst encoding. #24

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Encoder/EncoderDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public function __invoke(Context $context): XmlEncoder
$encoder = new RepeatingElementEncoder($encoder);
}

if (!$encoder instanceof Feature\OptionalAware && $meta->isNullable()->unwrapOr(false)) {
$encoder = new OptionalElementEncoder($encoder);
}

$encoder = new ErrorHandlingEncoder($encoder);

return $this->cache[$type] = $encoder;
Expand Down
3 changes: 3 additions & 0 deletions src/Encoder/Feature/ListAware.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace Soap\Encoding\Encoder\Feature;

/**
* Tells the encoder knows how to teal with list inputs.
*/
interface ListAware extends DisregardXsiInformation
{
}
11 changes: 11 additions & 0 deletions src/Encoder/Feature/OptionalAware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Encoder\Feature;

/**
* Tells the encoder knows about optional (nullable) values.
*/
interface OptionalAware extends DisregardXsiInformation
{
}
2 changes: 1 addition & 1 deletion src/Encoder/OptionalElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @template T of mixed
* @implements XmlEncoder<T, string>
*/
final class OptionalElementEncoder implements XmlEncoder
final class OptionalElementEncoder implements Feature\OptionalAware, XmlEncoder
{
/**
* @param XmlEncoder<T, string> $elementEncoder
Expand Down
10 changes: 5 additions & 5 deletions src/Encoder/RepeatingElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

/**
* @template T
* @implements XmlEncoder<iterable<array-key, T>, string>
* @implements XmlEncoder<iterable<array-key, T>|null, string>
*/
final class RepeatingElementEncoder implements Feature\ListAware, XmlEncoder
{
Expand All @@ -25,7 +25,7 @@ public function __construct(
}

/**
* @return Iso<iterable<array-key, T>, string>
* @return Iso<iterable<array-key, T>|null, string>
*/
public function iso(Context $context): Iso
{
Expand All @@ -39,12 +39,12 @@ public function iso(Context $context): Iso

return new Iso(
/**
* @param iterable<array-key, T> $raw
* @param iterable<array-key, T>|null $raw
*/
static function (iterable $raw) use ($innerIso): string {
static function (iterable|null $raw) use ($innerIso): string {
return join(
map(
$raw,
$raw ?? [],
/**
* @param T $item
*/
Expand Down
8 changes: 5 additions & 3 deletions src/Encoder/SimpleType/EncoderDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ public function __invoke(Context $context): XmlEncoder
}

if ($meta->isElement()->unwrapOr(false)) {
$encoder = new OptionalElementEncoder(
new ElementEncoder($encoder)
);
$encoder = new ElementEncoder($encoder);

if ($meta->isNullable()->unwrapOr(false)) {
$encoder = new OptionalElementEncoder($encoder);
}
}

return $encoder;
Expand Down
64 changes: 64 additions & 0 deletions tests/PhpCompatibility/Implied/ImpliedSchema004Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Test\PhpCompatibility\Implied;

use PHPUnit\Framework\Attributes\CoversClass;
use Soap\Encoding\Decoder;
use Soap\Encoding\Driver;
use Soap\Encoding\Encoder;
use Soap\Encoding\Test\PhpCompatibility\AbstractCompatibilityTests;

#[CoversClass(Driver::class)]
#[CoversClass(Encoder::class)]
#[CoversClass(Decoder::class)]
final class ImpliedSchema004Test extends AbstractCompatibilityTests
{
protected string $schema = <<<EOXML
<element name="testType">
<complexType>
<sequence>
<element name="OptionalList" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
<element name="OptionalSimpleElement" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<element name="OptionalObject" minOccurs="0">
<complexType>
<sequence>
<element name="item" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
EOXML;
protected string $type = 'type="tns:testType"';

protected function calculateParam(): mixed
{
return (object)[];
}

protected function expectDecoded(): mixed
{
return (object)[
'OptionalList' => [],
'OptionalSimpleElement' => null,
'OptionalObject' => null,
];
}

protected function expectXml(): string
{
return <<<XML
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://test-uri/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:test>
<testParam xsi:type="tns:testType" />
</tns:test>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
}
}
15 changes: 15 additions & 0 deletions tests/Unit/Encoder/RepeatingElementEncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,19 @@ public function test_it_can_decode_from_xml_item_list(): void

static::assertEquals(['world'], $actual);
}

public function test_it_can_encode_from_null(): void
{
$encoder = new RepeatingElementEncoder(new ElementEncoder(new StringTypeEncoder()));
$context = self::createContext(
XsdType::guess('string')
->withXmlTargetNodeName('hello')
->withMeta(static fn (TypeMeta $meta): TypeMeta => $meta->withIsQualified(true))
);

$iso = $encoder->iso($context);
$actual = $iso->to(null);

static::assertSame('', $actual);
}
}