From 61ed8865297b446002911cdcdbcbc86796f87f50 Mon Sep 17 00:00:00 2001 From: Asmir Mustafic Date: Thu, 8 Sep 2016 14:24:46 +0300 Subject: [PATCH] added header handlers --- src/Arguments/ArgumentsReader.php | 41 +++++++++- .../Headers/Handler/HeaderHandler.php | 82 +++++++++++++++++++ .../Headers/Handler/HeaderPlaceholder.php | 9 ++ src/Arguments/Headers/Header.php | 28 +++++++ .../Headers/MustUnderstandHeader.php | 11 +++ src/Client.php | 5 +- src/ClientFactory.php | 14 +++- tests/Client/ClientRequestResponsesTest.php | 64 ++++++++++++++- 8 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 src/Arguments/Headers/Handler/HeaderHandler.php create mode 100644 src/Arguments/Headers/Handler/HeaderPlaceholder.php create mode 100644 src/Arguments/Headers/Header.php create mode 100644 src/Arguments/Headers/MustUnderstandHeader.php diff --git a/src/Arguments/ArgumentsReader.php b/src/Arguments/ArgumentsReader.php index dafccb9..a60f30e 100644 --- a/src/Arguments/ArgumentsReader.php +++ b/src/Arguments/ArgumentsReader.php @@ -3,6 +3,9 @@ use Doctrine\Common\Inflector\Inflector; use Doctrine\Instantiator\Instantiator; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Handler\HeaderHandler; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Handler\HeaderPlaceholder; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Header; use JMS\Serializer\Serializer; class ArgumentsReader implements ArgumentsReaderInterface @@ -11,10 +14,15 @@ class ArgumentsReader implements ArgumentsReaderInterface * @var Serializer */ private $serializer; + /** + * @var HeaderHandler + */ + private $headerHandler; - public function __construct(Serializer $serializer) + public function __construct(Serializer $serializer, HeaderHandler $headerHandler) { $this->serializer = $serializer; + $this->headerHandler = $headerHandler; } /** @@ -24,9 +32,40 @@ public function __construct(Serializer $serializer) */ public function readArguments(array $args, array $input) { + + $envelope = array_filter($args, function ($item) use ($input) { + return $item instanceof $input['message_fqcn']; + }); + if ($envelope) { + return reset($envelope); + } + $instantiator = new Instantiator(); $envelope = $instantiator->instantiate($input['message_fqcn']); + $headers = array_filter($args, function ($item) use ($input) { + return $item instanceof $input['headers_fqcn']; + }); + if ($headers) { + $envelope->setHeader(reset($headers)); + } else { + + $headers = array_filter($args, function ($item) { + return $item instanceof Header; + }); + if (count($headers)) { + $headerPlaceholder = new HeaderPlaceholder(); + foreach ($headers as $headerInfo) { + $this->headerHandler->addHeaderData($headerPlaceholder, $headerInfo); + } + $envelope->setHeader($headerPlaceholder); + } + } + + $args = array_filter($args, function ($item) use ($input) { + return !($item instanceof Header) && !($item instanceof $input['headers_fqcn']); + }); + if (!count($input['parts'])) { return $envelope; } diff --git a/src/Arguments/Headers/Handler/HeaderHandler.php b/src/Arguments/Headers/Handler/HeaderHandler.php new file mode 100644 index 0000000..07011ae --- /dev/null +++ b/src/Arguments/Headers/Handler/HeaderHandler.php @@ -0,0 +1,82 @@ + GraphNavigator::DIRECTION_SERIALIZATION, + 'format' => 'xml', + 'type' => HeaderPlaceholder::class, + 'method' => 'serializeHeader' + ), + ); + } + + public function addHeaderData(HeaderPlaceholder $reference, $data) + { + $this->headerData[spl_object_hash($reference)][] = $data; + } + + public function serializeHeader(XmlSerializationVisitor $visitor, HeaderPlaceholder $data, array $type, SerializationContext $context) + { + if (!isset($this->headerData[spl_object_hash($data)])) { + return; + } + $factory = $context->getMetadataFactory(); + /** + * @var $header Header + */ + foreach ($this->headerData[spl_object_hash($data)] as $header) { + /** + * @var $classMetadata \JMS\Serializer\Metadata\ClassMetadata + */ + $classMetadata = $factory->getMetadataForClass(get_class($header->getData())); + + $metadata = new StaticPropertyMetadata($classMetadata->name, $classMetadata->xmlRootName, $header->getData()); + $metadata->xmlNamespace = $classMetadata->xmlRootNamespace; + $metadata->serializedName = $classMetadata->xmlRootName; + + $visitor->visitProperty($metadata, $header->getData(), $context); + + $this->handleOptions($visitor, $header); + } + } + + private function handleOptions(XmlSerializationVisitor $visitor, $header) + { + $options = $header->getOptions(); + if (!count($options)) { + return; + } + $currentNode = $visitor->getCurrentNode(); + foreach ($options as $option => $value) { + if ($option === 'mustUnderstand' || $option === 'required') { + $this->setAttributeOnNode($currentNode->lastChild, $option, "true", 'http://schemas.xmlsoap.org/soap/envelope/'); + } + } + } + + private function setAttributeOnNode(\DOMElement $node, $name, $value, $namespace) + { + if (!($prefix = $node->lookupPrefix($namespace)) && !($prefix = $node->ownerDocument->lookupPrefix($namespace))) { + $prefix = 'ns-' . substr(sha1($namespace), 0, 8); + } + $node->setAttributeNS($namespace, $prefix . ':' . $name, $value); + } + +} + + + diff --git a/src/Arguments/Headers/Handler/HeaderPlaceholder.php b/src/Arguments/Headers/Handler/HeaderPlaceholder.php new file mode 100644 index 0000000..b7862d9 --- /dev/null +++ b/src/Arguments/Headers/Handler/HeaderPlaceholder.php @@ -0,0 +1,9 @@ +data = $data; + $this->options = $options; + } + + public function getData() + { + return $this->data; + } + + public function getOptions() + { + return $this->options; + } +} diff --git a/src/Arguments/Headers/MustUnderstandHeader.php b/src/Arguments/Headers/MustUnderstandHeader.php new file mode 100644 index 0000000..d9efe93 --- /dev/null +++ b/src/Arguments/Headers/MustUnderstandHeader.php @@ -0,0 +1,11 @@ + true], $options)); + } +} diff --git a/src/Client.php b/src/Client.php index 2e59387..f28e8b1 100644 --- a/src/Client.php +++ b/src/Client.php @@ -3,6 +3,7 @@ use GoetasWebservices\SoapServices\SoapClient\Arguments\ArgumentsReader; use GoetasWebservices\SoapServices\SoapClient\Arguments\ArgumentsReaderInterface; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Handler\HeaderHandler; use GoetasWebservices\SoapServices\SoapClient\Exception\ClientException; use GoetasWebservices\SoapServices\SoapClient\Exception\FaultException; use GoetasWebservices\SoapServices\SoapClient\Exception\ServerException; @@ -48,14 +49,14 @@ class Client private $argumentsReader; - public function __construct(array $serviceDefinition, Serializer $serializer, MessageFactory $messageFactory, HttpClient $client, $unwrap = false) + public function __construct(array $serviceDefinition, Serializer $serializer, MessageFactory $messageFactory, HttpClient $client, HeaderHandler $headerHandler, $unwrap = false) { $this->serviceDefinition = $serviceDefinition; $this->serializer = $serializer; $this->client = $client; $this->messageFactory = $messageFactory; - $this->argumentsReader = new ArgumentsReader($this->serializer); + $this->argumentsReader = new ArgumentsReader($this->serializer, $headerHandler); $this->resultCreator = new ResultCreator($this->serializer, $unwrap); } diff --git a/src/ClientFactory.php b/src/ClientFactory.php index a59dc77..cee707d 100644 --- a/src/ClientFactory.php +++ b/src/ClientFactory.php @@ -1,6 +1,7 @@ setSerializer($serializer); @@ -45,6 +51,11 @@ public function __construct(array $namespaces, SerializerInterface $serializer) } } + public function setHeaderHandler(HeaderHandler $headerHandler) + { + $this->headerHandler = $headerHandler; + } + public function setUnwrapResponses($unwrap) { $this->unwrap = !!$unwrap; @@ -105,9 +116,10 @@ public function getClient($wsdl, $portName = null, $serviceName = null, $unwrap $this->httpClient = $this->httpClient ?: HttpClientDiscovery::find(); $this->messageFactory = $this->messageFactory ?: MessageFactoryDiscovery::find(); + $headerHandler = $this->headerHandler ?: new HeaderHandler(); $unwrap = is_null($unwrap) ? $this->unwrap : $unwrap; - return new Client($service, $this->serializer, $this->messageFactory, $this->httpClient, $unwrap); + return new Client($service, $this->serializer, $this->messageFactory, $this->httpClient, $headerHandler, $unwrap); } /** diff --git a/tests/Client/ClientRequestResponsesTest.php b/tests/Client/ClientRequestResponsesTest.php index 4fa5836..e3a4fc9 100644 --- a/tests/Client/ClientRequestResponsesTest.php +++ b/tests/Client/ClientRequestResponsesTest.php @@ -2,8 +2,11 @@ namespace GoetasWebservices\SoapServices\Tests; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Handler\HeaderHandler; use GoetasWebservices\SoapServices\SoapClient\ClientFactory; use GoetasWebservices\SoapServices\SoapClient\Exception\FaultException; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Header; +use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\MustUnderstandHeader; use GoetasWebservices\SoapServices\SoapCommon\Metadata\PhpMetadataGenerator; use GoetasWebservices\SoapServices\SoapCommon\SoapEnvelope\Parts\Fault; use GoetasWebservices\WsdlToPhp\Tests\Generator; @@ -13,6 +16,7 @@ use GuzzleHttp\Middleware; use GuzzleHttp\Psr7\Response; use Http\Adapter\Guzzle6\Client as GuzzleAdapter; +use JMS\Serializer\Handler\HandlerRegistryInterface; use Psr\Http\Message\ResponseInterface; class ClientRequestResponsesTest extends \PHPUnit_Framework_TestCase @@ -39,7 +43,7 @@ public static function setUpBeforeClass() 'http://www.example.org/test/' => "Ex" ]; - self::$generator = new Generator($namespaces); + self::$generator = new Generator($namespaces);//, [], '/home/goetas/projects/soap-client/tmp'); self::$generator->generate([__DIR__ . '/../Fixtures/Soap/test.wsdl']); self::$generator->registerAutoloader(); } @@ -57,7 +61,10 @@ public function setUp() ]; $generator = new Generator($namespaces); $ref = new \ReflectionClass(Fault::class); - $serializer = $generator->buildSerializer(null, [ + $headerHandler = new HeaderHandler(); + $serializer = $generator->buildSerializer(function (HandlerRegistryInterface $h) use ($headerHandler) { + $h->registerSubscribingHandler($headerHandler); + }, [ 'GoetasWebservices\SoapServices\SoapCommon\SoapEnvelope' => dirname($ref->getFileName()) . '/../../Resources/metadata/jms' ]); @@ -71,6 +78,7 @@ public function setUp() $this->factory = new ClientFactory($namespaces, $serializer); $this->factory->setHttpClient(new GuzzleAdapter($guzzle)); + $this->factory->setHeaderHandler($headerHandler); $metadataGenerator = new PhpMetadataGenerator($namespaces); $this->factory->setMetadataGenerator($metadataGenerator); @@ -104,6 +112,58 @@ public function testGetSimple() $this->assertEquals("A", $response->getOut()); } + public function testHeaders() + { + $httpResponse = new Response(200, ['Content-Type' => 'text/xml'], ' + + + + + + + '); + + $this->responseMock->append($httpResponse); + $this->responseMock->append($httpResponse); + + $client = $this->factory->getClient(__DIR__ . '/../Fixtures/Soap/test.wsdl', null, null, true); + + $mp = new \Ex\GetReturnMultiParam(); + $mp->setIn("foo"); + + $client->getSimple("foo", new Header($mp)); + $client->getSimple("foo", new MustUnderstandHeader($mp)); + $this->assertXmlStringEqualsXmlString( + ' + + + + + + + + + + + ', + (string)$this->requestResponseStack[0]['request']->getBody()); + + $this->assertXmlStringEqualsXmlString( + ' + + + + + + + + + + + ', + (string)$this->requestResponseStack[1]['request']->getBody()); + } + public function testNoOutput() { $this->responseMock->append(