Skip to content

Commit

Permalink
Read XML from memory
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Jun 13, 2024
1 parent e87d790 commit af4a2d7
Show file tree
Hide file tree
Showing 24 changed files with 437 additions and 80 deletions.
8 changes: 4 additions & 4 deletions src/Decoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Soap\WsdlReader\Model\Definitions\BindingUse;
use Soap\WsdlReader\Model\Definitions\Namespaces;
use function count;
use function Psl\Type\non_empty_string;
use function Psl\invariant;
use function Psl\Vec\map;

final class Decoder implements SoapDecoder
Expand Down Expand Up @@ -39,9 +39,9 @@ public function decode(string $method, SoapResponse $response): mixed

// The SoapResponse only contains the payload of the response (with no headers).
// It can be parsed directly as XML.
$parts = (new OperationReader($meta))(
non_empty_string()->assert($response->getPayload())
);
$payload = $response->getPayload();
invariant($payload !== '', 'Expected a non-empty response payload. Received an empty HTTP response');
$parts = (new OperationReader($meta))($payload)->elements();

return match(count($parts)) {
0 => null,
Expand Down
8 changes: 4 additions & 4 deletions src/Encoder/ElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

namespace Soap\Encoding\Encoder;

use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Reader\ElementValueReader;
use Soap\Encoding\Xml\Writer\ElementValueBuilder;
use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Dom\Document;

/**
* @implements XmlEncoder<mixed, string>
Expand Down Expand Up @@ -38,13 +38,13 @@ public function iso(Context $context): Iso
(new ElementValueBuilder($context, $typeEncoder, $raw))
),
/**
* @psalm-param non-empty-string $xml
* @psalm-param non-empty-string|Element $xml
* @psalm-return mixed
*/
static fn (string $xml): mixed => (new ElementValueReader())(
static fn (Element|string $xml): mixed => (new ElementValueReader())(
$context,
$typeEncoder,
Document::fromXmlString($xml)->locateDocumentElement(),
($xml instanceof Element ? $xml : Element::fromString($xml))->element()
)
);
}
Expand Down
14 changes: 9 additions & 5 deletions src/Encoder/ObjectEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Soap\Encoding\Normalizer\PhpPropertyNameNormalizer;
use Soap\Encoding\TypeInference\ComplexTypeBuilder;
use Soap\Encoding\TypeInference\XsiTypeDetector;
use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Reader\DocumentToLookupArrayReader;
use Soap\Encoding\Xml\Writer\AttributeBuilder;
use Soap\Encoding\Xml\Writer\NilAttributeBuilder;
Expand Down Expand Up @@ -62,11 +63,15 @@ function (object|array $value) use ($context, $properties) : string {
return $this->to($context, $properties, $value);
},
/**
* @param non-empty-string $value
* @param non-empty-string|Element $value
* @return TObj
*/
function (string $value) use ($context, $properties) : object {
return $this->from($context, $properties, $value);
function (string|Element $value) use ($context, $properties) : object {
return $this->from(
$context,
$properties,
($value instanceof Element ? $value : Element::fromString($value))
);
}
);
}
Expand Down Expand Up @@ -131,11 +136,10 @@ function (Property $property) use ($context, $data, $defaultAction) : Closure {

/**
* @param array<string, Property> $properties
* @param non-empty-string $data
*
* @return TObj
*/
private function from(Context $context, array $properties, string $data): object
private function from(Context $context, array $properties, Element $data): object
{
$nodes = (new DocumentToLookupArrayReader())($data);
/** @var Iso<TObj, array<string, mixed>> $objectData */
Expand Down
7 changes: 4 additions & 3 deletions src/Encoder/OptionalElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

namespace Soap\Encoding\Encoder;

use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Writer\NilAttributeBuilder;
use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Dom\Document;
use VeeWee\Xml\Xmlns\Xmlns;

/**
Expand Down Expand Up @@ -48,16 +48,17 @@ public function iso(Context $context): Iso
/**
* @return T|null
*/
static function (string $xml) use ($elementIso) : mixed {
static function (Element|string $xml) use ($elementIso) : mixed {
if ($xml === '') {
return null;
}

$documentElement = Document::fromXmlString($xml)->locateDocumentElement();
$documentElement = ($xml instanceof Element ? $xml : Element::fromString($xml))->element();
if ($documentElement->getAttributeNS(Xmlns::xsi()->value(), 'nil') === 'true') {
return null;
}

/** @var Iso<T|null, Element|non-empty-string> $elementIso */
return $elementIso->from($xml);
}
);
Expand Down
20 changes: 13 additions & 7 deletions src/Encoder/RepeatingElementEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

namespace Soap\Encoding\Encoder;

use DOMElement;
use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Node\ElementList;
use Soap\Engine\Metadata\Model\TypeMeta;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Dom\Document;
use function Psl\Str\join;
use function Psl\Vec\map;
use function VeeWee\Xml\Dom\Locator\Element\children as readChildren;

/**
* @template T
Expand Down Expand Up @@ -57,11 +56,18 @@ static function (iterable $raw) use ($innerIso): string {
/**
* @return iterable<array-key, T>
*/
static function (string $xml) use ($innerIso): iterable {
$doc = Document::fromXmlString('<list>'.$xml.'</list>');
static function (Element|ElementList|string $xml) use ($innerIso): iterable {

return readChildren($doc->locateDocumentElement())->map(
static fn (DOMElement $element): mixed => $innerIso->from($doc->stringifyNode($element))
$elements = match (true) {
$xml instanceof Element => [$xml],
$xml instanceof ElementList => $xml->elements(),
default => ElementList::fromString('<list>'.$xml.'</list>')->elements()
};

/** @var Iso<T|null, Element|non-empty-string> $innerIso */
return map(
$elements,
static fn (Element $element): mixed => $innerIso->from($element)
);
}
);
Expand Down
19 changes: 9 additions & 10 deletions src/Encoder/SoapEnc/ApacheMapEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
use Soap\Encoding\Encoder\SimpleType\ScalarTypeEncoder;
use Soap\Encoding\Encoder\XmlEncoder;
use Soap\Encoding\TypeInference\XsiTypeDetector;
use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Reader\ElementValueReader;
use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter;
use Soap\Encoding\Xml\Writer\XsiAttributeBuilder;
use Soap\Engine\Metadata\Model\XsdType;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Dom\Document;
use function Psl\Dict\merge;
use function Psl\Type\string;
use function VeeWee\Xml\Dom\Assert\assert_element;
Expand All @@ -39,9 +39,12 @@ public function iso(Context $context): Iso
*/
fn (array $value): string => $this->encodeArray($context, $value),
/**
* @param non-empty-string $value
* @param non-empty-string|Element $value
*/
fn (string $value): array => $this->decodeArray($context, $value),
fn (string|Element $value): array => $this->decodeArray(
$context,
$value instanceof Element ? $value : Element::fromString($value)
),
));
}

