From fe11f7d7827e8eaad9ca303483442d5a194ada6e Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 2 Jun 2021 22:55:43 +0100 Subject: [PATCH 1/8] Adds support for local headers --- src/Facades/Soap.php | 3 +- src/Header.php | 57 +++++++++++++++ src/Request/Request.php | 5 ++ src/Request/SoapClientRequest.php | 49 +++++++++++-- src/Soap.php | 5 ++ src/helpers.php | 8 ++- tests/Headers/HeadersTest.php | 116 ++++++++++++++++++++++++++++++ tests/Options/OptionsTest.php | 19 +++-- 8 files changed, 244 insertions(+), 18 deletions(-) create mode 100644 src/Header.php create mode 100644 tests/Headers/HeadersTest.php diff --git a/src/Facades/Soap.php b/src/Facades/Soap.php index babd053..8c7e777 100644 --- a/src/Facades/Soap.php +++ b/src/Facades/Soap.php @@ -4,8 +4,8 @@ namespace RicorocksDigitalAgency\Soap\Facades; -use Closure; use Illuminate\Support\Facades\Facade; +use RicorocksDigitalAgency\Soap\Header; use RicorocksDigitalAgency\Soap\Inclusion; use RicorocksDigitalAgency\Soap\OptionSet; use RicorocksDigitalAgency\Soap\Parameters\Node; @@ -16,6 +16,7 @@ * @package RicorocksDigitalAgency\Soap\Facades * * @method static Request to(string $endpoint) + * @method static Header header(?string $name = null, ?string $namespace = null, $data = null) * @method static Node node(array $attributes = []) * @method static Inclusion include(array $parameters) * @method static OptionSet options(array $options) diff --git a/src/Header.php b/src/Header.php new file mode 100644 index 0000000..7c931ce --- /dev/null +++ b/src/Header.php @@ -0,0 +1,57 @@ +name = $name; + $this->namespace = $namespace; + $this->data = $data; + } + + public function name(string $name): self + { + return tap($this, fn () => $this->name = $name); + } + + public function namespace(string $namespace): self + { + return tap($this, fn () => $this->namespace = $namespace); + } + + public function data($data): self + { + return tap($this, fn () => $this->data = $data); + } + + public function actor(string $actor): self + { + return tap($this, fn () => $this->actor = $actor); + } + + public function mustUnderstand(bool $mustUnderstand = true): self + { + return tap($this, fn () => $this->mustUnderstand = $mustUnderstand); + } + + public function toArray() + { + return [ + 'name' => $this->name, + 'namespace' => $this->namespace, + 'data' => $this->data, + 'mustUnderstand' => $this->mustUnderstand, + 'actor' => $this->actor, + ]; + } +} diff --git a/src/Request/Request.php b/src/Request/Request.php index 2556ca1..06d88f2 100644 --- a/src/Request/Request.php +++ b/src/Request/Request.php @@ -2,6 +2,7 @@ namespace RicorocksDigitalAgency\Soap\Request; +use RicorocksDigitalAgency\Soap\Header; use RicorocksDigitalAgency\Soap\Response\Response; interface Request @@ -43,4 +44,8 @@ public function withOptions(array $options): self; public function withBasicAuth($login, $password): self; public function withDigestAuth($login, $password): self; + + public function withHeaders(Header ...$headers): self; + + public function getHeaders(): array; } diff --git a/src/Request/SoapClientRequest.php b/src/Request/SoapClientRequest.php index dcde77e..a93ef18 100644 --- a/src/Request/SoapClientRequest.php +++ b/src/Request/SoapClientRequest.php @@ -2,10 +2,12 @@ namespace RicorocksDigitalAgency\Soap\Request; +use RicorocksDigitalAgency\Soap\Header; use RicorocksDigitalAgency\Soap\Parameters\Builder; use RicorocksDigitalAgency\Soap\Response\Response; use RicorocksDigitalAgency\Soap\Support\Tracing\Trace; use SoapClient; +use SoapHeader; class SoapClientRequest implements Request { @@ -17,6 +19,7 @@ class SoapClientRequest implements Request protected Response $response; protected $hooks = []; protected $options = []; + protected $headers = []; public function __construct(Builder $builder) { @@ -68,12 +71,35 @@ protected function makeRequest() protected function client() { - return $this->client ??= app( - SoapClient::class, - [ - 'wsdl' => $this->endpoint, - 'options' => $this->options - ] + return $this->client ??= $this->constructClient(); + } + + protected function constructClient() + { + $client = resolve(SoapClient::class, [ + 'wsdl' => $this->endpoint, + 'options' => $this->options + ]); + + $client->__setSoapHeaders($this->constructHeaders()); + + return $client; + } + + protected function constructHeaders() + { + if (empty($this->headers)) { + return; + } + + return array_map( + fn ($header) => resolve(SoapHeader::class, [ + 'namespace' => $header->namespace, + 'name' => $header->name, + 'data' => $header->data, + 'mustUnderstand' => $header->mustUnderstand, + 'actor' => $header->actor + ]), $this->headers ); } @@ -168,4 +194,15 @@ public function withOptions(array $options): Request $this->options = array_merge($this->getOptions(), $options); return $this; } + + public function withHeaders(Header ...$headers): Request + { + $this->headers = array_merge($this->getHeaders(), $headers); + return $this; + } + + public function getHeaders(): array + { + return $this->headers; + } } diff --git a/src/Soap.php b/src/Soap.php index a13c7a8..f352de7 100644 --- a/src/Soap.php +++ b/src/Soap.php @@ -42,6 +42,11 @@ public function node($attributes = []): Node return new Node($attributes); } + public function header(?string $name = null, ?string $namespace = null, $data = null): Header + { + return new Header($name, $namespace, $data); + } + public function include($parameters) { $inclusion = new Inclusion($parameters); diff --git a/src/helpers.php b/src/helpers.php index a9b0e74..ef8f708 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -6,4 +6,10 @@ function soap_node($attributes = []) { return Soap::node($attributes); } -} \ No newline at end of file +} + +if (!function_exists('soap_header')) { + function soap_header(?string $name = null, ?string $namespace = null, $data = null) { + return Soap::header($name, $namespace, $data); + } +} diff --git a/tests/Headers/HeadersTest.php b/tests/Headers/HeadersTest.php new file mode 100644 index 0000000..a6e92ef --- /dev/null +++ b/tests/Headers/HeadersTest.php @@ -0,0 +1,116 @@ +withHeaders(Soap::header('Auth', 'xml')->data(['foo' => 'bar'])) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']) + ]; + } + ); + } + + /** @test */ + public function multiple_headers_can_be_defined_in_the_same_method() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(...[ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']), + ]) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']), + ]; + } + ); + } + + /** @test */ + public function multiple_headers_can_be_defined_in_the_multiple_methods() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(Soap::header('Auth', 'xml')->data(['foo' => 'bar'])) + ->withHeaders(Soap::header('Brand', 'xml')->data(['hello' => 'world'])) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']), + ]; + } + ); + } + + /** @test */ + public function a_header_can_be_created_without_any_parameters_and_be_composed_fluently() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders( + Soap::header() + ->name('Auth') + ->namespace('xml') + ->data(['foo' => 'bar']) + ->mustUnderstand() + ->actor('this.test') + ) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml') + ->data(['foo' => 'bar']) + ->mustUnderstand() + ->actor('this.test') + ]; + } + ); + } + + /** @test */ + public function a_header_can_be_created_with_the_helper_method() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(soap_header('Auth', 'xml', ['foo' => 'bar'])) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']) + ]; + } + ); + } +} diff --git a/tests/Options/OptionsTest.php b/tests/Options/OptionsTest.php index b5e0b9e..e87f2ab 100644 --- a/tests/Options/OptionsTest.php +++ b/tests/Options/OptionsTest.php @@ -10,7 +10,6 @@ class OptionsTest extends TestCase { - /** @test */ public function options_can_be_set() { @@ -23,8 +22,8 @@ public function options_can_be_set() Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getOptions() == [ - 'compression' => SOAP_COMPRESSION_GZIP, - ]; + 'compression' => SOAP_COMPRESSION_GZIP, + ]; } ); } @@ -42,11 +41,11 @@ public function it_merges_with_other_options() Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getOptions() == [ - 'authentication' => SOAP_AUTHENTICATION_BASIC, - 'login' => 'foo', - 'password' => 'bar', - 'compression' => SOAP_COMPRESSION_GZIP, - ]; + 'authentication' => SOAP_AUTHENTICATION_BASIC, + 'login' => 'foo', + 'password' => 'bar', + 'compression' => SOAP_COMPRESSION_GZIP, + ]; } ); } @@ -64,8 +63,8 @@ public function it_overrides_previous_values() Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getOptions() == [ - 'compression' => SOAP_COMPRESSION_GZIP, - ]; + 'compression' => SOAP_COMPRESSION_GZIP, + ]; } ); } From 7440e272ca933f985af4b08821dc3d576b2f5ceb Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 2 Jun 2021 23:11:00 +0100 Subject: [PATCH 2/8] Adds support for global headers --- src/Facades/Soap.php | 2 + src/HeaderSet.php | 20 ++++++++ src/Soap.php | 19 +++++++ tests/Headers/GlobalHeadersTest.php | 77 +++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 src/HeaderSet.php create mode 100644 tests/Headers/GlobalHeadersTest.php diff --git a/src/Facades/Soap.php b/src/Facades/Soap.php index 8c7e777..e2e26de 100644 --- a/src/Facades/Soap.php +++ b/src/Facades/Soap.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Facade; use RicorocksDigitalAgency\Soap\Header; +use RicorocksDigitalAgency\Soap\HeaderSet; use RicorocksDigitalAgency\Soap\Inclusion; use RicorocksDigitalAgency\Soap\OptionSet; use RicorocksDigitalAgency\Soap\Parameters\Node; @@ -17,6 +18,7 @@ * * @method static Request to(string $endpoint) * @method static Header header(?string $name = null, ?string $namespace = null, $data = null) + * @method static HeaderSet headers(Header ...$headers) * @method static Node node(array $attributes = []) * @method static Inclusion include(array $parameters) * @method static OptionSet options(array $options) diff --git a/src/HeaderSet.php b/src/HeaderSet.php new file mode 100644 index 0000000..efb55dc --- /dev/null +++ b/src/HeaderSet.php @@ -0,0 +1,20 @@ +headers = $headers; + } + + public function getHeaders() + { + return $this->headers; + } +} diff --git a/src/Soap.php b/src/Soap.php index f352de7..b7c69c8 100644 --- a/src/Soap.php +++ b/src/Soap.php @@ -16,6 +16,7 @@ class Soap } protected Fakery $fakery; + protected $headerSets = []; protected $inclusions = []; protected $optionsSets = []; protected $globalHooks = []; @@ -24,6 +25,7 @@ public function __construct(Fakery $fakery) { $this->fakery = $fakery; $this->beforeRequesting(fn($request) => $request->fakeUsing($this->fakery->mockResponseIfAvailable($request))); + $this->beforeRequesting(fn($request) => $this->mergeHeadersFor($request)); $this->beforeRequesting(fn($request) => $this->mergeInclusionsFor($request)); $this->beforeRequesting(fn($request) => $this->mergeOptionsFor($request)); $this->afterRequesting(fn($request, $response) => $this->record($request, $response)); @@ -61,6 +63,23 @@ public function options(array $options) return $options; } + public function headers(Header ...$headers) + { + $headers = new HeaderSet(...$headers); + $this->headerSets[] = $headers; + return $headers; + } + + protected function mergeHeadersFor(Request $request) + { + collect($this->headerSets) + ->filter + ->matches($request->getEndpoint(), $request->getMethod()) + ->flatMap + ->getHeaders() + ->pipe(fn($headers) => $request->withHeaders(...$headers)); + } + protected function mergeInclusionsFor(Request $request) { collect($this->inclusions) diff --git a/tests/Headers/GlobalHeadersTest.php b/tests/Headers/GlobalHeadersTest.php new file mode 100644 index 0000000..9d23c78 --- /dev/null +++ b/tests/Headers/GlobalHeadersTest.php @@ -0,0 +1,77 @@ + 'bar'])); + Soap::to(static::EXAMPLE_SOAP_ENDPOINT)->call('Add', (['intB' => 25])); + + Soap::assertSent(function($request) { + return $request->getHeaders() == [ + soap_header('Auth', 'xml', ['foo' => 'bar']) + ]; + }); + } + + /** @test */ + public function it_can_scope_headers_based_on_the_endpoint() + { + Soap::fake(); + + Soap::headers(soap_header('Brand', 'xmls', ['hello' => 'world']))->for('https://foo.bar'); + Soap::headers(soap_header('Auth', 'xml', ['foo' => 'bar']))->for(static::EXAMPLE_SOAP_ENDPOINT); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT)->call('Add', (['intB' => 25])); + + Soap::assertSent(function($request) { + return $request->getHeaders() == [ + soap_header('Auth', 'xml', ['foo' => 'bar']) + ]; + }); + } + + /** @test */ + public function it_can_scope_headers_based_on_the_endpoint_and_method() + { + Soap::fake(); + + Soap::headers(soap_header('Brand', 'xmls', ['hello' => 'world']))->for(static::EXAMPLE_SOAP_ENDPOINT, 'Add'); + Soap::headers(soap_header('Auth', 'xml', ['foo' => 'bar']))->for(static::EXAMPLE_SOAP_ENDPOINT, 'Subtract'); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT)->call('Add', (['intB' => 25])); + + Soap::assertSent(function($request) { + return $request->getHeaders() == [ + soap_header('Brand', 'xmls', ['hello' => 'world']) + ]; + }); + } + + /** @test */ + public function the_global_headers_are_merged_with_local_headers() + { + Soap::fake(); + + Soap::headers(soap_header('Brand', 'xmls', ['hello' => 'world'])); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(soap_header('Auth', 'xml', ['foo' => 'bar'])) + ->call('Add', (['intB' => 25])); + + Soap::assertSent(function($request) { + return $request->getHeaders() == [ + soap_header('Auth', 'xml', ['foo' => 'bar']), + soap_header('Brand', 'xmls', ['hello' => 'world']) + ]; + }); + } +} From 6d45ec08714e4526155ded2d7fbc5b3f09a54d4e Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 2 Jun 2021 23:30:28 +0100 Subject: [PATCH 3/8] Adds headers to tracing - improves tracing --- src/Request/SoapClientRequest.php | 12 +++-------- src/Support/Tracing/Trace.php | 17 +++++++++------ tests/Mocks/MockSoapClient.php | 12 ++++++++++- tests/Tracing/SoapTracingTest.php | 6 ++++++ tests/Tracing/TraceTest.php | 35 +++++++++---------------------- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/Request/SoapClientRequest.php b/src/Request/SoapClientRequest.php index a93ef18..277530d 100644 --- a/src/Request/SoapClientRequest.php +++ b/src/Request/SoapClientRequest.php @@ -60,7 +60,9 @@ protected function getRealResponse() { return tap( Response::new($this->makeRequest()), - fn($response) => data_get($this->options, 'trace') ? $this->addTrace($response) : $response + fn($response) => data_get($this->options, 'trace') + ? $response->setTrace(Trace::client($this->client())) + : $response ); } @@ -113,14 +115,6 @@ public function getBody() return $this->body; } - protected function addTrace($response) - { - return $response->setTrace( - Trace::thisXmlRequest($this->client()->__getLastRequest()) - ->thisXmlResponse($this->client()->__getLastResponse()) - ); - } - public function functions(): array { return $this->client()->__getFunctions(); diff --git a/src/Support/Tracing/Trace.php b/src/Support/Tracing/Trace.php index 11907ba..ed7632b 100644 --- a/src/Support/Tracing/Trace.php +++ b/src/Support/Tracing/Trace.php @@ -4,16 +4,21 @@ class Trace { + public $client; public $xmlRequest; public $xmlResponse; + public $requestHeaders; + public $responseHeaders; - public static function thisXmlRequest($xml): self + public static function client($client): self { - return tap(new static, fn($instance) => $instance->xmlRequest = $xml); - } + $trace = new static; + $trace->client = $client; + $trace->xmlRequest = $client->__getLastRequest(); + $trace->xmlResponse = $client->__getLastResponse(); + $trace->requestHeaders = $client->__getLastRequestHeaders(); + $trace->responseHeaders = $client->__getLastResponseHeaders(); - public function thisXmlResponse($xml): self - { - return tap($this, fn($self) => $self->xmlResponse = $xml); + return $trace; } } diff --git a/tests/Mocks/MockSoapClient.php b/tests/Mocks/MockSoapClient.php index 6b7c850..cadf48d 100644 --- a/tests/Mocks/MockSoapClient.php +++ b/tests/Mocks/MockSoapClient.php @@ -46,6 +46,11 @@ public function __getLastRequest() public function __getLastRequestHeaders() { + if (!$this->shouldTrace) { + return null; + } + + return 'Hello World'; } public function __getLastResponse() @@ -59,6 +64,11 @@ public function __getLastResponse() public function __getLastResponseHeaders() { + if (!$this->shouldTrace) { + return null; + } + + return 'Foo Bar'; } public function __getTypes() @@ -91,4 +101,4 @@ public function SoapClient(mixed $wsdl, array $options = []) return new static($wsdl, $options); } -} \ No newline at end of file +} diff --git a/tests/Tracing/SoapTracingTest.php b/tests/Tracing/SoapTracingTest.php index 45400a3..a84e9a5 100644 --- a/tests/Tracing/SoapTracingTest.php +++ b/tests/Tracing/SoapTracingTest.php @@ -23,6 +23,8 @@ public function a_trace_can_be_requested_at_time_of_request() $this->assertEquals('World', $response->trace()->xmlRequest); $this->assertEquals('Success!', $response->trace()->xmlResponse); + $this->assertEquals('Hello World', $response->trace()->requestHeaders); + $this->assertEquals('Foo Bar', $response->trace()->responseHeaders); } /** @test */ @@ -35,6 +37,8 @@ public function a_trace_can_be_requested_globally() $this->assertEquals('World', $response->trace()->xmlRequest); $this->assertEquals('Success!', $response->trace()->xmlResponse); + $this->assertEquals('Hello World', $response->trace()->requestHeaders); + $this->assertEquals('Foo Bar', $response->trace()->responseHeaders); } /** @test */ @@ -45,5 +49,7 @@ public function by_default_the_trace_has_no_content_on_the_response() $this->assertEmpty($response->trace()->xmlRequest); $this->assertEmpty($response->trace()->xmlResponse); + $this->assertEmpty($response->trace()->requestHeaders); + $this->assertEmpty($response->trace()->responseHeaders); } } diff --git a/tests/Tracing/TraceTest.php b/tests/Tracing/TraceTest.php index 636439a..869a1ba 100644 --- a/tests/Tracing/TraceTest.php +++ b/tests/Tracing/TraceTest.php @@ -4,37 +4,19 @@ use RicorocksDigitalAgency\Soap\Support\Tracing\Trace; use RicorocksDigitalAgency\Soap\Tests\TestCase; +use SoapClient; class TraceTest extends TestCase { /** @test */ - public function the_trace_object_has_a_static_thisXmlRequest_method() + public function the_trace_object_has_a_static_client_method() { - $xml = 'World'; + $trace = Trace::client($client = new SoapClient(static::EXAMPLE_SOAP_ENDPOINT)); - $trace = Trace::thisXmlRequest($xml); - - $this->assertSame($xml, $trace->xmlRequest); - } - - /** @test */ - public function the_trace_object_has_a_thisXmlResponse_method() - { - $request = 'World'; - $response = 'Success!'; - - $trace = Trace::thisXmlRequest($request)->thisXmlResponse($response); - - $this->assertSame($response, $trace->xmlResponse); - } - - /** @test */ - public function a_null_trace_returns_gracefully() - { - $trace = Trace::thisXmlRequest(null)->thisXmlResponse(null); - - $this->assertNull($trace->xmlRequest); - $this->assertNull($trace->xmlResponse); + $this->assertSame($client->__getLastRequest(), $trace->xmlRequest); + $this->assertSame($client->__getLastResponse(), $trace->xmlResponse); + $this->assertSame($client->__getLastRequestHeaders(), $trace->requestHeaders); + $this->assertSame($client->__getLastResponseHeaders(), $trace->responseHeaders); } /** @test */ @@ -42,7 +24,10 @@ public function a_fresh_trace_returns_gracefully() { $trace = new Trace; + $this->assertNull($trace->client); $this->assertNull($trace->xmlRequest); $this->assertNull($trace->xmlResponse); + $this->assertNull($trace->requestHeaders); + $this->assertNull($trace->responseHeaders); } } From d2d883643c0f9f60057582638d5f0365f58b3057 Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 2 Jun 2021 23:47:52 +0100 Subject: [PATCH 4/8] Support for SoapVars in headers --- src/Request/SoapClientRequest.php | 7 +++---- src/Soap.php | 12 ++++++------ tests/Headers/HeadersTest.php | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Request/SoapClientRequest.php b/src/Request/SoapClientRequest.php index 277530d..a6a05af 100644 --- a/src/Request/SoapClientRequest.php +++ b/src/Request/SoapClientRequest.php @@ -83,9 +83,7 @@ protected function constructClient() 'options' => $this->options ]); - $client->__setSoapHeaders($this->constructHeaders()); - - return $client; + return tap($client, fn ($client) => $client->__setSoapHeaders($this->constructHeaders())); } protected function constructHeaders() @@ -101,7 +99,8 @@ protected function constructHeaders() 'data' => $header->data, 'mustUnderstand' => $header->mustUnderstand, 'actor' => $header->actor - ]), $this->headers + ]), + $this->headers ); } diff --git a/src/Soap.php b/src/Soap.php index b7c69c8..117ce6c 100644 --- a/src/Soap.php +++ b/src/Soap.php @@ -24,16 +24,16 @@ class Soap public function __construct(Fakery $fakery) { $this->fakery = $fakery; - $this->beforeRequesting(fn($request) => $request->fakeUsing($this->fakery->mockResponseIfAvailable($request))); - $this->beforeRequesting(fn($request) => $this->mergeHeadersFor($request)); - $this->beforeRequesting(fn($request) => $this->mergeInclusionsFor($request)); - $this->beforeRequesting(fn($request) => $this->mergeOptionsFor($request)); - $this->afterRequesting(fn($request, $response) => $this->record($request, $response)); + $this->beforeRequesting(fn($request) => $request->fakeUsing($this->fakery->mockResponseIfAvailable($request))) + ->beforeRequesting(fn($request) => $this->mergeHeadersFor($request)) + ->beforeRequesting(fn($request) => $this->mergeInclusionsFor($request)) + ->beforeRequesting(fn($request) => $this->mergeOptionsFor($request)) + ->afterRequesting(fn($request, $response) => $this->record($request, $response)); } public function to(string $endpoint) { - return app(Request::class) + return resolve(Request::class) ->beforeRequesting(...$this->globalHooks['beforeRequesting']) ->afterRequesting(...$this->globalHooks['afterRequesting']) ->to($endpoint); diff --git a/tests/Headers/HeadersTest.php b/tests/Headers/HeadersTest.php index a6e92ef..6159fc4 100644 --- a/tests/Headers/HeadersTest.php +++ b/tests/Headers/HeadersTest.php @@ -5,6 +5,7 @@ use RicorocksDigitalAgency\Soap\Facades\Soap; use RicorocksDigitalAgency\Soap\Request\SoapClientRequest; use RicorocksDigitalAgency\Soap\Tests\TestCase; +use SoapVar; class HeadersTest extends TestCase { @@ -113,4 +114,22 @@ function (SoapClientRequest $request, $response) { } ); } + + /** @test */ + public function a_header_can_be_set_using_a_SoapVar() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(soap_header('Auth', 'xml', new SoapVar(['foo' => 'bar'], null))) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(new SoapVar(['foo' => 'bar'], null)) + ]; + } + ); + } } From e659bb31edd28fa9aa38b4221f6ea055d1f924e6 Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 3 Jun 2021 00:11:43 +0100 Subject: [PATCH 5/8] Adds documentation for headers --- README.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e28d549..2540b4a 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,16 @@ A Laravel SOAP client that provides a clean interface for handling requests and - [Installation](#installation) - [Using Soap](#using-soap) - [Features/API](#features/api) + * [Headers](#headers) * [To](#to) * [Functions](#functions) * [Call](#call) * [Parameters](#parameters) * [Nodes](#nodes) -- [Options](#options) - * [Tracing](#tracing) - * [Authentication](#authentication) - * [Global Options](#global-options) + * [Options](#options) + * [Tracing](#tracing) + * [Authentication](#authentication) + * [Global Options](#global-options) - [Hooks](#hooks) - [Faking](#faking) - [Configuration](#configuration) @@ -45,6 +46,62 @@ Soap::to() ## Features/API +### Headers + +You can set the headers for each soap request that will be passed to the Soap Client using the `withHeaders` method. + +```php +Soap::to('...')->withHeaders(...$headers)->call('...'); +``` + +Each header should be a `Header` instance, which provides a fluent interface for constructing a new [PHP Soap Header](https://www.php.net/manual/en/soapheader.construct.php) and can be composed as follows: +```php +$header = Soap::header() + ->name('Authentication') + ->namespace('test.com') + ->data([ + 'user' => '...', + 'password' => '...' + ]) + ->mustUnderstand() + ->author('foo.co.uk') +``` +This can also be expressed as: +```php +$header = Soap::header('Authentication', 'test.com', [ + 'user' => '...', + 'password' => '...' + ]) + ->mustUnderstand() + ->author('foo.co.uk') +``` +Plus, the `soap_header` helper method can be used: +```php +$header = soap_header('Authentication', 'test.com') + ->data([ + 'user' => '...', + 'password' => '...' + ]) +``` +> The `data` for the header can either be an array or a `SoapVar`, as per the `SoapHeader` constructor +#### Global Headers +Soap allows you to set headers that should be included for every request: +```php +Soap::headers(...$headers) +``` +Again, each header should be an instance of `Header`. + +You may also want to include headers on every request, but only for a certain endpoint or action: + +```php +// Only requests to this endpoint will include these headers +Soap::headers(soap_header('Auth', 'test.com'))->for('https://api.example.com'); + +// Only requests to this endpoint and the method Customers will include these headers +Soap::headers(soap_header('Brand', 'test.com'))->for('https://api.example.com', 'Customers'); +``` + +These calls are usually placed in the `boot` method of one of your application's Service Providers. ### To The endpoint to be accessed @@ -151,7 +208,7 @@ Now, just by adding or removing a body to the `soap_node()` the outputted array A node can be made with either the Facade `Soap::node()` or the helper method `soap_node()`. -## Options +### Options You can set custom options for each soap request that will be passed to the Soap Client using the `withOptions` method. @@ -159,13 +216,13 @@ You can set custom options for each soap request that will be passed to the Soap Soap::to('...')->withOptions(['soap_version' => SOAP_1_2])->call('...'); ``` -See [https://www.php.net/manual/en/soapclient.construct.php](https://www.php.net/manual/en/soapclient.construct.php) +> See [https://www.php.net/manual/en/soapclient.construct.php](https://www.php.net/manual/en/soapclient.construct.php) for more details and available options. Soap also provides a number of methods that add syntactical sugar to the most commonly used options, which are detailed below. -### Tracing +#### Tracing Soap allows you to easily trace your interactions with the SOAP endpoint being accessed. To trace all requests, set the following in the register method of your `ServiceProvider`: @@ -173,7 +230,11 @@ To trace all requests, set the following in the register method of your `Service ```php Soap::trace() ``` -Now, all `Response` objects returned will have a `Trace` object attached, accessible via `$response->getTrace()`. This has two properties `xmlRequest` and `xmlResponse` - storing the raw XML values for each. +Now, all `Response` objects returned will have a `Trace` object attached, accessible via `$response->getTrace()`. This has four properties which are wrappers for the respective methods found on the `SoapClient`: +- `xmlRequest` (`__getLastRequest`) +- `xmlResponse` (`__getLastResponse`) +- `requestHeaders` (`__getLastRequestHeaders`) +- `responseHeaders` (`__getLastResponseHeaders`) Tracing can also be declared locally: ```php @@ -183,7 +244,7 @@ Now, just this `Response` will have a valid `Trace`. Tracing is null safe. If `$response->getTrace()` is called when a `Trace` hasn't been set, a new `Trace` is returned. This `Trace`'s properties will all return `null`. -### Authentication +#### Authentication You can authenticate using Basic or Digest by calling `withBasicAuth` and `withDigestAuth` respectively. @@ -192,7 +253,7 @@ Soap::to('...')->withBasicAuth('username', 'password')->call('...'); Soap::to('...')->withDigestAuth('username', 'password')->call('...'); ``` -### Global Options +#### Global Options Sometimes, you may wish to include the same set of options on every SOAP request. You can do that using the `options` method on the `Soap` facade: From 5757b381c88ded2a68a8a7334a0b71d3a2ab2328 Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 3 Jun 2021 00:15:14 +0100 Subject: [PATCH 6/8] Update for test --- tests/Headers/HeadersTest.php | 46 ++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/Headers/HeadersTest.php b/tests/Headers/HeadersTest.php index 6159fc4..9ff6511 100644 --- a/tests/Headers/HeadersTest.php +++ b/tests/Headers/HeadersTest.php @@ -32,10 +32,32 @@ public function multiple_headers_can_be_defined_in_the_same_method() { Soap::fake(); + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders( + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']) + ) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']), + ]; + } + ); + } + + /** @test */ + public function multiple_headers_can_be_defined_with_an_array_in_the_same_method() + { + Soap::fake(); + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) ->withHeaders(...[ Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']) ]) ->call('Add', ['intA' => 10, 'intB' => 25]); @@ -49,6 +71,28 @@ function (SoapClientRequest $request, $response) { ); } + /** @test */ + public function multiple_headers_can_be_defined_with_a_collection_in_the_same_method() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(...collect([ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']) + ])) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'xml')->data(['foo' => 'bar']), + Soap::header('Brand', 'xml')->data(['hello' => 'world']), + ]; + } + ); + } + /** @test */ public function multiple_headers_can_be_defined_in_the_multiple_methods() { From 57dcbefdfc5935b640c1501d757faae639a33904 Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 3 Jun 2021 08:39:57 +0100 Subject: [PATCH 7/8] Updates for optional parameters --- README.md | 1 + src/Facades/Soap.php | 2 +- src/Header.php | 10 +++-- src/Ray/SoapWatcher.php | 8 ++++ src/helpers.php | 4 +- tests/Headers/GlobalHeadersTest.php | 24 +++++----- tests/Headers/HeadersTest.php | 68 +++++++++++++++++++---------- 7 files changed, 74 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 2540b4a..880cce8 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ A Laravel SOAP client that provides a clean interface for handling requests and - [Using Soap](#using-soap) - [Features/API](#features/api) * [Headers](#headers) + * [Global Headers](#global-headers) * [To](#to) * [Functions](#functions) * [Call](#call) diff --git a/src/Facades/Soap.php b/src/Facades/Soap.php index e2e26de..cb7b82c 100644 --- a/src/Facades/Soap.php +++ b/src/Facades/Soap.php @@ -17,7 +17,7 @@ * @package RicorocksDigitalAgency\Soap\Facades * * @method static Request to(string $endpoint) - * @method static Header header(?string $name = null, ?string $namespace = null, $data = null) + * @method static Header header(?string $name = null, ?string $namespace = null, $data = null, bool $mustUnderstand = false, ?string $actor = null) * @method static HeaderSet headers(Header ...$headers) * @method static Node node(array $attributes = []) * @method static Inclusion include(array $parameters) diff --git a/src/Header.php b/src/Header.php index 7c931ce..33b54d7 100644 --- a/src/Header.php +++ b/src/Header.php @@ -10,13 +10,15 @@ class Header implements Arrayable public $namespace; public $data; public $actor; - public $mustUnderstand = false; + public $mustUnderstand; - public function __construct(?string $name = null, ?string $namespace = null, $data = null) + public function __construct(?string $name = null, ?string $namespace = null, $data = null, bool $mustUnderstand = false, ?string $actor = null) { $this->name = $name; $this->namespace = $namespace; $this->data = $data; + $this->mustUnderstand = $mustUnderstand; + $this->actor = $actor; } public function name(string $name): self @@ -29,12 +31,12 @@ public function namespace(string $namespace): self return tap($this, fn () => $this->namespace = $namespace); } - public function data($data): self + public function data($data = null): self { return tap($this, fn () => $this->data = $data); } - public function actor(string $actor): self + public function actor(?string $actor = null): self { return tap($this, fn () => $this->actor = $actor); } diff --git a/src/Ray/SoapWatcher.php b/src/Ray/SoapWatcher.php index 792457b..49e9bbc 100644 --- a/src/Ray/SoapWatcher.php +++ b/src/Ray/SoapWatcher.php @@ -35,10 +35,18 @@ protected function handleRequest(Request $request, Response $response) [ 'Endpoint' => $request->getEndpoint(), 'Method' => $request->getMethod(), + 'Headers' => $this->headers($request), 'Request' => $request->getBody(), 'Response' => $response->response, ], "SOAP" ); } + + protected function headers(Request $request) + { + return $request->getHeaders() + ? collect($request->getHeaders())->map->toArray()->toArray() + : []; + } } diff --git a/src/helpers.php b/src/helpers.php index ef8f708..8838801 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -9,7 +9,7 @@ function soap_node($attributes = []) { } if (!function_exists('soap_header')) { - function soap_header(?string $name = null, ?string $namespace = null, $data = null) { - return Soap::header($name, $namespace, $data); + function soap_header(?string $name = null, ?string $namespace = null, $data = null, bool $mustUnderstand = false, ?string $actor = null) { + return Soap::header($name, $namespace, $data, $mustUnderstand, $actor); } } diff --git a/tests/Headers/GlobalHeadersTest.php b/tests/Headers/GlobalHeadersTest.php index 9d23c78..624f0ff 100644 --- a/tests/Headers/GlobalHeadersTest.php +++ b/tests/Headers/GlobalHeadersTest.php @@ -12,12 +12,12 @@ public function it_can_include_global_headers_for_every_request() { Soap::fake(); - Soap::headers(soap_header('Auth', 'xml', ['foo' => 'bar'])); + Soap::headers(soap_header('Auth', 'test.com', ['foo' => 'bar'])); Soap::to(static::EXAMPLE_SOAP_ENDPOINT)->call('Add', (['intB' => 25])); Soap::assertSent(function($request) { return $request->getHeaders() == [ - soap_header('Auth', 'xml', ['foo' => 'bar']) + soap_header('Auth', 'test.com', ['foo' => 'bar']) ]; }); } @@ -27,14 +27,14 @@ public function it_can_scope_headers_based_on_the_endpoint() { Soap::fake(); - Soap::headers(soap_header('Brand', 'xmls', ['hello' => 'world']))->for('https://foo.bar'); - Soap::headers(soap_header('Auth', 'xml', ['foo' => 'bar']))->for(static::EXAMPLE_SOAP_ENDPOINT); + Soap::headers(soap_header('Brand', 'test.coms', ['hello' => 'world']))->for('https://foo.bar'); + Soap::headers(soap_header('Auth', 'test.com', ['foo' => 'bar']))->for(static::EXAMPLE_SOAP_ENDPOINT); Soap::to(static::EXAMPLE_SOAP_ENDPOINT)->call('Add', (['intB' => 25])); Soap::assertSent(function($request) { return $request->getHeaders() == [ - soap_header('Auth', 'xml', ['foo' => 'bar']) + soap_header('Auth', 'test.com', ['foo' => 'bar']) ]; }); } @@ -44,14 +44,14 @@ public function it_can_scope_headers_based_on_the_endpoint_and_method() { Soap::fake(); - Soap::headers(soap_header('Brand', 'xmls', ['hello' => 'world']))->for(static::EXAMPLE_SOAP_ENDPOINT, 'Add'); - Soap::headers(soap_header('Auth', 'xml', ['foo' => 'bar']))->for(static::EXAMPLE_SOAP_ENDPOINT, 'Subtract'); + Soap::headers(soap_header('Brand', 'test.coms', ['hello' => 'world']))->for(static::EXAMPLE_SOAP_ENDPOINT, 'Add'); + Soap::headers(soap_header('Auth', 'test.com', ['foo' => 'bar']))->for(static::EXAMPLE_SOAP_ENDPOINT, 'Subtract'); Soap::to(static::EXAMPLE_SOAP_ENDPOINT)->call('Add', (['intB' => 25])); Soap::assertSent(function($request) { return $request->getHeaders() == [ - soap_header('Brand', 'xmls', ['hello' => 'world']) + soap_header('Brand', 'test.coms', ['hello' => 'world']) ]; }); } @@ -61,16 +61,16 @@ public function the_global_headers_are_merged_with_local_headers() { Soap::fake(); - Soap::headers(soap_header('Brand', 'xmls', ['hello' => 'world'])); + Soap::headers(soap_header('Brand', 'test.coms', ['hello' => 'world'])); Soap::to(static::EXAMPLE_SOAP_ENDPOINT) - ->withHeaders(soap_header('Auth', 'xml', ['foo' => 'bar'])) + ->withHeaders(soap_header('Auth', 'test.com', ['foo' => 'bar'])) ->call('Add', (['intB' => 25])); Soap::assertSent(function($request) { return $request->getHeaders() == [ - soap_header('Auth', 'xml', ['foo' => 'bar']), - soap_header('Brand', 'xmls', ['hello' => 'world']) + soap_header('Auth', 'test.com', ['foo' => 'bar']), + soap_header('Brand', 'test.coms', ['hello' => 'world']) ]; }); } diff --git a/tests/Headers/HeadersTest.php b/tests/Headers/HeadersTest.php index 9ff6511..405df29 100644 --- a/tests/Headers/HeadersTest.php +++ b/tests/Headers/HeadersTest.php @@ -15,13 +15,13 @@ public function headers_can_be_set() Soap::fake(); Soap::to(static::EXAMPLE_SOAP_ENDPOINT) - ->withHeaders(Soap::header('Auth', 'xml')->data(['foo' => 'bar'])) + ->withHeaders(Soap::header('Auth', 'test.com')->data(['foo' => 'bar'])) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']) + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']) ]; } ); @@ -34,16 +34,16 @@ public function multiple_headers_can_be_defined_in_the_same_method() Soap::to(static::EXAMPLE_SOAP_ENDPOINT) ->withHeaders( - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']) + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']) ) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']), + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']), ]; } ); @@ -56,16 +56,16 @@ public function multiple_headers_can_be_defined_with_an_array_in_the_same_method Soap::to(static::EXAMPLE_SOAP_ENDPOINT) ->withHeaders(...[ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']) + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']) ]) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']), + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']), ]; } ); @@ -78,16 +78,16 @@ public function multiple_headers_can_be_defined_with_a_collection_in_the_same_me Soap::to(static::EXAMPLE_SOAP_ENDPOINT) ->withHeaders(...collect([ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']) + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']) ])) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']), + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']), ]; } ); @@ -99,15 +99,15 @@ public function multiple_headers_can_be_defined_in_the_multiple_methods() Soap::fake(); Soap::to(static::EXAMPLE_SOAP_ENDPOINT) - ->withHeaders(Soap::header('Auth', 'xml')->data(['foo' => 'bar'])) - ->withHeaders(Soap::header('Brand', 'xml')->data(['hello' => 'world'])) + ->withHeaders(Soap::header('Auth', 'test.com')->data(['foo' => 'bar'])) + ->withHeaders(Soap::header('Brand', 'test.com')->data(['hello' => 'world'])) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']), - Soap::header('Brand', 'xml')->data(['hello' => 'world']), + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']), + Soap::header('Brand', 'test.com')->data(['hello' => 'world']), ]; } ); @@ -122,7 +122,7 @@ public function a_header_can_be_created_without_any_parameters_and_be_composed_f ->withHeaders( Soap::header() ->name('Auth') - ->namespace('xml') + ->namespace('test.com') ->data(['foo' => 'bar']) ->mustUnderstand() ->actor('this.test') @@ -132,7 +132,7 @@ public function a_header_can_be_created_without_any_parameters_and_be_composed_f Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml') + Soap::header('Auth', 'test.com') ->data(['foo' => 'bar']) ->mustUnderstand() ->actor('this.test') @@ -147,13 +147,13 @@ public function a_header_can_be_created_with_the_helper_method() Soap::fake(); Soap::to(static::EXAMPLE_SOAP_ENDPOINT) - ->withHeaders(soap_header('Auth', 'xml', ['foo' => 'bar'])) + ->withHeaders(soap_header('Auth', 'test.com', ['foo' => 'bar'])) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(['foo' => 'bar']) + Soap::header('Auth', 'test.com')->data(['foo' => 'bar']) ]; } ); @@ -165,13 +165,33 @@ public function a_header_can_be_set_using_a_SoapVar() Soap::fake(); Soap::to(static::EXAMPLE_SOAP_ENDPOINT) - ->withHeaders(soap_header('Auth', 'xml', new SoapVar(['foo' => 'bar'], null))) + ->withHeaders(soap_header('Auth', 'test.com', new SoapVar(['foo' => 'bar'], null))) ->call('Add', ['intA' => 10, 'intB' => 25]); Soap::assertSent( function (SoapClientRequest $request, $response) { return $request->getHeaders() == [ - Soap::header('Auth', 'xml')->data(new SoapVar(['foo' => 'bar'], null)) + Soap::header('Auth', 'test.com')->data(new SoapVar(['foo' => 'bar'], null)) + ]; + } + ); + } + + /** @test */ + public function the_optional_parameters_of_the_SoapHeader_are_optional() + { + Soap::fake(); + + Soap::to(static::EXAMPLE_SOAP_ENDPOINT) + ->withHeaders(Soap::header('Auth', 'test.com')->data(null)->actor(null)) + ->withHeaders(soap_header('Brand', 'test.com', null, false, null)) + ->call('Add', ['intA' => 10, 'intB' => 25]); + + Soap::assertSent( + function (SoapClientRequest $request, $response) { + return $request->getHeaders() == [ + Soap::header('Auth', 'test.com', null, false, null), + Soap::header('Brand', 'test.com', null, false, null), ]; } ); From a36497a82158ef65e7ab55156f676087d69fbe5b Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 3 Jun 2021 13:50:15 +0100 Subject: [PATCH 8/8] Updates readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 880cce8..590ca56 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ $header = Soap::header() 'password' => '...' ]) ->mustUnderstand() - ->author('foo.co.uk') + ->actor('foo.co.uk') ``` This can also be expressed as: ```php @@ -74,7 +74,7 @@ $header = Soap::header('Authentication', 'test.com', [ 'password' => '...' ]) ->mustUnderstand() - ->author('foo.co.uk') + ->actor('foo.co.uk') ``` Plus, the `soap_header` helper method can be used: ```php