Skip to content

Commit

Permalink
Introduce a way to encode+decode CDATA
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Jun 6, 2024
1 parent 5a86b18 commit d0ac7fd
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 7 deletions.
3 changes: 1 addition & 2 deletions src/Encoder/ElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ public function __construct(
public function iso(Context $context): Iso
{
$typeEncoder = $this->typeEncoder;
$typeIso = $typeEncoder->iso($context);

return new Iso(
/**
* @psalm-param mixed $raw
*/
static fn (mixed $raw): string => (new XsdTypeXmlElementWriter())(
$context,
(new ElementValueBuilder($context, $typeIso, $raw))
(new ElementValueBuilder($context, $typeEncoder, $raw))
),
/**
* @psalm-param non-empty-string $xml
Expand Down
8 changes: 8 additions & 0 deletions src/Encoder/Feature/CData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Encoder\Feature;

interface CData
{
}
28 changes: 28 additions & 0 deletions src/Encoder/SimpleType/CDataTypeEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Encoder\SimpleType;

use Soap\Encoding\Encoder\Context;
use Soap\Encoding\Encoder\Feature;
use Soap\Encoding\Encoder\XmlEncoder;
use VeeWee\Reflecta\Iso\Iso;

/**
* This encoder works exactly the same as the string encoder.
* However, it implements the CData feature.
* When writing the data to the XML element, it will be wrapped in a CDATA section.
*
* @psalm-suppress UnusedClass
* @implements XmlEncoder<string, string>
*/
final class CDataTypeEncoder implements Feature\CData, XmlEncoder
{
/**
* @return Iso<string, string>
*/
public function iso(Context $context): Iso
{
return (new StringTypeEncoder())->iso($context);
}
}
25 changes: 21 additions & 4 deletions src/Xml/Writer/ElementValueBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@

use Generator;
use Soap\Encoding\Encoder\Context;
use Soap\Encoding\Encoder\Feature\CData;
use Soap\Encoding\Encoder\XmlEncoder;
use Soap\Encoding\TypeInference\XsiTypeDetector;
use Soap\WsdlReader\Model\Definitions\BindingUse;
use VeeWee\Reflecta\Iso\Iso;
use XMLWriter;
use function VeeWee\Xml\Writer\Builder\cdata;
use function VeeWee\Xml\Writer\Builder\children;
use function VeeWee\Xml\Writer\Builder\value;

final class ElementValueBuilder
{
/**
* @param Iso<mixed, string> $iso
* @param XmlEncoder<mixed, string> $encoder
* @psalm-param mixed $value
*/
public function __construct(
private readonly Context $context,
private readonly Iso $iso,
private readonly XmlEncoder $encoder,
private readonly mixed $value
) {
}
Expand All @@ -32,7 +34,7 @@ public function __invoke(XMLWriter $writer): Generator
{
yield from children([
$this->buildXsiType(...),
value($this->iso->to($this->value))
$this->buildValue(...),
])($writer);
}

Expand All @@ -51,4 +53,19 @@ private function buildXsiType(XMLWriter $writer): Generator
includeXsiTargetNamespace: !$this->context->type->getMeta()->isQualified()->unwrapOr(false)
))($writer);
}

/**
* @return Generator<bool>
*/
private function buildValue(XMLWriter $writer): Generator
{
$encoded = $this->encoder->iso($this->context)->to($this->value);

$builder = match (true) {
$this->encoder instanceof CData => cdata(value($encoded)),
default => value($encoded)
};

yield from $builder($writer);
}
}
51 changes: 51 additions & 0 deletions tests/Unit/Encoder/SimpleType/CDataTypeEncoderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Test\Unit\Encoder\SimpleType;

use PHPUnit\Framework\Attributes\CoversClass;
use Soap\Encoding\Encoder\ElementEncoder;
use Soap\Encoding\Encoder\SimpleType\CDataTypeEncoder;
use Soap\Encoding\Test\Unit\Encoder\AbstractEncoderTests;
use Soap\Engine\Metadata\Model\XsdType;

#[CoversClass(CDataTypeEncoder::class)]
final class CDataTypeEncoderTest extends AbstractEncoderTests
{
public static function provideIsomorphicCases(): iterable
{
$baseConfig = [
'encoder' => $encoder = new CDataTypeEncoder(),
'context' => $context = self::createContext(
XsdType::guess('string')
->withXmlTargetNodeName('root')
),
];

yield 'simple' => [
...$baseConfig,
'xml' => 'hello',
'data' => 'hello',
];
yield 'special-chars' => [
...$baseConfig,
'xml' => 'hëllo\'"<>',
'data' => 'hëllo\'"<>',
];

$elementEncoder = new ElementEncoder($encoder);
yield 'element-wrapped' => [
...$baseConfig,
'encoder' => $elementEncoder,
'xml' => '<root><![CDATA[hello]]></root>',
'data' => 'hello',

];
yield 'element-wrapped-special-chars' => [
...$baseConfig,
'encoder' => $elementEncoder,
'xml' => '<root><![CDATA[hëllo\'"<>]]></root>',
'data' => 'hëllo\'"<>',
];
}
}
21 changes: 20 additions & 1 deletion tests/Unit/Encoder/SimpleType/StringTypeEncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Soap\Encoding\Test\Unit\Encoder\SimpleType;

use PHPUnit\Framework\Attributes\CoversClass;
use Soap\Encoding\Encoder\ElementEncoder;
use Soap\Encoding\Encoder\SimpleType\StringTypeEncoder;
use Soap\Encoding\Test\Unit\Encoder\AbstractEncoderTests;
use Soap\Engine\Metadata\Model\XsdType;
Expand All @@ -15,7 +16,10 @@ public static function provideIsomorphicCases(): iterable
{
$baseConfig = [
'encoder' => $encoder = new StringTypeEncoder(),
'context' => $context = self::createContext(XsdType::guess('string')),
'context' => $context = self::createContext(
XsdType::guess('string')
->withXmlTargetNodeName('root')
),
];

yield 'simple' => [
Expand All @@ -28,5 +32,20 @@ public static function provideIsomorphicCases(): iterable
'xml' => 'hëllo\'"<>',
'data' => 'hëllo\'"<>',
];

$elementEncoder = new ElementEncoder($encoder);
yield 'element-wrapped' => [
...$baseConfig,
'encoder' => $elementEncoder,
'xml' => '<root>hello</root>',
'data' => 'hello',

];
yield 'element-wrapped-special-chars' => [
...$baseConfig,
'encoder' => $elementEncoder,
'xml' => '<root>hëllo\'&quot;&lt;&gt;</root>',
'data' => 'hëllo\'"<>',
];
}
}

0 comments on commit d0ac7fd

Please sign in to comment.