Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve operation and param element generation #16

Merged
merged 1 commit into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions src/Encoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use Soap\Encoding\Encoder\Context;
use Soap\Encoding\Xml\Writer\OperationBuilder;
use Soap\Encoding\Xml\Writer\ParameterBuilder;
use Soap\Encoding\Xml\Writer\SoapEnvelopeWriter;
use Soap\Engine\Encoder as SoapEncoder;
use Soap\Engine\HttpBinding\SoapRequest;
Expand All @@ -13,8 +14,6 @@
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
use Soap\WsdlReader\Model\Definitions\Namespaces;
use Soap\WsdlReader\Model\Definitions\SoapVersion;
use function Psl\Type\mixed;
use function Psl\Type\non_empty_string;
use function VeeWee\Reflecta\Lens\index;

final class Encoder implements SoapEncoder
Expand All @@ -35,19 +34,17 @@ public function encode(string $method, array $arguments): SoapRequest
$bindingUse = $meta->inputBindingUsage()->map(BindingUse::from(...))->unwrapOr(BindingUse::LITERAL);
$encodingStyle = $meta->inputEncodingStyle()->map(EncodingStyle::from(...));

$request = [];
$requestParams = [];
foreach ($methodInfo->getParameters() as $index => $parameter) {
$type = $parameter->getType();
$context = new Context($type, $this->metadata, $this->registry, $this->namespaces, $bindingUse);
/** @var mixed $argument */
$argument = index($index)->get($arguments);
/** @var mixed $value */
$value = index($index)->get($arguments);

$request[] = non_empty_string()->assert(
$this->registry->detectEncoderForContext($context)->iso($context)->to($argument)
);
$requestParams[] = (new ParameterBuilder($meta, $context, $value))(...);
}

$operation = new OperationBuilder($meta, $this->namespaces, $request);
$operation = new OperationBuilder($meta, $this->namespaces, $requestParams);
$writeEnvelope = new SoapEnvelopeWriter($soapVersion, $bindingUse, $encodingStyle, $operation(...));

