diff --git a/Converter/ConverterRepository.php b/Converter/ConverterRepository.php index b1691f1..2a31a95 100644 --- a/Converter/ConverterRepository.php +++ b/Converter/ConverterRepository.php @@ -31,25 +31,9 @@ class ConverterRepository $this->typeConverters[] = $converter; } - public function toSoapServerTypemap(SoapKernel $kernel) + public function getTypeConverters() { - $result = array(); - - foreach($this->typeConverters as $typeConverter) - { - $result[] = array( - 'type_name' => $typeConverter->getTypeName(), - 'type_ns' => $typeConverter->getTypeNamespace(), - 'from_xml' => function($input) use ($kernel, $typeConverter) { - return $typeConverter->convertXmlToPhp($kernel->getRequest(), $input); - }, - 'to_xml' => function($input) use ($kernel, $typeConverter) { - return $typeConverter->convertPhpToXml($kernel->getResponse(), $input); - } - ); - } - - return $result; + return $this->typeConverters; } public function registerTypeConverterServices(ContainerInterface $container) diff --git a/Resources/config/services.xml b/Resources/config/services.xml index e0eb394..4cb4bf6 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -11,7 +11,7 @@ Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition Bundle\WebServiceBundle\ServiceDefinition\Loader\XmlFileLoader - Bundle\WebServiceBundle\Tests\StaticFileDumper + Bundle\WebServiceBundle\ServiceDefinition\Dumper\WsdlFileDumper @@ -23,14 +23,12 @@ - + - - @@ -39,6 +37,12 @@ + + + + + + @@ -47,6 +51,8 @@ %webservice.definition.name% + %webservice.definition.namespace% + %webservice.definition.resource% diff --git a/ServiceBinding/ServiceBinder.php b/ServiceBinding/ServiceBinder.php index 375e2f5..abf0430 100644 --- a/ServiceBinding/ServiceBinder.php +++ b/ServiceBinding/ServiceBinder.php @@ -10,6 +10,8 @@ namespace Bundle\WebServiceBundle\ServiceBinding; +use Bundle\WebServiceBundle\Util\QName; + use Bundle\WebServiceBundle\ServiceDefinition\Type; use Bundle\WebServiceBundle\Soap\SoapHeader; @@ -43,60 +45,16 @@ class ServiceBinder public function __construct( ServiceDefinition $definition, - LoaderInterface $loader, - DumperInterface $dumper, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder ) { - $loader->loadServiceDefinition($definition); - $this->definition = $definition; - $this->definitionDumper = $dumper; $this->requestMessageBinder = $requestMessageBinder; $this->responseMessageBinder = $responseMessageBinder; } - public function getSerializedServiceDefinition() - { - // TODO: add caching - return $this->definitionDumper->dumpServiceDefinition($this->definition); - } - - public function getSoapServerClassmap() - { - $result = array(); - - foreach($this->definition->getHeaders() as $header) - { - $this->addSoapServerClassmapEntry($result, $header->getType()); - } - - foreach($this->definition->getMethods() as $method) - { - foreach($method->getArguments() as $arg) - { - $this->addSoapServerClassmapEntry($result, $arg->getType()); - } - } - - return $result; - } - - private function addSoapServerClassmapEntry(&$classmap, Type $type) - { - list($namespace, $xmlType) = $this->parsePackedQName($type->getXmlType()); - $phpType = $type->getPhpType(); - - if(isset($classmap[$xmlType]) && $classmap[$xmlType] != $phpType) - { - // log warning - } - - $classmap[$xmlType] = $phpType; - } - public function isServiceHeader($name) { return $this->definition->getHeaders()->has($name); @@ -134,18 +92,8 @@ class ServiceBinder protected function createSoapHeader(Header $headerDefinition, $data) { - list($namespace, $name) = $this->parsePackedQName($headerDefinition->getType()->getXmlType()); + $qname = QName::fromPackedQName($headerDefinition->getType()->getXmlType()); - return new SoapHeader($namespace, $name, $data); - } - - private function parsePackedQName($qname) - { - if(!preg_match('/^\{(.+)\}(.+)$/', $qname, $matches)) - { - throw new \InvalidArgumentException(); - } - - return array($matches[1], $matches[2]); + return new SoapHeader($qname->getNamespace(), $qname->getName(), $data); } } \ No newline at end of file diff --git a/Soap/SoapServerFactory.php b/Soap/SoapServerFactory.php new file mode 100644 index 0000000..983a07c --- /dev/null +++ b/Soap/SoapServerFactory.php @@ -0,0 +1,111 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\Soap; + +/** + * + * @author Christian Kerl + */ +use Bundle\WebServiceBundle\ServiceDefinition\Type; + +use Bundle\WebServiceBundle\ServiceDefinition\Dumper\FileDumper; + +use Bundle\WebServiceBundle\Converter\ConverterRepository; + +use Bundle\WebServiceBundle\SoapKernel; + +use Bundle\WebServiceBundle\Util\QName; + +use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; + +class SoapServerFactory +{ + private $definition; + private $converters; + private $dumper; + + public function __construct(ServiceDefinition $definition, ConverterRepository $converters, FileDumper $dumper) + { + $this->definition = $definition; + $this->converters = $converters; + $this->dumper = $dumper; + } + + public function create(&$request, &$response) + { + $file = $this->dumper->dumpServiceDefinition($this->definition); + + $server = new \SoapServer( + $file, + array( + 'classmap' => $this->createSoapServerClassmap(), + 'typemap' => $this->createSoapServerTypemap($request, $response), + 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, + ) + ); + + return $server; + } + + private function createSoapServerTypemap(&$request, &$response) + { + $result = array(); + + foreach($this->converters->getTypeConverters() as $typeConverter) + { + $result[] = array( + 'type_name' => $typeConverter->getTypeName(), + 'type_ns' => $typeConverter->getTypeNamespace(), + 'from_xml' => function($input) use (&$request, $typeConverter) { + return $typeConverter->convertXmlToPhp($request, $input); + }, + 'to_xml' => function($input) use (&$response, $typeConverter) { + return $typeConverter->convertPhpToXml($response, $input); + } + ); + } + + return $result; + } + + private function createSoapServerClassmap() + { + $result = array(); + + foreach($this->definition->getHeaders() as $header) + { + $this->addSoapServerClassmapEntry($result, $header->getType()); + } + + foreach($this->definition->getMethods() as $method) + { + foreach($method->getArguments() as $arg) + { + $this->addSoapServerClassmapEntry($result, $arg->getType()); + } + } + + return $result; + } + + private function addSoapServerClassmapEntry(&$classmap, Type $type) + { + $xmlType = QName::fromPackedQName($type->getXmlType())->getName(); + $phpType = $type->getPhpType(); + + if(isset($classmap[$xmlType]) && $classmap[$xmlType] != $phpType) + { + // log warning + } + + $classmap[$xmlType] = $phpType; + } +} diff --git a/SoapKernel.php b/SoapKernel.php index e939583..aedd9bd 100644 --- a/SoapKernel.php +++ b/SoapKernel.php @@ -11,6 +11,8 @@ namespace Bundle\WebServiceBundle; +use Bundle\WebServiceBundle\Soap\SoapServerFactory; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -61,21 +63,13 @@ class SoapKernel implements HttpKernelInterface */ protected $kernel; - public function __construct(ServiceBinder $serviceBinder, ConverterRepository $converterRepository, HttpKernelInterface $kernel) + public function __construct(ServiceBinder $serviceBinder, SoapServerFactory $soapServerFactory, HttpKernelInterface $kernel) { $this->serviceBinder = $serviceBinder; - - $this->soapServer = new \SoapServer( - $this->serviceBinder->getSerializedServiceDefinition(), - array( - 'classmap' => $this->serviceBinder->getSoapServerClassmap(), - 'typemap' => $converterRepository->toSoapServerTypemap($this), - 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, - ) - ); + $this->soapServer = $soapServerFactory->create($this->soapRequest, $this->soapResponse); $this->soapServer->setObject($this); - $this->kernel = $kernel; + } public function getRequest() diff --git a/Tests/SoapKernelTest.php b/Tests/SoapKernelTest.php index 21d4490..bb6dc5c 100644 --- a/Tests/SoapKernelTest.php +++ b/Tests/SoapKernelTest.php @@ -10,6 +10,8 @@ namespace Bundle\WebServiceBundle\Tests; +use Bundle\WebServiceBundle\Soap\SoapServerFactory; + use Bundle\WebServiceBundle\Converter\ConverterRepository; use Symfony\Component\HttpFoundation\Request; @@ -42,20 +44,20 @@ class SoapKernelTest extends \PHPUnit_Framework_TestCase { $serviceDefinition = new ServiceDefinition('api'); $serviceDefinitionLoader = new XmlFileLoader(__DIR__ . '/fixtures/api-servicedefinition.xml'); + $serviceDefinitionLoader->loadServiceDefinition($serviceDefinition); $serviceDefinitionDumper = new StaticFileDumper(__DIR__ . '/fixtures/api.wsdl'); $requestMessageBinder = new RpcLiteralRequestMessageBinder(); $responseMessageBinder = new RpcLiteralResponseMessageBinder(); - $serviceBinder = new ServiceBinder($serviceDefinition, $serviceDefinitionLoader, $serviceDefinitionDumper, $requestMessageBinder, $responseMessageBinder); - + $serviceBinder = new ServiceBinder($serviceDefinition, $requestMessageBinder, $responseMessageBinder); $converterRepository = new ConverterRepository(); - + $soapServerFactory = new SoapServerFactory($serviceDefinition, $converterRepository, $serviceDefinitionDumper); $httpKernel = $this->getMock('Symfony\\Component\\HttpKernel\\HttpKernelInterface'); $httpKernel->expects($this->any()) ->method('handle') ->will($this->returnValue(new SoapResponse(200))); - $this->soapKernel = new SoapKernel($serviceBinder, $converterRepository, $httpKernel); + $this->soapKernel = new SoapKernel($serviceBinder, $soapServerFactory, $httpKernel); } public function testHandle() diff --git a/Tests/StaticFileDumper.php b/Tests/StaticFileDumper.php index 82675ed..3d91744 100644 --- a/Tests/StaticFileDumper.php +++ b/Tests/StaticFileDumper.php @@ -10,18 +10,13 @@ namespace Bundle\WebServiceBundle\Tests; +use Bundle\WebServiceBundle\ServiceDefinition\Dumper\FileDumper; + use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; use Bundle\WebServiceBundle\ServiceDefinition\Dumper\DumperInterface; -class StaticFileDumper implements DumperInterface +class StaticFileDumper extends FileDumper { - private $file; - - public function __construct($file) - { - $this->file = $file; - } - public function dumpServiceDefinition(ServiceDefinition $definition) { return $this->file; diff --git a/Util/QName.php b/Util/QName.php new file mode 100644 index 0000000..d2bf3f2 --- /dev/null +++ b/Util/QName.php @@ -0,0 +1,49 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\Util; + +/** + * + * @author Christian Kerl + */ +class QName +{ + public static function fromPackedQName($qname) + { + Assert::thatArgument('qname', preg_match('/^\{(.+)\}(.+)$/', $qname, $matches)); + + return new self($matches[1], $matches[2]); + } + + private $namespace; + private $name; + + public function __construct($namespace, $name) + { + $this->namespace = $namespace; + $this->name = $name; + } + + public function getNamespace() + { + return $this->namespace; + } + + public function getName() + { + return $this->name; + } + + public function __toString() + { + return sprintf('{%s}%s', $this->getNamespace(), $this->getName()); + } +}