Expand Down Expand Up @@ -76,14 +79,10 @@ private function encodeArray(Context $context, array $data): string
);
}

/**
* @param non-empty-string $value
*/
private function decodeArray(Context $context, string $value): array
private function decodeArray(Context $context, Element $value): array
{
$document = Document::fromXmlString($value);
$xpath = $document->xpath();
$element = $document->locateDocumentElement();
$element = $value->element();
$xpath = $value->document()->xpath();

return readChildren($element)->reduce(
static function (array $map, DOMElement $item) use ($context, $xpath): array {
Expand Down
15 changes: 8 additions & 7 deletions src/Encoder/SoapEnc/SoapArrayEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
use Soap\Encoding\Encoder\SimpleType\ScalarTypeEncoder;
use Soap\Encoding\Encoder\XmlEncoder;
use Soap\Encoding\TypeInference\XsiTypeDetector;
use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Reader\ElementValueReader;
use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter;
use Soap\Encoding\Xml\Writer\XsiAttributeBuilder;
use Soap\Engine\Metadata\Model\XsdType;
use Soap\WsdlReader\Model\Definitions\BindingUse;
use Soap\WsdlReader\Parser\Xml\QnameParser;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Dom\Document;
use XMLWriter;
use function count;
use function Psl\Vec\map;
Expand Down Expand Up @@ -46,10 +46,13 @@ public function iso(Context $context): Iso
*/
fn (array $value): string => $this->encodeArray($context, $value),
/**
* @param non-empty-string $value
* @param non-empty-string|Element $value
* @return list<mixed>
*/
fn (string $value): array => $this->decodeArray($context, $value),
fn (string|Element $value): array => $this->decodeArray(
$context,
$value instanceof Element ? $value : Element::fromString($value)
),
));
}