return new SoapRequest(
Expand Down
28 changes: 0 additions & 28 deletions src/Xml/Reader/ChildrenReader.php

This file was deleted.

37 changes: 13 additions & 24 deletions src/Xml/Writer/OperationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@

namespace Soap\Encoding\Xml\Writer;

use Closure;
use Generator;
use Soap\Encoding\Xml\Reader\ChildrenReader;
use Soap\Engine\Metadata\Model\MethodMeta;
use Soap\WsdlReader\Model\Definitions\BindingStyle;
use Soap\WsdlReader\Model\Definitions\Namespaces;
use XMLWriter;
use function Psl\Vec\map;
use function VeeWee\Xml\Writer\Builder\children;
use function VeeWee\Xml\Writer\Builder\namespaced_element;
use function VeeWee\Xml\Writer\Builder\raw;

final class OperationBuilder
{
/**
* @param list<non-empty-string> $parameters
* @param list<Closure(XMLWriter): Generator<bool>> $parameters
*/
public function __construct(
private readonly MethodMeta $meta,
Expand All @@ -29,22 +28,6 @@ public function __construct(
* @return Generator<bool>
*/
public function __invoke(XMLWriter $writer): Generator
{
$operationName = $this->meta->operationName()->unwrap();
$namespace = $this->meta->inputNamespace()->or($this->meta->targetNamespace())->unwrap();

yield from namespaced_element(
$namespace,
$this->namespaces->lookupNameFromNamespace($namespace)->unwrapOr('tns'),
$operationName,
$this->buildChildren(...)
)($writer);
}

/**
* @return Generator<bool>
*/
private function buildChildren(XMLWriter $writer): Generator
{
$bindingStyle = BindingStyle::tryFrom($this->meta->bindingStyle()->unwrapOr(BindingStyle::DOCUMENT->value));

Expand All @@ -59,16 +42,22 @@ private function buildChildren(XMLWriter $writer): Generator
*/
private function buildDocument(XMLWriter $writer): Generator
{
$documentParts = map($this->parameters, (new ChildrenReader())(...));

yield from raw(implode('', $documentParts))($writer);
yield from children($this->parameters)($writer);
}

/**
* @return Generator<bool>
*/
private function buildRpc(XMLWriter $writer): Generator
{
yield from raw(implode('', $this->parameters))($writer);
$operationName = $this->meta->operationName()->unwrap();
$namespace = $this->meta->inputNamespace()->or($this->meta->targetNamespace())->unwrap();

yield from namespaced_element(
$namespace,
$this->namespaces->lookupNameFromNamespace($namespace)->unwrapOr('tns'),
$operationName,
children($this->parameters),
)($writer);
}
}
71 changes: 71 additions & 0 deletions src/Xml/Writer/ParameterBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);

namespace Soap\Encoding\Xml\Writer;

use Generator;
use Soap\Encoding\Encoder\Context;
use Soap\Engine\Metadata\Model\MethodMeta;
use Soap\Engine\Metadata\Model\TypeMeta;
use Soap\WsdlReader\Model\Definitions\BindingStyle;
use XMLWriter;
use function Psl\Type\non_empty_string;
use function VeeWee\Xml\Writer\Builder\raw;

final class ParameterBuilder
{
public function __construct(
private readonly MethodMeta $meta,
private readonly Context $context,
private readonly mixed $value
) {
}

/**
* @return Generator<bool>
*/
public function __invoke(XMLWriter $writer): Generator
{
$bindingStyle = BindingStyle::tryFrom($this->meta->bindingStyle()->unwrapOr(BindingStyle::DOCUMENT->value));

yield from match($bindingStyle) {
BindingStyle::DOCUMENT => $this->buildDocument($writer),
BindingStyle::RPC => $this->buildRpc($writer),
};
}

/**
* @return Generator<bool>
*/
private function buildDocument(XMLWriter $writer): Generator
{
$type = $this->context->type;
$context = $this->context->withType(
$type
->withXmlTargetNodeName($type->getName())
->withMeta(
static fn (TypeMeta $meta) => $meta->withIsQualified(true)
)
);

yield from raw($this->encode($context))($writer);
}

/**
* @return Generator<bool>
*/
private function buildRpc(XMLWriter $writer): Generator
{
yield from raw($this->encode($this->context))($writer);
}

/**
* @return non-empty-string
*/
private function encode(Context $context): string
{
return non_empty_string()->assert(
$context->registry->detectEncoderForContext($context)->iso($context)->to($this->value)
);
}
}
72 changes: 39 additions & 33 deletions src/Xml/Writer/SoapEnvelopeWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
use Closure;
use Generator;
use Psl\Option\Option;
use Soap\Encoding\Exception\ExceptionInterface as EncodingExceptionInterface;
use Soap\WsdlReader\Model\Definitions\BindingUse;
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
use Soap\WsdlReader\Model\Definitions\SoapVersion;
use Soap\Xml\Xmlns;
use VeeWee\Xml\Exception\RuntimeException as XmlRuntimeException;
use VeeWee\Xml\Writer\Writer;
use XMLWriter;
use function Psl\Vec\filter_nulls;
Expand Down Expand Up @@ -42,44 +44,48 @@ public function __invoke(): string
SoapVersion::SOAP_12 => rtrim(Xmlns::soap12Envelope()->value(), '/'),
};

return Writer::inMemory()
->write(
namespaced_element(
$envelopeNamespace,
'SOAP-ENV',
'Envelope',
try {
return Writer::inMemory()
->write(
namespaced_element(
$envelopeNamespace,
'SOAP-ENV',
'Body',
children(
filter_nulls([
// In SOAP 1.2 the position of the encoding attributes is limited:
// See: https://www.w3.org/TR/soap12-part1/#soapencattr
// For SOAP 1.1 it can be everywhere:
// See: https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383495
$this->encodingStyle
->filter(fn (): bool => $this->bindingUse === BindingUse::ENCODED)
->map(
static fn (EncodingStyle $encodingStyle) => children([
namespace_attribute(
$encodingStyle->value,
'SOAP-ENC'
),
namespaced_attribute(
$envelopeNamespace,
'SOAP-ENV',
'encodingStyle',
$encodingStyle->value
)
])
)->unwrapOr(null),
$this->children
])
'Envelope',
namespaced_element(
$envelopeNamespace,
'SOAP-ENV',
'Body',
children(
filter_nulls([
// In SOAP 1.2 the position of the encoding attributes is limited:
// See: https://www.w3.org/TR/soap12-part1/#soapencattr
// For SOAP 1.1 it can be everywhere:
// See: https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383495
$this->encodingStyle
->filter(fn (): bool => $this->bindingUse === BindingUse::ENCODED)
->map(
static fn (EncodingStyle $encodingStyle) => children([
namespace_attribute(
$encodingStyle->value,
'SOAP-ENC'
),
namespaced_attribute(
$envelopeNamespace,
'SOAP-ENV',
'encodingStyle',
$encodingStyle->value
)
])
)->unwrapOr(null),
$this->children
])
)
)
)
)
)
->map(memory_output());
->map(memory_output());
} catch (XmlRuntimeException $e) {
throw ($e->getPrevious() instanceof EncodingExceptionInterface) ? $e->getPrevious() : $e;
}
}
}
2 changes: 1 addition & 1 deletion tests/PhpCompatibility/Schema071Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected function calculateParam(): mixed
#[Test]
public function it_is_compatible_with_phps_encoding()
{
static::markTestSkipped('Literal document seems about right - yet php soap uses the type instead of the part name. Not sure what to do here yet.');
static::markTestSkipped('Literal document seems about right - it seems to be taking the param name instead of the complextype name though. Not sure what to do here yet.');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO : Check spec for literal encoding on what to do here.
Current assumption:

  • if the type is a complex type, the parameter name is being used (unqualified)
  • if the type is an element type, the element info is being used (qualified)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cant seem to figure out why it is encoding it like this. SOAP-UI is also using the message part name. Leaving it for now.

}

protected function expectXml(): string
Expand Down
7 changes: 0 additions & 7 deletions tests/PhpCompatibility/Schema072Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace Soap\Encoding\Test\PhpCompatibility;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use Soap\Encoding\Decoder;
use Soap\Encoding\Driver;
use Soap\Encoding\Encoder;
Expand Down Expand Up @@ -37,12 +36,6 @@ protected function calculateParam(): mixed
];
}

#[Test]
public function it_is_compatible_with_phps_encoding()
{
static::markTestSkipped('Literal document seems about right - yet php soap uses the type instead of the part name. Not sure what to do here yet.');
}

protected function expectXml(): string
{
return <<<XML
Expand Down
7 changes: 0 additions & 7 deletions tests/PhpCompatibility/Schema073Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace Soap\Encoding\Test\PhpCompatibility;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use Soap\Encoding\Decoder;
use Soap\Encoding\Driver;
use Soap\Encoding\Encoder;
Expand Down Expand Up @@ -36,12 +35,6 @@ protected function calculateParam(): mixed
];
}

#[Test]
public function it_is_compatible_with_phps_encoding()
{
static::markTestSkipped('Literal document seems about right - yet php soap uses the type instead of the part name. Not sure what to do here yet.');
}

protected function expectXml(): string
{
return <<<XML
Expand Down
Loading