diff --git a/Converter/TypeRepository.php b/Converter/TypeRepository.php new file mode 100644 index 0000000..6946547 --- /dev/null +++ b/Converter/TypeRepository.php @@ -0,0 +1,91 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\Converter; + +use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; +use Bundle\WebServiceBundle\Util\Assert; +use Bundle\WebServiceBundle\Util\QName; +use Bundle\WebServiceBundle\Util\String; + +/** + * @author Christian Kerl + */ +class TypeRepository +{ + const ARRAY_SUFFIX = '[]'; + + private $xmlNamespaces = array(); + private $defaultTypeMap = array(); + + public function addXmlNamespace($prefix, $url) + { + $this->xmlNamespaces[$prefix] = $url; + } + + public function getXmlNamespace($prefix) + { + return $this->xmlNamespaces[$prefix]; + } + + public function addDefaultTypeMapping($phpType, $xmlType) + { + Assert::thatArgumentNotNull('phpType', $phpType); + Assert::thatArgumentNotNull('xmlType', $xmlType); + + $this->defaultTypeMap[$phpType] = $this->getQName($xmlType); + } + + public function fixTypeInformation(ServiceDefinition $definition) + { + $typeMap = $this->defaultTypeMap; + + foreach($definition->getAllTypes() as $type) { + $phpType = $type->getPhpType(); + $xmlType = $type->getXmlType(); + + if (null === $phpType) { + throw new \InvalidArgumentException(); + } + + if (null === $xmlType) { + if (!isset($typeMap[$phpType])) { + $parts = explode('\\', $phpType); + $xmlTypeName = ucfirst(end($parts)); + + if (String::endsWith($phpType, self::ARRAY_SUFFIX)) { + $xmlTypeName = str_replace(self::ARRAY_SUFFIX, 'Array', $xmlTypeName); + } + + $typeMap[$phpType] = new QName($definition->getNamespace(), $xmlTypeName); + } + + $xmlType = $typeMap[$phpType]; + } else { + $xmlType = $this->getQName($xmlType); + } + + $type->setXmlType((string) $xmlType); + } + } + + private function getQName($xmlType) + { + if (QName::isPrefixedQName($xmlType)) { + return QName::fromPrefixedQName($xmlType, array($this, 'getXmlNamespace')); + } else { + return QName::fromPackedQName($xmlType); + } + } + + public function createComplexTypeMap(ServiceDefinition $definition) + { + } +} \ No newline at end of file diff --git a/DependencyInjection/WebServiceExtension.php b/DependencyInjection/WebServiceExtension.php index 12e3d63..68afc93 100644 --- a/DependencyInjection/WebServiceExtension.php +++ b/DependencyInjection/WebServiceExtension.php @@ -65,9 +65,9 @@ class WebServiceExtension extends Extension $arguments = array(); foreach($this->contextArguments as $i => $argument) { - if (in_array($i, array(1, 3, 4))) { + if (in_array($i, array(1, 2, 3))) { $argument = new Reference($argument->__toString().$bindingSuffix); - } elseif (5 === $i) { + } elseif (6 === $i) { $argument = array_merge($argument, $config); } else { $argument = new Reference($argument->__toString()); diff --git a/Resources/config/webservice.xml b/Resources/config/webservice.xml index d0fdbd1..a2d6950 100644 --- a/Resources/config/webservice.xml +++ b/Resources/config/webservice.xml @@ -13,15 +13,17 @@ Bundle\WebServiceBundle\ServiceBinding\DocumentLiteralWrappedResponseMessageBinder Bundle\WebServiceBundle\ServiceDefinition\Dumper\WsdlDumper Bundle\WebServiceBundle\Converter\ConverterRepository + Bundle\WebServiceBundle\Converter\TypeRepository - + + %webservice.cache_dir% %kernel.debug% @@ -38,11 +40,30 @@ - - - + + + + + xsd + http://www.w3.org/2001/XMLSchema + + + string + xsd:string + + + int + xsd:int + + + bool + xsd:boolean + + + float + xsd:float - \ No newline at end of file + diff --git a/ServiceDefinition/ServiceDefinition.php b/ServiceDefinition/ServiceDefinition.php index 9be4a9e..8a24bc0 100644 --- a/ServiceDefinition/ServiceDefinition.php +++ b/ServiceDefinition/ServiceDefinition.php @@ -109,4 +109,22 @@ class ServiceDefinition { $this->headers->addAll($headers); } + + /** + * @return array + */ + public function getAllTypes() + { + $types = array(); + + foreach($this->methods as $method) { + foreach($method->getArguments() as $argument) { + $types[] = $argument->getType(); + } + + $types[] = $method->getReturn(); + } + + return $types; + } } \ No newline at end of file diff --git a/Soap/SoapServerFactory.php b/Soap/SoapServerFactory.php index 1666a8c..9ffa0c6 100644 --- a/Soap/SoapServerFactory.php +++ b/Soap/SoapServerFactory.php @@ -11,24 +11,21 @@ namespace Bundle\WebServiceBundle\Soap; use Bundle\WebServiceBundle\Converter\ConverterRepository; -use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; -use Bundle\WebServiceBundle\ServiceDefinition\Type; -use Bundle\WebServiceBundle\Util\QName; /** * @author Christian Kerl */ class SoapServerFactory { - private $definition; - private $converters; private $wsdlFile; + private $classmap; + private $converters; private $debug; - public function __construct(ServiceDefinition $definition, $wsdlFile, ConverterRepository $converters, $debug = false) + public function __construct($wsdlFile, array $classmap, ConverterRepository $converters, $debug = false) { - $this->definition = $definition; $this->wsdlFile = $wsdlFile; + $this->classmap = $classmap; $this->converters = $converters; $this->debug = $debug; } @@ -38,7 +35,7 @@ class SoapServerFactory return new \SoapServer( $this->wsdlFile, array( - 'classmap' => $this->createSoapServerClassmap(), + 'classmap' => $this->classmap, 'typemap' => $this->createSoapServerTypemap($request, $response), 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, 'cache_wsdl' => $this->debug ? WSDL_CACHE_NONE : WSDL_CACHE_DISK, @@ -65,36 +62,4 @@ class SoapServerFactory return $typemap; } - - private function createSoapServerClassmap() - { - $classmap = array(); - - foreach($this->definition->getHeaders() as $header) { - $this->addSoapServerClassmapEntry($classmap, $header->getType()); - } - - foreach($this->definition->getMethods() as $method) { - foreach($method->getArguments() as $arg) { - $this->addSoapServerClassmapEntry($classmap, $arg->getType()); - } - } - - return $classmap; - } - - private function addSoapServerClassmapEntry(&$classmap, Type $type) - { - // TODO: fix this hack - if(null === $type->getXmlType()) return; - - $xmlType = QName::fromPackedQName($type->getXmlType())->getName(); - $phpType = $type->getPhpType(); - - if(isset($classmap[$xmlType]) && $classmap[$xmlType] != $phpType) { - // log warning - } - - $classmap[$xmlType] = $phpType; - } } \ No newline at end of file diff --git a/Util/QName.php b/Util/QName.php index 924138e..874f52d 100644 --- a/Util/QName.php +++ b/Util/QName.php @@ -18,6 +18,20 @@ class QName private $namespace; private $name; + public static function isPrefixedQName($qname) + { + return false !== strpos($qname, ':') ? true : false; + } + + public static function fromPrefixedQName($qname, $resolveNamespacePrefixCallable) + { + Assert::thatArgument('qname', self::isPrefixedQName($qname)); + + list($prefix, $name) = explode(':', $qname); + + return new self(call_user_func($resolveNamespacePrefixCallable, $prefix), $name); + } + public static function fromPackedQName($qname) { Assert::thatArgument('qname', preg_match('/^\{(.+)\}(.+)$/', $qname, $matches)); @@ -28,7 +42,7 @@ class QName public function __construct($namespace, $name) { $this->namespace = $namespace; - $this->name = $name; + $this->name = $name; } public function getNamespace() diff --git a/WebServiceContext.php b/WebServiceContext.php index af14ee7..90c3879 100644 --- a/WebServiceContext.php +++ b/WebServiceContext.php @@ -11,6 +11,7 @@ namespace Bundle\WebServiceBundle; use Bundle\WebServiceBundle\Converter\ConverterRepository; +use Bundle\WebServiceBundle\Converter\TypeRepository; use Bundle\WebServiceBundle\ServiceBinding\MessageBinderInterface; use Bundle\WebServiceBundle\ServiceBinding\ServiceBinder; use Bundle\WebServiceBundle\ServiceDefinition\Dumper\DumperInterface; @@ -26,9 +27,10 @@ use Symfony\Component\Config\Loader\LoaderInterface; */ class WebServiceContext { - private $converterRepository; private $requestMessageBinder; private $responseMessageBinder; + private $typeRepository; + private $converterRepository; private $wsdlFileDumper; @@ -38,15 +40,16 @@ class WebServiceContext private $serviceBinder; private $serverFactory; - public function __construct(LoaderInterface $loader, DumperInterface $dumper, ConverterRepository $converterRepository, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder, array $options = array()) - { + public function __construct(LoaderInterface $loader, DumperInterface $dumper, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder, TypeRepository $typeRepository, ConverterRepository $converterRepository, array $options) { $this->loader = $loader; $this->wsdlFileDumper = $dumper; - $this->converterRepository = $converterRepository; $this->requestMessageBinder = $requestMessageBinder; $this->responseMessageBinder = $responseMessageBinder; + $this->typeRepository = $typeRepository; + $this->converterRepository = $converterRepository; + $this->options = $options; } @@ -60,6 +63,8 @@ class WebServiceContext $this->serviceDefinition = $this->loader->load($this->options['resource'], $this->options['resource_type']); $this->serviceDefinition->setName($this->options['name']); $this->serviceDefinition->setNamespace($this->options['namespace']); + + $this->typeRepository->fixTypeInformation($this->serviceDefinition); } return $this->serviceDefinition; @@ -67,15 +72,14 @@ class WebServiceContext public function getWsdlFile($endpoint = null) { - $id = null !== $endpoint ? '.'. md5($endpoint) : ''; - $file = sprintf('%s/%s.wsdl', $this->options['cache_dir'], $this->options['name'].$id); - $cache = new ConfigCache($file, true); + $file = sprintf('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint)); + $cache = new ConfigCache($file, $this->options['debug']); if(!$cache->isFresh()) { $cache->write($this->wsdlFileDumper->dumpServiceDefinition($this->getServiceDefinition(), array('endpoint' => $endpoint))); } - return $file; + return (string) $cache; } public function getWsdlFileContent($endpoint = null) @@ -95,7 +99,7 @@ class WebServiceContext public function getServerFactory() { if (null === $this->serverFactory) { - $this->serverFactory = new SoapServerFactory($this->getServiceDefinition(), $this->getWsdlFile(), $this->converterRepository, $this->options['debug']); + $this->serverFactory = new SoapServerFactory($this->getWsdlFile(), array(), $this->converterRepository, $this->options['debug']); } return $this->serverFactory;