Skip to content

Commit 938f361

Browse files
authored
fix(laravel-soap-115): setting headers is not working (#120)
* fix(laravel-soap-115): setting headers is not working Seems Phpro also never had the header issue ... made some "improvements" :> * Apply fixes from StyleCI (#121) Co-authored-by: Gregor Becker <[email protected]> Co-authored-by: Gregor Becker <[email protected]>
1 parent 7d7311e commit 938f361

File tree

6 files changed

+437
-3
lines changed

6 files changed

+437
-3
lines changed

src/Facades/Soap.php

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* @method static \CodeDredd\Soap\SoapClient buildClient(string $setup = '')
1414
* @method static \CodeDredd\Soap\SoapClient byConfig(string $setup = '')
1515
* @method static \CodeDredd\Soap\SoapClient withOptions(array $options)
16+
* @method static \CodeDredd\Soap\SoapClient withHeaders(array $options)
1617
* @method static \CodeDredd\Soap\SoapClient handlerOptions(array $options)
1718
* @method static \CodeDredd\Soap\SoapClient withWsse(array $config)
1819
* @method static \CodeDredd\Soap\SoapClient withWsa()

src/Handler/HttPlugHandle.php

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace CodeDredd\Soap\Handler;
4+
5+
use CodeDredd\Soap\HttpBinding\Converter\Psr7Converter;
6+
use Http\Client\Common\PluginClient;
7+
use Http\Discovery\HttpClientDiscovery;
8+
use Http\Discovery\MessageFactoryDiscovery;
9+
use Http\Discovery\StreamFactoryDiscovery;
10+
use Phpro\SoapClient\Middleware\CollectLastRequestInfoMiddleware;
11+
use Phpro\SoapClient\Middleware\MiddlewareInterface;
12+
use Phpro\SoapClient\Middleware\MiddlewareSupportingInterface;
13+
use Phpro\SoapClient\Soap\Handler\HandlerInterface;
14+
use Phpro\SoapClient\Soap\Handler\LastRequestInfoCollectorInterface;
15+
use Phpro\SoapClient\Soap\HttpBinding\LastRequestInfo;
16+
use Phpro\SoapClient\Soap\HttpBinding\SoapRequest;
17+
use Phpro\SoapClient\Soap\HttpBinding\SoapResponse;
18+
use Psr\Http\Client\ClientInterface;
19+
20+
class HttPlugHandle implements HandlerInterface, MiddlewareSupportingInterface
21+
{
22+
/**
23+
* @var ClientInterface
24+
*/
25+
private $client;
26+
27+
/**
28+
* @var LastRequestInfoCollectorInterface
29+
*/
30+
private $lastRequestInfoCollector;
31+
32+
/**
33+
* @var Psr7Converter
34+
*/
35+
private $converter;
36+
37+
/**
38+
* @var array
39+
*/
40+
private $middlewares = [];
41+
42+
/**
43+
* @var array
44+
*/
45+
private $requestHeaders = [];
46+
47+
public function __construct(
48+
ClientInterface $client,
49+
Psr7Converter $converter,
50+
CollectLastRequestInfoMiddleware $lastRequestInfoCollector,
51+
$requestHeaders = []
52+
) {
53+
$this->client = $client;
54+
$this->converter = $converter;
55+
$this->lastRequestInfoCollector = $lastRequestInfoCollector;
56+
$this->requestHeaders = $requestHeaders;
57+
}
58+
59+
public static function createWithDefaultClient(): HttPlugHandle
60+
{
61+
return self::createForClient(HttpClientDiscovery::find());
62+
}
63+
64+
public static function createForClient(ClientInterface $client, $requestHeaders = []): HttPlugHandle
65+
{
66+
return new self(
67+
$client,
68+
new Psr7Converter(
69+
MessageFactoryDiscovery::find(),
70+
StreamFactoryDiscovery::find()
71+
),
72+
new CollectLastRequestInfoMiddleware(),
73+
$requestHeaders
74+
);
75+
}
76+
77+
public function addMiddleware(MiddlewareInterface $middleware)
78+
{
79+
$this->middlewares[$middleware->getName()] = $middleware;
80+
}
81+
82+
public function request(SoapRequest $request): SoapResponse
83+
{
84+
$client = new PluginClient(
85+
$this->client,
86+
array_merge(
87+
array_values($this->middlewares),
88+
[$this->lastRequestInfoCollector]
89+
)
90+
);
91+
92+
$psr7Request = $this->converter->convertSoapRequest($request, $this->requestHeaders);
93+
$psr7Response = $client->sendRequest($psr7Request);
94+
95+
return $this->converter->convertSoapResponse($psr7Response);
96+
}
97+
98+
public function collectLastRequestInfo(): LastRequestInfo
99+
{
100+
return $this->lastRequestInfoCollector->collectLastRequestInfo();
101+
}
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
3+
namespace CodeDredd\Soap\HttpBinding\Builder;
4+
5+
use Http\Message\MessageFactory;
6+
use Http\Message\StreamFactory;
7+
use Phpro\SoapClient\Exception\RequestException;
8+
use Psr\Http\Message\RequestInterface;
9+
use Psr\Http\Message\StreamInterface;
10+
11+
class Psr7RequestBuilder
12+
{
13+
const SOAP11 = '1.1';
14+
const SOAP12 = '1.2';
15+
16+
/**
17+
* @var string
18+
*/
19+
private $endpoint;
20+
21+
/**
22+
* @var array
23+
*/
24+
private $headers = [];
25+
26+
/**
27+
* @var string
28+
*/
29+
private $soapVersion = self::SOAP11;
30+
31+
/**
32+
* @var string
33+
*/
34+
private $soapAction = '';
35+
36+
/**
37+
* @var StreamInterface
38+
*/
39+
private $soapMessage;
40+
41+
/**
42+
* @var bool
43+
*/
44+
private $hasSoapMessage = false;
45+
46+
/**
47+
* @var string
48+
*/
49+
private $httpMethod = 'POST';
50+
51+
/**
52+
* @var MessageFactory
53+
*/
54+
private $messageFactory;
55+
56+
/**
57+
* @var StreamFactory
58+
*/
59+
private $streamFactory;
60+
61+
public function __construct(MessageFactory $messageFactory, StreamFactory $streamFactory)
62+
{
63+
$this->messageFactory = $messageFactory;
64+
$this->streamFactory = $streamFactory;
65+
}
66+
67+
/**
68+
* @return RequestInterface
69+
* @throws RequestException
70+
*/
71+
public function getHttpRequest(): RequestInterface
72+
{
73+
$this->validate();
74+
75+
try {
76+
$request = $this->messageFactory
77+
->createRequest($this->httpMethod, $this->endpoint)
78+
->withBody($this->prepareMessage());
79+
$headers = array_merge($this->prepareHeaders(), $this->headers);
80+
81+
foreach ($headers as $name => $value) {
82+
$request = $request->withHeader($name, $value);
83+
}
84+
} catch (\InvalidArgumentException $e) {
85+
throw new RequestException($e->getMessage(), $e->getCode(), $e);
86+
}
87+
88+
return $request;
89+
}
90+
91+
/**
92+
* @param string $endpoint
93+
*/
94+
public function setEndpoint(string $endpoint)
95+
{
96+
$this->endpoint = $endpoint;
97+
}
98+
99+
/**
100+
* @param array $headers
101+
*/
102+
public function setHeaders(array $headers)
103+
{
104+
$this->headers = $headers;
105+
}
106+
107+
/**
108+
* Mark as SOAP 1.1.
109+
*/
110+
public function isSOAP11()
111+
{
112+
$this->soapVersion = self::SOAP11;
113+
}
114+
115+
/**
116+
* Mark as SOAP 1.2.
117+
*/
118+
public function isSOAP12()
119+
{
120+
$this->soapVersion = self::SOAP12;
121+
}
122+
123+
/**
124+
* @param string $soapAction
125+
*/
126+
public function setSoapAction(string $soapAction)
127+
{
128+
$this->soapAction = $soapAction;
129+
}
130+
131+
/**
132+
* @param string $content
133+
*/
134+
public function setSoapMessage(string $content)
135+
{
136+
$this->soapMessage = $this->streamFactory->createStream($content);
137+
$this->hasSoapMessage = true;
138+
}
139+
140+
/**
141+
* @param string $method
142+
*/
143+
public function setHttpMethod(string $method)
144+
{
145+
$this->httpMethod = $method;
146+
}
147+
148+
/**
149+
* @return void
150+
* @throws \Phpro\SoapClient\Exception\RequestException
151+
*/
152+
private function validate()
153+
{
154+
if (! $this->endpoint) {
155+
throw new RequestException('There is no endpoint specified.');
156+
}
157+
158+
if (! $this->hasSoapMessage && $this->httpMethod === 'POST') {
159+
throw new RequestException('There is no SOAP message specified.');
160+
}
161+
162+
/**
163+
* SOAP 1.1 only defines HTTP binding with POST method.
164+
* @link https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383527
165+
*/
166+
if ($this->soapVersion === self::SOAP11 && $this->httpMethod !== 'POST') {
167+
throw new RequestException('You cannot use the POST method with SOAP 1.1.');
168+
}
169+
170+
/**
171+
* SOAP 1.2 only defines HTTP binding with POST and GET methods.
172+
* @link https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L10309
173+
*/
174+
if ($this->soapVersion === self::SOAP12 && ! in_array($this->httpMethod, ['GET', 'POST'])) {
175+
throw new RequestException('Invalid SOAP method specified for SOAP 1.2. Expeted: GET or POST.');
176+
}
177+
}
178+
179+
/**
180+
* @return array
181+
*/
182+
private function prepareHeaders(): array
183+
{
184+
if ($this->soapVersion === self::SOAP11) {
185+
return $this->prepareSoap11Headers();
186+
}
187+
188+
return $this->prepareSoap12Headers();
189+
}
190+
191+
/**
192+
* @link https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383526
193+
* @return array
194+
*/
195+
private function prepareSoap11Headers(): array
196+
{
197+
$headers = [];
198+
$headers['Content-Length'] = (string) $this->soapMessage->getSize();
199+
$headers['SOAPAction'] = $this->soapAction;
200+
$headers['Content-Type'] = 'text/xml; charset="utf-8"';
201+
202+
return $headers;
203+
}
204+
205+
/**
206+
* SOAPAction header is removed in SOAP 1.2 and now expressed as a value of
207+
* an (optional) "action" parameter of the "application/soap+xml" media type.
208+
* @link https://www.w3.org/TR/soap12-part0/#L4697
209+
* @return array
210+
*/
211+
private function prepareSoap12Headers(): array
212+
{
213+
$headers = [];
214+
if ($this->httpMethod !== 'POST') {
215+
$headers['Accept'] = 'application/soap+xml';
216+
217+
return $headers;
218+
}
219+
220+
$headers['Content-Length'] = (string) $this->soapMessage->getSize();
221+
$headers['Content-Type'] = 'application/soap+xml; charset="utf-8"'.'; action="'.$this->soapAction.'"';
222+
223+
return $headers;
224+
}
225+
226+
/**
227+
* @return StreamInterface
228+
*/
229+
private function prepareMessage(): StreamInterface
230+
{
231+
if ($this->httpMethod === 'POST') {
232+
return $this->soapMessage;
233+
}
234+
235+
return $this->streamFactory->createStream('');
236+
}
237+
}

0 commit comments

Comments
 (0)