diff --git a/src/Encoder/ElementEncoder.php b/src/Encoder/ElementEncoder.php index 28d0100..9a91015 100644 --- a/src/Encoder/ElementEncoder.php +++ b/src/Encoder/ElementEncoder.php @@ -28,7 +28,6 @@ public function __construct( public function iso(Context $context): Iso { $typeEncoder = $this->typeEncoder; - $typeIso = $typeEncoder->iso($context); return new Iso( /** @@ -36,7 +35,7 @@ public function iso(Context $context): Iso */ static fn (mixed $raw): string => (new XsdTypeXmlElementWriter())( $context, - (new ElementValueBuilder($context, $typeIso, $raw)) + (new ElementValueBuilder($context, $typeEncoder, $raw)) ), /** * @psalm-param non-empty-string $xml diff --git a/src/Encoder/Feature/CData.php b/src/Encoder/Feature/CData.php new file mode 100644 index 0000000..c92eb82 --- /dev/null +++ b/src/Encoder/Feature/CData.php @@ -0,0 +1,8 @@ + + */ +final class CDataTypeEncoder implements Feature\CData, XmlEncoder +{ + /** + * @return Iso + */ + public function iso(Context $context): Iso + { + return (new StringTypeEncoder())->iso($context); + } +} diff --git a/src/Xml/Writer/ElementValueBuilder.php b/src/Xml/Writer/ElementValueBuilder.php index 12e1f61..723d6bb 100644 --- a/src/Xml/Writer/ElementValueBuilder.php +++ b/src/Xml/Writer/ElementValueBuilder.php @@ -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 $iso + * @param XmlEncoder $encoder * @psalm-param mixed $value */ public function __construct( private readonly Context $context, - private readonly Iso $iso, + private readonly XmlEncoder $encoder, private readonly mixed $value ) { } @@ -32,7 +34,7 @@ public function __invoke(XMLWriter $writer): Generator { yield from children([ $this->buildXsiType(...), - value($this->iso->to($this->value)) + $this->buildValue(...), ])($writer); } @@ -51,4 +53,19 @@ private function buildXsiType(XMLWriter $writer): Generator includeXsiTargetNamespace: !$this->context->type->getMeta()->isQualified()->unwrapOr(false) ))($writer); } + + /** + * @return Generator + */ + 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); + } } diff --git a/tests/Unit/Encoder/SimpleType/CDataTypeEncoderTest.php b/tests/Unit/Encoder/SimpleType/CDataTypeEncoderTest.php new file mode 100644 index 0000000..90315d9 --- /dev/null +++ b/tests/Unit/Encoder/SimpleType/CDataTypeEncoderTest.php @@ -0,0 +1,51 @@ + $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' => '', + 'data' => 'hello', + + ]; + yield 'element-wrapped-special-chars' => [ + ...$baseConfig, + 'encoder' => $elementEncoder, + 'xml' => ']]>', + 'data' => 'hëllo\'"<>', + ]; + } +} diff --git a/tests/Unit/Encoder/SimpleType/StringTypeEncoderTest.php b/tests/Unit/Encoder/SimpleType/StringTypeEncoderTest.php index 699686a..966686e 100644 --- a/tests/Unit/Encoder/SimpleType/StringTypeEncoderTest.php +++ b/tests/Unit/Encoder/SimpleType/StringTypeEncoderTest.php @@ -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; @@ -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' => [ @@ -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' => 'hello', + 'data' => 'hello', + + ]; + yield 'element-wrapped-special-chars' => [ + ...$baseConfig, + 'encoder' => $elementEncoder, + 'xml' => 'hëllo\'"<>', + 'data' => 'hëllo\'"<>', + ]; } }