diff --git a/README.md b/README.md index 4f0da48..4252732 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,38 @@ Makes it possible to build the content of a `soap:Header` element. ```php use Soap\Xml\Builder\SoapHeaders; -use Soap\Xml\Manipulator\PrependSoapHeaders;use VeeWee\Xml\Dom\Document; -use function VeeWee\Xml\Dom\Builder\children; +use Soap\Xml\Builder\SoapHeader; +use Soap\Xml\Builder\Header\Actor; +use Soap\Xml\Builder\Header\MustUnderstand; +use Soap\Xml\Manipulator\PrependSoapHeaders; +use VeeWee\Xml\Dom\Document; +use function VeeWee\Xml\Dom\Builder\namespaced_element; use function VeeWee\Xml\Dom\Builder\element; use function VeeWee\Xml\Dom\Builder\value; $doc = Document::fromXmlString($xml); $builder = new SoapHeaders( - children( - element('user', value('josbos')), - element('password', value('topsecret')) - ) + new SoapHeader( + $targetNamespace, + 'Auth', + children( + namespaced_element($targetNamespace, 'user', value('josbos')), + namespaced_element($targetNamespace, 'password', value('topsecret')) + ), + // Optionally, you can provide additional configurators for setting + // SOAP-ENV specific attributes: + Actor::next(), + new MustUnderstand() + ), + $header2, + $header3 ); -$header = $doc->build($builder)[0]; +$headers = $doc->build($builder); // You can prepend the soap:Header as first element of the soap:envelope // Like this -$doc->manipulate(new PrependSoapHeaders($header)); +$doc->manipulate(new PrependSoapHeaders(...$headers)); ``` ## Locator diff --git a/src/Builder/Header/Actor.php b/src/Builder/Header/Actor.php new file mode 100644 index 0000000..1697816 --- /dev/null +++ b/src/Builder/Header/Actor.php @@ -0,0 +1,40 @@ +actor)($node); + } +} diff --git a/src/Builder/Header/MustUnderstand.php b/src/Builder/Header/MustUnderstand.php new file mode 100644 index 0000000..c2710b8 --- /dev/null +++ b/src/Builder/Header/MustUnderstand.php @@ -0,0 +1,30 @@ + + */ + private array $configurators; + + /** + * @no-named-arguments + * @param list $configurators + */ + public function __construct( + private string $namespace, + private string $name, + callable ... $configurators, + ) { + $this->configurators = $configurators; + } + + /** + * @psalm-suppress MissingThrowsDocblock + */ + public function __invoke(DOMNode $node): DOMNode + { + return children( + namespaced_element( + $this->namespace, + $this->name, + ...$this->configurators + ) + )($node); + } +} diff --git a/src/Builder/SoapHeaders.php b/src/Builder/SoapHeaders.php index 164e6ab..0bce2c7 100644 --- a/src/Builder/SoapHeaders.php +++ b/src/Builder/SoapHeaders.php @@ -27,8 +27,6 @@ public function __construct(callable ... $configurators) /** * @psalm-suppress MissingThrowsDocblock - * - * @param callable(DOMElement): DOMElement ...$configurators */ public function __invoke(DOMNode $node): DOMNode { diff --git a/src/Manipulator/PrependSoapHeaders.php b/src/Manipulator/PrependSoapHeaders.php index 810e031..00d8304 100644 --- a/src/Manipulator/PrependSoapHeaders.php +++ b/src/Manipulator/PrependSoapHeaders.php @@ -12,9 +12,15 @@ final class PrependSoapHeaders { - private DOMElement $soapHeaders; + /** + * @var list + */ + private array $soapHeaders; - public function __construct(DOMElement $soapHeaders) + /** + * @no-named-arguments + */ + public function __construct(DOMElement ... $soapHeaders) { $this->soapHeaders = $soapHeaders; } @@ -29,6 +35,10 @@ public function __invoke(DOMDocument $document): DOMElement $doc = Document::fromUnsafeDocument($document); $envelope = $doc->locate(new SoapEnvelopeLocator()); - return $envelope->insertBefore($this->soapHeaders, $envelope->firstChild); + foreach (array_reverse($this->soapHeaders) as $header) { + $envelope->insertBefore($header, $envelope->firstChild); + } + + return $envelope; } } diff --git a/tests/Unit/Builder/SoapHeaderTest.php b/tests/Unit/Builder/SoapHeaderTest.php new file mode 100644 index 0000000..43bbada --- /dev/null +++ b/tests/Unit/Builder/SoapHeaderTest.php @@ -0,0 +1,59 @@ +build($builder); + $doc->manipulate(new PrependSoapHeaders(...$headers)); + + $expected = << + + + josbos + topsecret + + + + + + EOXML; + + + static::assertXmlStringEqualsXmlString( + Document::fromXmlString($expected, comparable())->toXmlString(), + Document::fromUnsafeDocument($doc->toUnsafeDocument(), comparable())->toXmlString() + ); + } +} diff --git a/tests/Unit/Manipulator/PrependSoapHeadersTest.php b/tests/Unit/Manipulator/PrependSoapHeadersTest.php index d66b992..0189fc5 100644 --- a/tests/Unit/Manipulator/PrependSoapHeadersTest.php +++ b/tests/Unit/Manipulator/PrependSoapHeadersTest.php @@ -7,9 +7,26 @@ use Soap\Xml\Builder\SoapHeaders; use Soap\Xml\Manipulator\PrependSoapHeaders; use VeeWee\Xml\Dom\Document; +use function VeeWee\Xml\Dom\Builder\attribute; final class PrependSoapHeadersTest extends TestCase { + public function test_it_can_prepend_no_header(): void + { + $doc = Document::fromXmlFile(FIXTURE_DIR.'/empty-envelope-with-body.xml'); + $doc->manipulate(new PrependSoapHeaders()); + + $expected = << + + + EOXML; + + static::assertXmlStringEqualsXmlString($expected, $doc->toXmlString()); + } + + public function test_it_can_prepend_a_soap_header_on_an_envelope(): void { $doc = Document::fromXmlFile(FIXTURE_DIR.'/empty-envelope-with-body.xml'); @@ -27,4 +44,26 @@ public function test_it_can_prepend_a_soap_header_on_an_envelope(): void static::assertXmlStringEqualsXmlString($expected, $doc->toXmlString()); } + + public function test_it_can_prepend_mulitple_soap_header_on_an_envelope(): void + { + $doc = Document::fromXmlFile(FIXTURE_DIR.'/empty-envelope-with-body.xml'); + $headers = $doc->build( + new SoapHeaders(), + new SoapHeaders(attribute('id', '2')), + ); + + $doc->manipulate(new PrependSoapHeaders(...$headers)); + + $expected = << + + + + + EOXML; + + static::assertXmlStringEqualsXmlString($expected, $doc->toXmlString()); + } }