-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rework SOAP:Array encoder to support complex type items.
- Loading branch information
Showing
3 changed files
with
154 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Soap\Encoding\Encoder\SoapEnc; | ||
|
||
use Soap\Encoding\Encoder\Context; | ||
use Soap\Encoding\Encoder\XmlEncoder; | ||
use Soap\Engine\Metadata\Model\TypeMeta; | ||
use Soap\Engine\Metadata\Model\XsdType; | ||
use Soap\WsdlReader\Model\Definitions\BindingUse; | ||
use Soap\WsdlReader\Parser\Xml\QnameParser; | ||
use Soap\Xml\Xmlns; | ||
use Stringable; | ||
use function Psl\Result\try_catch; | ||
|
||
final class SoapArrayAccess | ||
{ | ||
/** | ||
* @param XmlEncoder<mixed, Stringable|string> $itemEncoder | ||
*/ | ||
public function __construct( | ||
public readonly string $xsiType, | ||
public readonly Context $itemContext, | ||
public readonly XmlEncoder $itemEncoder, | ||
) { | ||
} | ||
|
||
public static function forContext(Context $context): self | ||
{ | ||
$meta = $context->type->getMeta(); | ||
[$namespace, $nodePrefix, $nodeType] = $meta->arrayType() | ||
->map(static fn (array $info): array => [$info['namespace'], ...(new QnameParser())($info['itemType'])]) | ||
->unwrapOr([ | ||
Xmlns::xsd()->value(), | ||
$context->namespaces->lookupNameFromNamespace(Xmlns::xsd()->value())->unwrapOr('xsd'), | ||
'anyType' | ||
]); | ||
$itemNodeName = $meta->arrayNodeName()->unwrapOr(null); | ||
$xsiType = ltrim($nodePrefix . ':' . $nodeType, ':'); | ||
|
||
$xsdType = try_catch( | ||
static fn (): XsdType => $context->metadata->getTypes() | ||
->fetchByNameAndXmlNamespace($nodeType, $namespace) | ||
->getXsdType(), | ||
static fn (): XsdType => XsdType::any() | ||
->copy($nodeType) | ||
->withXmlTypeName($nodeType) | ||
->withXmlNamespace($namespace) | ||
->withMeta(static fn (TypeMeta $meta): TypeMeta => $meta->withIsElement(true)) | ||
); | ||
|
||
if ($context->bindingUse === BindingUse::ENCODED || $itemNodeName !== null) { | ||
$xsdType = $xsdType->withXmlTargetNodeName($itemNodeName ?? 'item'); | ||
} else { | ||
$xsdType = $xsdType | ||
->withXmlTargetNodeName($nodeType) | ||
->withXmlTargetNamespaceName($nodePrefix) | ||
->withXmlTargetNamespace($namespace) | ||
->withMeta( | ||
static fn (TypeMeta $meta): TypeMeta => $meta->withIsQualified(true), | ||
); | ||
} | ||
|
||
$itemContext = $context->withType($xsdType); | ||
$encoder = $context->registry->detectEncoderForContext($itemContext); | ||
|
||
return new self( | ||
$xsiType, | ||
$itemContext, | ||
$encoder, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Soap\Encoding\Test\PhpCompatibility\Implied; | ||
|
||
use PHPUnit\Framework\Attributes\CoversClass; | ||
use Soap\Encoding\Decoder; | ||
use Soap\Encoding\Driver; | ||
use Soap\Encoding\Encoder; | ||
use Soap\Encoding\Test\PhpCompatibility\AbstractCompatibilityTests; | ||
|
||
#[CoversClass(Driver::class)] | ||
#[CoversClass(Encoder::class)] | ||
#[CoversClass(Decoder::class)] | ||
#[CoversClass(Encoder\SoapEnc\SoapArrayEncoder::class)] | ||
final class ImpliedSchema013Test extends AbstractCompatibilityTests | ||
{ | ||
protected string $schema = <<<EOXML | ||
<complexType name="Foo"> | ||
<all> | ||
<element name="id" type="string" /> | ||
</all> | ||
</complexType> | ||
<complexType name="ArrayOfFoo" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"> | ||
<complexContent> | ||
<restriction base="soap-enc:Array"> | ||
<attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:Foo[]"/> | ||
</restriction> | ||
</complexContent> | ||
</complexType> | ||
<element name="testType" minOccurs="1" maxOccurs="1" type="tns:ArrayOfFoo" /> | ||
EOXML; | ||
protected string $type = 'type="tns:ArrayOfFoo"'; | ||
|
||
protected function calculateParam(): mixed | ||
{ | ||
return [ | ||
(object)['id' => 'abc'], | ||
(object)['id' => 'def'], | ||
]; | ||
} | ||
|
||
protected function expectXml(): string | ||
{ | ||
return <<<XML | ||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | ||
xmlns:tns="http://test-uri/" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" | ||
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> | ||
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> | ||
<tns:test> | ||
<testParam SOAP-ENC:arrayType="tns:Foo[2]" xsi:type="tns:ArrayOfFoo"> | ||
<item xsi:type="tns:Foo"> | ||
<id xsi:type="xsd:string">abc</id> | ||
</item> | ||
<item xsi:type="tns:Foo"> | ||
<id xsi:type="xsd:string">def</id> | ||
</item> | ||
</testParam> | ||
</tns:test> | ||
</SOAP-ENV:Body> | ||
</SOAP-ENV:Envelope> | ||
XML; | ||
} | ||
} |