diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f5b5dc7..f246a54 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -5,6 +5,7 @@ \Symfony\Component\Finder\Finder::create() ->in([ __DIR__ . '/src', + __DIR__ . '/examples', __DIR__ . '/tests', ]) ->name('*.php') diff --git a/README.md b/README.md index d5ef4ff..2b924bb 100644 --- a/README.md +++ b/README.md @@ -126,3 +126,6 @@ class MySpecificTypeCEncoder implements XmlEncoder **Note:** An encoder is considered to be isomorphic : When calling `from` and `to` on the `Iso` object, the data should be the same. More information about the concept [can be found here](https://github.com/veewee/reflecta/blob/main/docs/isomorphisms.md). + +For a full list of available encoders, you can check the [Soap\Encoding\Encoder](src/Encoder) namespace. +There are also some examples of common problems you can solve with these encoders in the [examples/encoders](examples/encoders) directory. diff --git a/examples/calc-encode.php b/examples/calc-encode.php index 5745ba3..33dd555 100644 --- a/examples/calc-encode.php +++ b/examples/calc-encode.php @@ -1,13 +1,12 @@ - + * + * + * + * + * + * This encoder will use veewee/xml to encode and decode the whole XML structure so that it can be used by you. + * + * The result looks like this: + * + * + * + * + * world + * + * + * <=> + * + * ^ {#1761 + * +"customerName": "John Doe" + * +"customerEmail": "john@doe.com" + * +"customerData": array:3 [ + * "foo" => "" + * "bar" => "" + * "hello" => "world" + * ] + * } + */ + +EncoderRegistry::default() + ->addComplexTypeConverter( + 'http://yournamespace', + 'yourTypeUsingTheAnyType', + new class implements XmlEncoder { + /** + * @return Iso + */ + public function iso(Context $context): Iso + { + $typeName = $context->type->getName(); + + return new Iso( + to: static fn (array $data): string => document_encode([$typeName => $data])->stringifyDocumentElement(), + from: static fn (Element|string $xml): array => xml_decode( + ($xml instanceof Element ? $xml : Element::fromString($xml))->value() + )[$typeName], + ); + } + } + ); diff --git a/examples/encoders/simpleType/anyType-with-xsi-info.php b/examples/encoders/simpleType/anyType-with-xsi-info.php new file mode 100644 index 0000000..2ca3522 --- /dev/null +++ b/examples/encoders/simpleType/anyType-with-xsi-info.php @@ -0,0 +1,57 @@ + + * + * Will Result in for example: + * + * + * 789 + * + */ + +EncoderRegistry::default() + ->addSimpleTypeConverter( + 'http://www.w3.org/2001/XMLSchema', + 'anyType', + new class implements + ElementContextEnhancer, + XmlEncoder { + public function iso(Context $context): Iso + { + return (new ScalarTypeEncoder())->iso($context); + } + + /** + * This method allows to change the context on the wrapping elementEncoder. + * By forcing the bindingUse to `ENCODED`, we can make sure the xsi:type attribute is added. + * We also make sure the type is not qualified so that the xsi:type prefix xmlns is imported as well. + */ + public function enhanceElementContext(Context $context): Context + { + return $context + ->withBindingUse(BindingUse::ENCODED) + ->withType( + $context->type->withMeta( + static fn (TypeMeta $meta): TypeMeta => $meta->withIsQualified(false) + ) + ); + } + } + ); diff --git a/src/Encoder/Context.php b/src/Encoder/Context.php index 7cc22ae..16bad2b 100644 --- a/src/Encoder/Context.php +++ b/src/Encoder/Context.php @@ -30,4 +30,15 @@ public function withType(XsdType $type): self $this->bindingUse, ); } + + public function withBindingUse(BindingUse $bindingUse): self + { + return new self( + $this->type, + $this->metadata, + $this->registry, + $this->namespaces, + $bindingUse, + ); + } } diff --git a/src/Encoder/ElementEncoder.php b/src/Encoder/ElementEncoder.php index c27b954..c65dcd1 100644 --- a/src/Encoder/ElementEncoder.php +++ b/src/Encoder/ElementEncoder.php @@ -28,6 +28,9 @@ public function __construct( public function iso(Context $context): Iso { $typeEncoder = $this->typeEncoder; + $context = $this->typeEncoder instanceof Feature\ElementContextEnhancer + ? $this->typeEncoder->enhanceElementContext($context) + : $context; return new Iso( /** diff --git a/src/Encoder/Feature/ElementContextEnhancer.php b/src/Encoder/Feature/ElementContextEnhancer.php new file mode 100644 index 0000000..66ebbfc --- /dev/null +++ b/src/Encoder/Feature/ElementContextEnhancer.php @@ -0,0 +1,19 @@ + '32', 'data' => 32, ]; + yield 'context-enhancing-child-encoder' => [ + ...$baseConfig, + 'encoder' => $encoder = new ElementEncoder(new class implements ElementContextEnhancer, XmlEncoder { + public function iso(Context $context): Iso + { + return (new IntTypeEncoder())->iso($context); + } + + public function enhanceElementContext(Context $context): Context + { + return $context->withType( + $context->type->withXmlTargetNodeName('bonjour') + ); + } + }), + 'xml' => '32', + 'data' => 32, + ]; } public function test_it_can_decode_from_xml_item(): void