Expand Down Expand Up @@ -125,13 +128,11 @@ private function itemElement(Context $context, ?string $itemNodeName, string $it
}

/**
* @param non-empty-string $value
* @return list<mixed>
*/
private function decodeArray(Context $context, string $value): array
private function decodeArray(Context $context, Element $value): array
{
$document = Document::fromXmlString($value);
$element = $document->locateDocumentElement();
$element = $value->element();

return readChildren($element)->reduce(
/**
Expand Down
17 changes: 8 additions & 9 deletions src/Encoder/SoapEnc/SoapObjectEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
use Soap\Encoding\Encoder\SimpleType\ScalarTypeEncoder;
use Soap\Encoding\Encoder\XmlEncoder;
use Soap\Encoding\TypeInference\XsiTypeDetector;
use Soap\Encoding\Xml\Node\Element;
use Soap\Encoding\Xml\Reader\ElementValueReader;
use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter;
use Soap\Encoding\Xml\Writer\XsiAttributeBuilder;
use Soap\Engine\Metadata\Model\XsdType;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Dom\Document;
use function Psl\Dict\merge;
use function VeeWee\Xml\Dom\Locator\Element\children as readChildren;
use function VeeWee\Xml\Writer\Builder\children;
Expand All @@ -37,9 +37,12 @@ public function iso(Context $context): Iso
*/
fn (object $value): string => $this->encodeArray($context, $value),
/**
* @param non-empty-string $value
* @param non-empty-string|Element $value
*/
fn (string $value): object => $this->decodeArray($context, $value),
fn (string|Element $value): object => $this->decodeArray(
$context,
$value instanceof Element ? $value : Element::fromString($value)
),
));
}

Expand Down Expand Up @@ -68,13 +71,9 @@ private function encodeArray(Context $context, object $data): string
);
}

/**
* @param non-empty-string $value
*/
private function decodeArray(Context $context, string $value): object
private function decodeArray(Context $context, Element $value): object
{
$document = Document::fromXmlString($value);
$element = $document->locateDocumentElement();
$element = $value->element();

return (object) readChildren($element)->reduce(
static function (array $map, DOMElement $item) use ($context): array {
Expand Down
3 changes: 2 additions & 1 deletion src/EncoderRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
use Soap\Xml\Xmlns;
use stdClass;
use Stringable;
use function Psl\Dict\pull;

final class EncoderRegistry
Expand Down Expand Up @@ -312,7 +313,7 @@ public function hasRegisteredComplexTypeForXsdType(XsdType $type): bool
}

/**
* @return XmlEncoder<mixed, string>
* @return XmlEncoder<mixed, string|Stringable>
*/
public function detectEncoderForContext(Context $context): XmlEncoder
{
Expand Down
79 changes: 79 additions & 0 deletions src/Xml/Node/Element.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Xml\Node;

use DOMElement;
use Stringable;
use VeeWee\Xml\Dom\Document;
use function Psl\invariant;

final class Element implements Stringable
{
private ?DOMElement $element = null;
/**
* @var non-empty-string|null
*/
private ?string $value = null;

private function __construct()
{
}

/**
* @param non-empty-string $xml
*/
public static function fromString(string $xml): Element
{
$new = new self();
$new->element = null;
$new->value = $xml;

return $new;
}

public static function fromDOMElement(DOMElement $element): self
{
$new = new self();
$new->element = $element;
$new->value = null;

return $new;
}

public function element(): DOMElement
{
if (!$this->element) {
invariant($this->value !== null, 'Expected an XML value to be present');
$this->element = Document::fromXmlString($this->value)->locateDocumentElement();
}

return $this->element;
}

/**
* @return non-empty-string
*/
public function value(): string
{
if ($this->value === null) {
invariant($this->element !== null, 'Expected an DOMElement to be present');
$this->value = Document::fromXmlNode($this->element)->stringifyDocumentElement();
}

return $this->value;
}

public function document(): Document
{
return Document::fromUnsafeDocument($this->element()->ownerDocument);
}

/**
* @return non-empty-string
*/
public function __toString()
{
return $this->value();
}
}
Loading

0 comments on commit af4a2d7

Please sign in to comment.