Skip to content

Commit 21fa98a

Browse files
committed
Parse HTTP binding information
1 parent ffb4e82 commit 21fa98a

17 files changed

+300
-27
lines changed

src/Formatter/MetaTableFormatter.php

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace Soap\WsdlReader\Formatter;
55

6+
use Psl\Option\Option;
67
use ReflectionClass;
78
use ReflectionProperty;
89
use Symfony\Component\Console\Helper\Table;
@@ -58,6 +59,7 @@ private function tryStringifyValue(mixed $value): ?string
5859
is_array($value) => json_encode($value, JSON_PRETTY_PRINT),
5960
is_bool($value) => $value ? 'true' : 'false',
6061
is_scalar($value) => (string)$value,
62+
$value instanceof Option => $value->map($this->tryStringifyValue(...))->unwrapOr(null),
6163
default => null,
6264
};
6365
} catch (Throwable) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Binding;
5+
6+
use Soap\Engine\Metadata\Model\Method;
7+
use Soap\WsdlReader\Model\Definitions\Binding;
8+
use function Psl\Fun\pipe;
9+
10+
final class BindingConfigurator
11+
{
12+
public function __invoke(Method $method, Binding $binding): Method
13+
{
14+
return pipe(
15+
static fn (Method $method) => (new HttpBindingConfigurator())($method, $binding),
16+
static fn (Method $method) => (new SoapBindingConfigurator())($method, $binding),
17+
)($method);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Binding;
5+
6+
use Soap\Engine\Metadata\Model\Method;
7+
use Soap\Engine\Metadata\Model\MethodMeta;
8+
use Soap\WsdlReader\Model\Definitions\Binding;
9+
use Soap\WsdlReader\Model\Definitions\Implementation\Binding\HttpBinding;
10+
11+
final class HttpBindingConfigurator
12+
{
13+
public function __invoke(Method $method, Binding $binding): Method
14+
{
15+
$implementation = $binding->implementation;
16+
if (!$implementation instanceof HttpBinding) {
17+
return $method;
18+
}
19+
20+
return $method->withMeta(
21+
static fn (MethodMeta $meta): MethodMeta => $meta
22+
->withTransport($implementation->transport->value)
23+
);
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<?php
22
declare(strict_types=1);
33

4-
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator;
4+
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Binding;
55

66
use Soap\Engine\Metadata\Model\Method;
77
use Soap\Engine\Metadata\Model\MethodMeta;
88
use Soap\WsdlReader\Model\Definitions\Binding;
99
use Soap\WsdlReader\Model\Definitions\Implementation\Binding\SoapBinding;
1010

11-
final class BindingConfigurator
11+
final class SoapBindingConfigurator
1212
{
1313
public function __invoke(Method $method, Binding $binding): Method
1414
{
@@ -19,7 +19,7 @@ public function __invoke(Method $method, Binding $binding): Method
1919

2020
return $method->withMeta(
2121
static fn (MethodMeta $meta): MethodMeta => $meta
22-
->withTransport($implementation->transport->value)
22+
->withTransport($implementation->transport->value)
2323
);
2424
}
2525
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Operation;
5+
6+
use Soap\Engine\Metadata\Model\Method;
7+
use Soap\Engine\Metadata\Model\MethodMeta;
8+
use Soap\WsdlReader\Model\Definitions\BindingOperation;
9+
use Soap\WsdlReader\Model\Definitions\BindingStyle;
10+
use Soap\WsdlReader\Model\Definitions\BindingUse;
11+
use Soap\WsdlReader\Model\Definitions\EncodingStyle;
12+
use Soap\WsdlReader\Model\Definitions\Implementation\Message\HttpMessage;
13+
use Soap\WsdlReader\Model\Definitions\Implementation\Operation\HttpOperation;
14+
use Soap\WsdlReader\Model\Definitions\SoapVersion;
15+
16+
final class HttpBindingOperationConfigurator
17+
{
18+
public function __invoke(Method $method, BindingOperation $operation): Method
19+
{
20+
$implementation = $operation->implementation;
21+
if (!$implementation instanceof HttpOperation) {
22+
return $method;
23+
}
24+
25+
if (!$this->messageIsConsideredSoap($operation)) {
26+
return $method;
27+
}
28+
29+
$guessedSoapVersion = $implementation->transport->guessSoapVersion();
30+
$guessedBindingUse = $this->guessBindingUse($guessedSoapVersion);
31+
$guessedEncodingStyle = $this->guessEncodingStyle($guessedSoapVersion);
32+
33+
return $method->withMeta(
34+
static fn (MethodMeta $meta): MethodMeta => $meta
35+
->withSoapVersion($guessedSoapVersion?->value)
36+
->withAction('') // Soap Action is considered empty for HTTP binding.
37+
->withOperationName($operation->name)
38+
->withBindingStyle(BindingStyle::RPC->value)
39+
->withInputBindingUsage($guessedBindingUse?->value)
40+
->withInputEncodingStyle($guessedEncodingStyle?->value)
41+
->withOutputBindingUsage($guessedBindingUse?->value)
42+
->withOutputEncodingStyle($guessedEncodingStyle?->value)
43+
);
44+
}
45+
46+
private function messageIsConsideredSoap(BindingOperation $operation): bool
47+
{
48+
$input = $operation->input?->implementation;
49+
if (!$input instanceof HttpMessage) {
50+
return false;
51+
}
52+
53+
return $input->isConsideredSoapContentType();
54+
}
55+
56+
private function guessEncodingStyle(?SoapVersion $soapVersion): ?EncodingStyle
57+
{
58+
return match ($soapVersion) {
59+
SoapVersion::SOAP_11 => EncodingStyle::SOAP_11,
60+
SoapVersion::SOAP_12 => EncodingStyle::SOAP_12_2003_05,
61+
default => null,
62+
};
63+
}
64+
65+
private function guessBindingUse(?SoapVersion $soapVersion): ?BindingUse
66+
{
67+
return match ($soapVersion) {
68+
SoapVersion::SOAP_11 => BindingUse::ENCODED,
69+
SoapVersion::SOAP_12 => BindingUse::LITERAL,
70+
default => null,
71+
};
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Operation;
4+
5+
use Soap\Engine\Metadata\Model\Method;
6+
use Soap\WsdlReader\Model\Definitions\BindingOperation;
7+
use function Psl\Fun\pipe;
8+
9+
final readonly class OperationConfigurator
10+
{
11+
public function __invoke(Method $method, BindingOperation $operation): Method
12+
{
13+
return pipe(
14+
static fn (Method $method) => (new HttpBindingOperationConfigurator())($method, $operation),
15+
static fn (Method $method) => (new SoapBindingOperationConfigurator())($method, $operation),
16+
)($method);
17+
}
18+
}

src/Metadata/Converter/Methods/Configurator/BindingOperationConfigurator.php renamed to src/Metadata/Converter/Methods/Configurator/Operation/SoapBindingOperationConfigurator.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
declare(strict_types=1);
33

4-
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator;
4+
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Operation;
55

66
use Soap\Engine\Metadata\Model\Method;
77
use Soap\Engine\Metadata\Model\MethodMeta;
@@ -10,7 +10,7 @@
1010
use Soap\WsdlReader\Model\Definitions\Implementation\Message\SoapMessage;
1111
use Soap\WsdlReader\Model\Definitions\Implementation\Operation\SoapOperation;
1212

13-
final class BindingOperationConfigurator
13+
final class SoapBindingOperationConfigurator
1414
{
1515
public function __invoke(Method $method, BindingOperation $operation): Method
1616
{

src/Metadata/Converter/Methods/Configurator/Wsdl1Configurator.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ final class Wsdl1Configurator
1111
{
1212
public function __invoke(Method $method, Wsdl1 $wsdl): Method
1313
{
14+
$targetNamespace = $wsdl->targetNamespace?->value();
15+
1416
return $method->withMeta(
1517
static fn (MethodMeta $meta): MethodMeta => $meta
16-
->withTargetNamespace($wsdl->targetNamespace?->value())
18+
->withTargetNamespace($targetNamespace)
19+
->withInputNamespace($targetNamespace)
20+
->withOutputNamespace($targetNamespace)
1721
);
1822
}
1923
}

src/Metadata/Converter/Methods/Configurator/Wsdl1SelectedServiceConfigurator.php

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace Soap\WsdlReader\Metadata\Converter\Methods\Configurator;
55

66
use Soap\Engine\Metadata\Model\Method;
7+
use Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Binding\BindingConfigurator;
78
use Soap\WsdlReader\Model\Service\Wsdl1SelectedService;
89
use function Psl\Fun\pipe;
910

src/Metadata/Converter/Wsdl1ToMethodsConverter.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Soap\Engine\Metadata\Model\Parameter;
1010
use Soap\Engine\Metadata\Model\XsdType;
1111
use Soap\WsdlReader\Locator\Wsdl1SelectedServiceLocator;
12-
use Soap\WsdlReader\Metadata\Converter\Methods\Configurator\BindingOperationConfigurator;
12+
use Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Operation\OperationConfigurator;
1313
use Soap\WsdlReader\Metadata\Converter\Methods\Configurator\PortTypeOperationConfigurator;
1414
use Soap\WsdlReader\Metadata\Converter\Methods\Configurator\Wsdl1SelectedServiceConfigurator;
1515
use Soap\WsdlReader\Metadata\Converter\Methods\Converter\MessageToMetadataTypesConverter;
@@ -66,7 +66,7 @@ private function parseMethod(Wsdl1SelectedService $service, BindingOperation $bi
6666

6767
$configure = pipe(
6868
static fn (Method $method) => (new Wsdl1SelectedServiceConfigurator())($method, $service),
69-
static fn (Method $method) => (new BindingOperationConfigurator())($method, $bindingOperation),
69+
static fn (Method $method) => (new OperationConfigurator())($method, $bindingOperation),
7070
static fn (Method $method) => (new PortTypeOperationConfigurator())($method, $portTypeOperation),
7171
);
7272

src/Model/Definitions/AddressBindingType.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ enum AddressBindingType : string
99
case SOAP_12 = 'http://schemas.xmlsoap.org/wsdl/soap12/';
1010
case RPC = 'http://www.w3.org/2003/05/soap-rpc"';
1111
case HTTP_11 = 'http://schemas.xmlsoap.org/wsdl/http/';
12-
case HTTP_12 = 'http://www.w3.org/2003/05/soap/bindings/HTTP/"';
12+
case HTTP_12 = 'http://www.w3.org/2003/05/soap/bindings/HTTP/';
1313

1414
public function isSoap(): bool
1515
{

src/Model/Definitions/Implementation/Binding/HttpBinding.php

+3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33

44
namespace Soap\WsdlReader\Model\Definitions\Implementation\Binding;
55

6+
use Soap\WsdlReader\Model\Definitions\TransportType;
7+
68
final class HttpBinding implements BindingImplementation
79
{
810
public function __construct(
911
public readonly string $verb,
12+
public readonly TransportType $transport,
1013
) {
1114
}
1215
}

src/Model/Definitions/Implementation/Message/HttpMessage.php

+15-15
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55

66
final class HttpMessage implements MessageImplementation
77
{
8-
// TODO ...
9-
/*
10-
* <wsdl:input>
11-
<mime:content type="application/x-www-form-urlencoded"/>
12-
</wsdl:input>
13-
<wsdl:output>
14-
<mime:mimeXml part="getServiceTicketResponsePart"/>
15-
</wsdl:output>
8+
public function __construct(
9+
public readonly string $contentType,
10+
public readonly ?string $part,
11+
) {
12+
}
1613

17-
<wsdl:input>
18-
<http:urlEncoded/>
19-
</wsdl:input>
20-
<wsdl:output>
21-
<mime:content part="ticket" type="text/plain"/>
22-
</wsdl:output>
23-
*/
14+
public function isConsideredSoapContentType(): bool
15+
{
16+
return match(mb_strtolower($this->contentType)) {
17+
'application/xml' => true,
18+
'application/text' => true,
19+
'application/soap+xml' => true,
20+
'multipart/related' => true,
21+
default => false,
22+
};
23+
}
2424
}

src/Model/Definitions/Implementation/Operation/HttpOperation.php

+3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33

44
namespace Soap\WsdlReader\Model\Definitions\Implementation\Operation;
55

6+
use Soap\WsdlReader\Model\Definitions\TransportType;
7+
68
final class HttpOperation implements OperationImplementation
79
{
810
public function __construct(
911
public readonly string $location,
12+
public readonly TransportType $transport,
1013
) {
1114
}
1215
}

src/Model/Definitions/TransportType.php

+9
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,13 @@ public function isHttp(): bool
1313
{
1414
return $this === self::HTTP || $this === self::W3_HTTP;
1515
}
16+
17+
public function guessSoapVersion(): ?SoapVersion
18+
{
19+
return match ($this) {
20+
self::HTTP, self::SMTP => SoapVersion::SOAP_11,
21+
self::W3_HTTP => SoapVersion::SOAP_12,
22+
default => null,
23+
};
24+
}
1625
}

src/Parser/Strategy/HttpStrategy.php

+35-3
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,58 @@
1010
use Soap\WsdlReader\Model\Definitions\Implementation\Message\MessageImplementation;
1111
use Soap\WsdlReader\Model\Definitions\Implementation\Operation\HttpOperation;
1212
use Soap\WsdlReader\Model\Definitions\Implementation\Operation\OperationImplementation;
13+
use Soap\WsdlReader\Model\Definitions\TransportType;
1314
use VeeWee\Xml\Dom\Document;
15+
use function VeeWee\Xml\Dom\Locator\Element\children;
1416

1517
final class HttpStrategy implements StrategyInterface
1618
{
19+
private const HTTP_NAMESPACE = 'http://schemas.xmlsoap.org/wsdl/http/';
20+
private const MIME_NAMESPACE = 'http://schemas.xmlsoap.org/wsdl/mime/';
21+
1722
public function parseBindingImplementation(Document $wsdl, DOMElement $binding): BindingImplementation
1823
{
1924
return new HttpBinding(
20-
verb: $binding->getAttribute('verb')
25+
verb: $binding->getAttribute('verb'),
26+
transport: TransportType::tryFrom((string) $binding->namespaceURI) ?? TransportType::HTTP,
2127
);
2228
}
2329

2430
public function parseOperationImplementation(Document $wsdl, DOMElement $operation): OperationImplementation
2531
{
2632
return new HttpOperation(
27-
location: $operation->getAttribute('location')
33+
location: $operation->getAttribute('location'),
34+
transport: TransportType::tryFrom((string) $operation->namespaceURI) ?? TransportType::HTTP,
2835
);
2936
}
3037

3138
public function parseMessageImplementation(Document $wsdl, DOMElement $message): MessageImplementation
3239
{
33-
return new HttpMessage();
40+
$info = children($message)->first();
41+
$fallbackImplementation = new HttpMessage(
42+
contentType: 'application/xml',
43+
part: null
44+
);
45+
46+
if (!$info) {
47+
return $fallbackImplementation;
48+
}
49+
50+
return match ($info->namespaceURI) {
51+
self::HTTP_NAMESPACE => new HttpMessage(
52+
contentType: 'text/plain',
53+
part: null
54+
),
55+
self::MIME_NAMESPACE => new HttpMessage(
56+
contentType: match($info->localName) {
57+
'content' => $info->hasAttribute('type') ? $info->getAttribute('type'): 'application/xml',
58+
'mimeXml' => 'application/xml',
59+
'multipartRelated' => 'Multipart/Related',
60+
default => 'application/xml'
61+
},
62+
part: $info->hasAttribute('part') ? $info->getAttribute('part') : null,
63+
),
64+
default => $fallbackImplementation,
65+
};
3466
}
3567
}

0 commit comments

Comments
 (0)