Skip to content

Commit a8f06bf

Browse files
authored
Merge pull request #24 from veewee/optional-encoding-fix
Allow not setting optional objects and arrays whilst encoding.
2 parents 0d1de01 + 76947c9 commit a8f06bf

File tree

8 files changed

+108
-9
lines changed

8 files changed

+108
-9
lines changed

src/Encoder/EncoderDetector.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ public function __invoke(Context $context): XmlEncoder
5151
$encoder = new RepeatingElementEncoder($encoder);
5252
}
5353

54+
if (!$encoder instanceof Feature\OptionalAware && $meta->isNullable()->unwrapOr(false)) {
55+
$encoder = new OptionalElementEncoder($encoder);
56+
}
57+
5458
$encoder = new ErrorHandlingEncoder($encoder);
5559

5660
return $this->cache[$type] = $encoder;

src/Encoder/Feature/ListAware.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
namespace Soap\Encoding\Encoder\Feature;
55

6+
/**
7+
* Tells the encoder knows how to teal with list inputs.
8+
*/
69
interface ListAware extends DisregardXsiInformation
710
{
811
}

src/Encoder/Feature/OptionalAware.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Soap\Encoding\Encoder\Feature;
5+
6+
/**
7+
* Tells the encoder knows about optional (nullable) values.
8+
*/
9+
interface OptionalAware extends DisregardXsiInformation
10+
{
11+
}

src/Encoder/OptionalElementEncoder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* @template T of mixed
1414
* @implements XmlEncoder<T, string>
1515
*/
16-
final class OptionalElementEncoder implements XmlEncoder
16+
final class OptionalElementEncoder implements Feature\OptionalAware, XmlEncoder
1717
{
1818
/**
1919
* @param XmlEncoder<T, string> $elementEncoder

src/Encoder/RepeatingElementEncoder.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
/**
1414
* @template T
15-
* @implements XmlEncoder<iterable<array-key, T>, string>
15+
* @implements XmlEncoder<iterable<array-key, T>|null, string>
1616
*/
1717
final class RepeatingElementEncoder implements Feature\ListAware, XmlEncoder
1818
{
@@ -25,7 +25,7 @@ public function __construct(
2525
}
2626

2727
/**
28-
* @return Iso<iterable<array-key, T>, string>
28+
* @return Iso<iterable<array-key, T>|null, string>
2929
*/
3030
public function iso(Context $context): Iso
3131
{
@@ -39,12 +39,12 @@ public function iso(Context $context): Iso
3939

4040
return new Iso(
4141
/**
42-
* @param iterable<array-key, T> $raw
42+
* @param iterable<array-key, T>|null $raw
4343
*/
44-
static function (iterable $raw) use ($innerIso): string {
44+
static function (iterable|null $raw) use ($innerIso): string {
4545
return join(
4646
map(
47-
$raw,
47+
$raw ?? [],
4848
/**
4949
* @param T $item
5050
*/

src/Encoder/SimpleType/EncoderDetector.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ public function __invoke(Context $context): XmlEncoder
3939
}
4040

4141
if ($meta->isElement()->unwrapOr(false)) {
42-
$encoder = new OptionalElementEncoder(
43-
new ElementEncoder($encoder)
44-
);
42+
$encoder = new ElementEncoder($encoder);
43+
44+
if ($meta->isNullable()->unwrapOr(false)) {
45+
$encoder = new OptionalElementEncoder($encoder);
46+
}
4547
}
4648

4749
return $encoder;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Soap\Encoding\Test\PhpCompatibility\Implied;
5+
6+
use PHPUnit\Framework\Attributes\CoversClass;
7+
use Soap\Encoding\Decoder;
8+
use Soap\Encoding\Driver;
9+
use Soap\Encoding\Encoder;
10+
use Soap\Encoding\Test\PhpCompatibility\AbstractCompatibilityTests;
11+
12+
#[CoversClass(Driver::class)]
13+
#[CoversClass(Encoder::class)]
14+
#[CoversClass(Decoder::class)]
15+
final class ImpliedSchema004Test extends AbstractCompatibilityTests
16+
{
17+
protected string $schema = <<<EOXML
18+
<element name="testType">
19+
<complexType>
20+
<sequence>
21+
<element name="OptionalList" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
22+
<element name="OptionalSimpleElement" type="xsd:string" minOccurs="0" maxOccurs="1"/>
23+
<element name="OptionalObject" minOccurs="0">
24+
<complexType>
25+
<sequence>
26+
<element name="item" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
27+
</sequence>
28+
</complexType>
29+
</element>
30+
</sequence>
31+
</complexType>
32+
</element>
33+
EOXML;
34+
protected string $type = 'type="tns:testType"';
35+
36+
protected function calculateParam(): mixed
37+
{
38+
return (object)[];
39+
}
40+
41+
protected function expectDecoded(): mixed
42+
{
43+
return (object)[
44+
'OptionalList' => [],
45+
'OptionalSimpleElement' => null,
46+
'OptionalObject' => null,
47+
];
48+
}
49+
50+
protected function expectXml(): string
51+
{
52+
return <<<XML
53+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://test-uri/"
54+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
55+
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
56+
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
57+
<tns:test>
58+
<testParam xsi:type="tns:testType" />
59+
</tns:test>
60+
</SOAP-ENV:Body>
61+
</SOAP-ENV:Envelope>
62+
XML;
63+
}
64+
}

tests/Unit/Encoder/RepeatingElementEncoderTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,19 @@ public function test_it_can_decode_from_xml_item_list(): void
8282

8383
static::assertEquals(['world'], $actual);
8484
}
85+
86+
public function test_it_can_encode_from_null(): void
87+
{
88+
$encoder = new RepeatingElementEncoder(new ElementEncoder(new StringTypeEncoder()));
89+
$context = self::createContext(
90+
XsdType::guess('string')
91+
->withXmlTargetNodeName('hello')
92+
->withMeta(static fn (TypeMeta $meta): TypeMeta => $meta->withIsQualified(true))
93+
);
94+
95+
$iso = $encoder->iso($context);
96+
$actual = $iso->to(null);
97+
98+
static::assertSame('', $actual);
99+
}
85100
}

0 commit comments

Comments
 (0)