Skip to content

fix(laravel-soap-115): setting headers is not working #120

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

Merged
merged 2 commits into from
Mar 29, 2021
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
1 change: 1 addition & 0 deletions src/Facades/Soap.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* @method static \CodeDredd\Soap\SoapClient buildClient(string $setup = '')
* @method static \CodeDredd\Soap\SoapClient byConfig(string $setup = '')
* @method static \CodeDredd\Soap\SoapClient withOptions(array $options)
* @method static \CodeDredd\Soap\SoapClient withHeaders(array $options)
* @method static \CodeDredd\Soap\SoapClient handlerOptions(array $options)
* @method static \CodeDredd\Soap\SoapClient withWsse(array $config)
* @method static \CodeDredd\Soap\SoapClient withWsa()
Expand Down
102 changes: 102 additions & 0 deletions src/Handler/HttPlugHandle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace CodeDredd\Soap\Handler;

use CodeDredd\Soap\HttpBinding\Converter\Psr7Converter;
use Http\Client\Common\PluginClient;
use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Discovery\StreamFactoryDiscovery;
use Phpro\SoapClient\Middleware\CollectLastRequestInfoMiddleware;
use Phpro\SoapClient\Middleware\MiddlewareInterface;
use Phpro\SoapClient\Middleware\MiddlewareSupportingInterface;
use Phpro\SoapClient\Soap\Handler\HandlerInterface;
use Phpro\SoapClient\Soap\Handler\LastRequestInfoCollectorInterface;
use Phpro\SoapClient\Soap\HttpBinding\LastRequestInfo;
use Phpro\SoapClient\Soap\HttpBinding\SoapRequest;
use Phpro\SoapClient\Soap\HttpBinding\SoapResponse;
use Psr\Http\Client\ClientInterface;

class HttPlugHandle implements HandlerInterface, MiddlewareSupportingInterface
{
/**
* @var ClientInterface
*/
private $client;

/**
* @var LastRequestInfoCollectorInterface
*/
private $lastRequestInfoCollector;

/**
* @var Psr7Converter
*/
private $converter;

/**
* @var array
*/
private $middlewares = [];

/**
* @var array
*/
private $requestHeaders = [];

public function __construct(
ClientInterface $client,
Psr7Converter $converter,
CollectLastRequestInfoMiddleware $lastRequestInfoCollector,
$requestHeaders = []
) {
$this->client = $client;
$this->converter = $converter;
$this->lastRequestInfoCollector = $lastRequestInfoCollector;
$this->requestHeaders = $requestHeaders;
}

public static function createWithDefaultClient(): HttPlugHandle
{
return self::createForClient(HttpClientDiscovery::find());
}

public static function createForClient(ClientInterface $client, $requestHeaders = []): HttPlugHandle
{
return new self(
$client,
new Psr7Converter(
MessageFactoryDiscovery::find(),
StreamFactoryDiscovery::find()
),
new CollectLastRequestInfoMiddleware(),
$requestHeaders
);
}

public function addMiddleware(MiddlewareInterface $middleware)
{
$this->middlewares[$middleware->getName()] = $middleware;
}

public function request(SoapRequest $request): SoapResponse
{
$client = new PluginClient(
$this->client,
array_merge(
array_values($this->middlewares),
[$this->lastRequestInfoCollector]
)
);

$psr7Request = $this->converter->convertSoapRequest($request, $this->requestHeaders);
$psr7Response = $client->sendRequest($psr7Request);

return $this->converter->convertSoapResponse($psr7Response);
}

public function collectLastRequestInfo(): LastRequestInfo
{
return $this->lastRequestInfoCollector->collectLastRequestInfo();
}
}
237 changes: 237 additions & 0 deletions src/HttpBinding/Builder/Psr7RequestBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
<?php

namespace CodeDredd\Soap\HttpBinding\Builder;

use Http\Message\MessageFactory;
use Http\Message\StreamFactory;
use Phpro\SoapClient\Exception\RequestException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;

