added TypeRepository managing all mappings from php to xml types; removed classmap generation from SoapServerFactory, this will be done by TypeRepository::createComplexTypeMap(...);
Conflicts: Resources/config/webservice.xml Soap/SoapServerFactory.php Util/QName.php WebServiceContext.php
This commit is contained in:
parent
5da442b716
commit
76e7f42ccb
91
Converter/TypeRepository.php
Normal file
91
Converter/TypeRepository.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the WebServiceBundle.
|
||||
*
|
||||
* (c) Christian Kerl <christian-kerl@web.de>
|
||||
*
|
||||
* 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 <christian-kerl@web.de>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
@ -13,15 +13,17 @@
|
||||
<parameter key="webservice.binder.response.documentwrapped.class">Bundle\WebServiceBundle\ServiceBinding\DocumentLiteralWrappedResponseMessageBinder</parameter>
|
||||
<parameter key="webservice.definition.dumper.wsdl.rpcliteral.class">Bundle\WebServiceBundle\ServiceDefinition\Dumper\WsdlDumper</parameter>
|
||||
<parameter key="webservice.converter.repository.class">Bundle\WebServiceBundle\Converter\ConverterRepository</parameter>
|
||||
<parameter key="webservice.type.repository.class">Bundle\WebServiceBundle\Converter\TypeRepository</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="webservice.context" class="%webservice.context.class%" abstract="true">
|
||||
<argument type="service" id="webservice.definition.loader"/>
|
||||
<argument type="service" id="webservice.definition.dumper.wsdl"/>
|
||||
<argument type="service" id="webservice.converter.repository"/>
|
||||
<argument type="service" id="webservice.binder.request"/>
|
||||
<argument type="service" id="webservice.binder.response"/>
|
||||
<argument type="service" id="webservice.type.repository"/>
|
||||
<argument type="service" id="webservice.converter.repository"/>
|
||||
<argument type="collection">
|
||||
<argument key="cache_dir">%webservice.cache_dir%</argument>
|
||||
<argument key="debug">%kernel.debug%</argument>
|
||||
@ -38,11 +40,30 @@
|
||||
|
||||
<service id="webservice.definition.dumper.wsdl.rpcliteral" class="%webservice.definition.dumper.wsdl.rpcliteral.class%" />
|
||||
|
||||
<service id="webservice.converter.repository" class="%webservice.converter.repository.class%">
|
||||
<call method="registerTypeConverterServices">
|
||||
<argument type="service" id="service_container" />
|
||||
<service id="webservice.converter.repository" class="%webservice.converter.repository.class%" />
|
||||
|
||||
<service id="webservice.type.repository" class="%webservice.type.repository.class%">
|
||||
<call method="addXmlNamespace">
|
||||
<argument>xsd</argument>
|
||||
<argument>http://www.w3.org/2001/XMLSchema</argument>
|
||||
</call>
|
||||
<call method="addDefaultTypeMapping">
|
||||
<argument>string</argument>
|
||||
<argument>xsd:string</argument>
|
||||
</call>
|
||||
<call method="addDefaultTypeMapping">
|
||||
<argument>int</argument>
|
||||
<argument>xsd:int</argument>
|
||||
</call>
|
||||
<call method="addDefaultTypeMapping">
|
||||
<argument>bool</argument>
|
||||
<argument>xsd:boolean</argument>
|
||||
</call>
|
||||
<call method="addDefaultTypeMapping">
|
||||
<argument>float</argument>
|
||||
<argument>xsd:float</argument>
|
||||
</call>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
||||
</container>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 <christian-kerl@web.de>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user