php-soap / encoding

SOAP encoding and decoding package
MIT License
6 stars 2 forks source link

Allow child encoders to enhance the context for the element encoder. #19

Closed veewee closed 2 months ago

veewee commented 2 months ago
Q A
Type improvement
BC Break no
Fixed issues https://github.com/phpro/soap-client/issues/534

Summary

Provides a fix for https://github.com/phpro/soap-client/issues/534

It is now possible to enhance the context of the element encoder from the internal simpleType encoder:

use Soap\Encoding\Encoder\Context;
use Soap\Encoding\Encoder\Feature\ElementContextEnhancer;
use Soap\Encoding\Encoder\SimpleType\ScalarTypeEncoder;
use Soap\Encoding\Encoder\XmlEncoder;
use Soap\Encoding\EncoderRegistry;
use Soap\Engine\Metadata\Model\TypeMeta;
use Soap\WsdlReader\Model\Definitions\BindingUse;
use VeeWee\Reflecta\Iso\Iso;

/**
 * This encoder can add xsi:type information to the XML element on xsd:anyType simpleTypes on literal encoded documents.
 *
 * <xsd:element minOccurs="0" maxOccurs="1" name="value" type="xsd:anyType" />
 *
 * Will Result in for example:
 *
 * <value
 *   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 *   xsi:type="xsds:int"
 *   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 * >
 *  789
 * </value>
 */

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)
                        )
                    );
            }
        }
    );