class Psr7RequestBuilder
{
const SOAP11 = '1.1';
const SOAP12 = '1.2';

/**
* @var string
*/
private $endpoint;

/**
* @var array
*/
private $headers = [];

/**
* @var string
*/
private $soapVersion = self::SOAP11;

/**
* @var string
*/
private $soapAction = '';

/**
* @var StreamInterface
*/
private $soapMessage;

/**
* @var bool
*/
private $hasSoapMessage = false;

/**
* @var string
*/
private $httpMethod = 'POST';

/**
* @var MessageFactory
*/
private $messageFactory;

/**
* @var StreamFactory
*/
private $streamFactory;

public function __construct(MessageFactory $messageFactory, StreamFactory $streamFactory)
{
$this->messageFactory = $messageFactory;
$this->streamFactory = $streamFactory;
}

/**
* @return RequestInterface
* @throws RequestException
*/
public function getHttpRequest(): RequestInterface
{
$this->validate();

try {
$request = $this->messageFactory
->createRequest($this->httpMethod, $this->endpoint)
->withBody($this->prepareMessage());
$headers = array_merge($this->prepareHeaders(), $this->headers);

foreach ($headers as $name => $value) {
$request = $request->withHeader($name, $value);
}
} catch (\InvalidArgumentException $e) {
throw new RequestException($e->getMessage(), $e->getCode(), $e);
}

return $request;
}

/**
* @param string $endpoint
*/
public function setEndpoint(string $endpoint)
{
$this->endpoint = $endpoint;
}

/**
* @param array $headers
*/
public function setHeaders(array $headers)
{
$this->headers = $headers;
}

/**
* Mark as SOAP 1.1.
*/
public function isSOAP11()
{
$this->soapVersion = self::SOAP11;
}

/**
* Mark as SOAP 1.2.
*/
public function isSOAP12()
{
$this->soapVersion = self::SOAP12;
}

/**
* @param string $soapAction
*/
public function setSoapAction(string $soapAction)
{
$this->soapAction = $soapAction;
}

/**
* @param string $content
*/
public function setSoapMessage(string $content)
{
$this->soapMessage = $this->streamFactory->createStream($content);
$this->hasSoapMessage = true;
}

/**
* @param string $method
*/
public function setHttpMethod(string $method)
{
$this->httpMethod = $method;
}

/**
* @return void
* @throws \Phpro\SoapClient\Exception\RequestException
*/
private function validate()
{
if (! $this->endpoint) {
throw new RequestException('There is no endpoint specified.');
}

if (! $this->hasSoapMessage && $this->httpMethod === 'POST') {
throw new RequestException('There is no SOAP message specified.');
}

/**
* SOAP 1.1 only defines HTTP binding with POST method.
* @link https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383527
*/
if ($this->soapVersion === self::SOAP11 && $this->httpMethod !== 'POST') {
throw new RequestException('You cannot use the POST method with SOAP 1.1.');
}

/**
* SOAP 1.2 only defines HTTP binding with POST and GET methods.
* @link https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L10309
*/
if ($this->soapVersion === self::SOAP12 && ! in_array($this->httpMethod, ['GET', 'POST'])) {
throw new RequestException('Invalid SOAP method specified for SOAP 1.2. Expeted: GET or POST.');
}
}

/**
* @return array
*/
private function prepareHeaders(): array
{
if ($this->soapVersion === self::SOAP11) {
return $this->prepareSoap11Headers();
}

return $this->prepareSoap12Headers();
}

/**
* @link https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383526
* @return array
*/
private function prepareSoap11Headers(): array
{
$headers = [];
$headers['Content-Length'] = (string) $this->soapMessage->getSize();
$headers['SOAPAction'] = $this->soapAction;
$headers['Content-Type'] = 'text/xml; charset="utf-8"';

return $headers;
}

/**
* SOAPAction header is removed in SOAP 1.2 and now expressed as a value of
* an (optional) "action" parameter of the "application/soap+xml" media type.
* @link https://www.w3.org/TR/soap12-part0/#L4697
* @return array
*/
private function prepareSoap12Headers(): array
{
$headers = [];
if ($this->httpMethod !== 'POST') {
$headers['Accept'] = 'application/soap+xml';

return $headers;
}

$headers['Content-Length'] = (string) $this->soapMessage->getSize();
$headers['Content-Type'] = 'application/soap+xml; charset="utf-8"'.'; action="'.$this->soapAction.'"';

return $headers;
}

/**
* @return StreamInterface
*/
private function prepareMessage(): StreamInterface
{
if ($this->httpMethod === 'POST') {
return $this->soapMessage;
}

return $this->streamFactory->createStream('');
}
}
Loading