Merge remote-tracking branch 'origin/client'

This commit is contained in:
Francis Besset 2011-11-13 22:42:51 +01:00
commit 6c4ef348bd
30 changed files with 488 additions and 353 deletions

41
Cache.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapBundle;
use BeSimple\SoapCommon\Cache as BaseCache;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class Cache
{
public function __construct($disabled, $type, $directory, $lifetime = null, $limit = null)
{
$isEnabled = $disabled ? BaseCache::DISABLED : BaseCache::ENABLED;
BaseCache::setEnabled($isEnabled);
if (BaseCache::ENABLED == BaseCache::isEnabled()) {
BaseCache::setType($type);
BaseCache::setDirectory($directory);
if (null !== $lifetime) {
BaseCache::setLifetime($lifetime);
}
if (null !== $limit) {
BaseCache::setLimit($limit);
}
}
}
}

View File

@ -58,9 +58,11 @@ class SoapWebServiceController extends ContainerAware
$this->serviceBinder = $webServiceContext->getServiceBinder();
$this->soapRequest = SoapRequest::createFromHttpRequest($this->container->get('request'));
$this->soapServer = $webServiceContext->getServerFactory()->create($this->soapRequest, $this->getResponse());
$this->soapServer->setObject($this);
$this->soapServer = $webServiceContext
->getServerBuilder()
->withHandler($this)
->build()
;
ob_start();
$this->soapServer->handle($this->soapRequest->getSoapMessage());

View File

@ -1,31 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Converter;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class ConverterRepository
{
private $typeConverters = array();
public function addTypeConverter(TypeConverterInterface $converter)
{
$this->typeConverters[] = $converter;
}
public function getTypeConverters()
{
return $this->typeConverters;
}
}

View File

@ -1,44 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\Util\String;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class DateTimeTypeConverter implements TypeConverterInterface
{
public function getTypeNamespace()
{
return 'http://www.w3.org/2001/XMLSchema';
}
public function getTypeName()
{
return 'dateTime';
}
public function convertXmlToPhp(SoapRequest $request, $data)
{
$doc = new \DOMDocument();
$doc->loadXML($data);
return new \DateTime($doc->textContent);
}
public function convertPhpToXml(SoapResponse $response, $data)
{
return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d\TH:i:sP'));
}
}

View File

@ -1,44 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\Util\String;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class DateTypeConverter implements TypeConverterInterface
{
public function getTypeNamespace()
{
return 'http://www.w3.org/2001/XMLSchema';
}
public function getTypeName()
{
return 'date';
}
public function convertXmlToPhp(SoapRequest $request, $data)
{
$doc = new \DOMDocument();
$doc->loadXML($data);
return new \DateTime($doc->textContent);
}
public function convertPhpToXml(SoapResponse $response, $data)
{
return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d'));
}
}

View File

@ -1,28 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
interface TypeConverterInterface
{
function getTypeNamespace();
function getTypeName();
function convertXmlToPhp(SoapRequest $request, $data);
function convertPhpToXml(SoapResponse $response, $data);
}

View File

@ -1,8 +1,10 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
@ -10,6 +12,8 @@
namespace BeSimple\SoapBundle\DependencyInjection;
use BeSimple\SoapCommon\Cache;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -22,6 +26,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
* BeSimpleSoapExtension.
*
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class BeSimpleSoapExtension extends Extension
{
@ -44,6 +49,12 @@ class BeSimpleSoapExtension extends Extension
$config = $processor->process($configuration->getConfigTree(), $configs);
$this->registerCacheConfiguration($config['cache'], $container, $loader);
if (!empty($config['clients'])) {
$this->registerClientConfiguration($config['clients'], $container, $loader);
}
$container->setParameter('besimple.soap.definition.dumper.options.stylesheet', $config['wsdl_dumper']['stylesheet']);
foreach($config['services'] as $name => $serviceConfig) {
@ -52,6 +63,74 @@ class BeSimpleSoapExtension extends Extension
}
}
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('soap.xml');
$config['type'] = $this->getCacheType($config['type']);
foreach (array('type', 'lifetime', 'limit') as $key) {
$container->setParameter('besimple.soap.cache.'.$key, $config[$key]);
}
}
private function registerClientConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('client.xml');
foreach ($config as $client => $options) {
$definition = new DefinitionDecorator('besimple.soap.client.builder');
$context = $container->setDefinition(sprintf('besimple.soap.client.builder.%s', $client), $definition);
$definition->replaceArgument(0, $options['wsdl']);
$defOptions = $container
->getDefinition('besimple.soap.client.builder')
->getArgument(1);
foreach (array('cache_type', 'user_agent') as $key) {
if (isset($options[$key])) {
$defOptions[$key] = $options[$key];
}
}
if (isset($defOptions['cache_type'])) {
$defOptions['cache_type'] = $this->getCacheType($defOptions['cache_type']);
}
$definition->replaceArgument(1, $defOptions);
if (!empty($options['classmap'])) {
$classmap = $this->createClientClassmap($client, $options['classmap'], $container);
$definition->replaceArgument(2, new Reference($classmap));
} else {
$definition->replaceArgument(2, null);
}
$this->createClient($client, $container);
}
}
private function createClientClassmap($client, array $classmap, ContainerBuilder $container)
{
$definition = new DefinitionDecorator('besimple.soap.classmap');
$context = $container->setDefinition(sprintf('besimple.soap.classmap.%s', $client), $definition);
$definition->setMethodCalls(array(
array('set', array($classmap)),
));
return sprintf('besimple.soap.classmap.%s', $client);
}
private function createClient($client, ContainerBuilder $container)
{
$definition = new DefinitionDecorator('besimple.soap.client');
$context = $container->setDefinition(sprintf('besimple.soap.client.%s', $client), $definition);
$definition->setFactoryService(sprintf('besimple.soap.client.builder.%s', $client));
}
private function createWebServiceContext(array $config, ContainerBuilder $container)
{
$bindingSuffix = $this->bindingConfigToServiceSuffixMap[$config['binding']];
@ -61,10 +140,31 @@ class BeSimpleSoapExtension extends Extension
$definition = new DefinitionDecorator('besimple.soap.context.'.$bindingSuffix);
$context = $container->setDefinition($contextId, $definition);
if (isset($config['cache_type'])) {
$config['cache_type'] = $this->getCacheType($config['cache_type']);
}
$options = $container
->getDefinition('besimple.soap.context.'.$bindingSuffix)
->getArgument(4);
->getArgument(5);
$definition->replaceArgument(4, array_merge($options, $config));
$definition->replaceArgument(5, array_merge($options, $config));
}
private function getCacheType($type)
{
switch ($type) {
case 'none':
return Cache::TYPE_NONE;
case 'disk':
return Cache::TYPE_DISK;
case 'memory':
return Cache::TYPE_MEMORY;
case 'disk_memory':
return Cache::TYPE_DISK_MEMORY;
}
}
}

View File

@ -23,14 +23,14 @@ class TypeConverterPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition('besimple.soap.converter.repository')) {
if (false === $container->hasDefinition('besimple.soap.converter.collection')) {
return;
}
$definition = $container->getDefinition('besimple.soap.converter.repository');
$definition = $container->getDefinition('besimple.soap.converter.collection');
foreach ($container->findTaggedServiceIds('besimple.soap.converter') as $id => $attributes) {
$definition->addMethodCall('addTypeConverter', array(new Reference($id)));
$definition->addMethodCall('add', array(new Reference($id)));
}
}
}

View File

@ -1,8 +1,10 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
@ -17,9 +19,12 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder;
* WebServiceExtension configuration structure.
*
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class Configuration
{
private $cacheTypes = array('none', 'disk', 'memory', 'disk_memory');
/**
* Generates the configuration tree.
*
@ -30,12 +35,62 @@ class Configuration
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('be_simple_soap');
$this->addCacheSection($rootNode);
$this->addClientSection($rootNode);
$this->addServicesSection($rootNode);
$this->addWsdlDumperSection($rootNode);
return $treeBuilder->buildTree();
}
private function addCacheSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('cache')
->addDefaultsIfNotSet()
->children()
->scalarNode('type')
->defaultValue('disk')
->validate()
->ifNotInArray($this->cacheTypes)
->thenInvalid(sprintf('The cache type has to be either %s', implode(', ', $this->cacheTypes)))
->end()
->end()
->scalarNode('lifetime')->defaultNull()->end()
->scalarNode('limit')->defaultNull()->end()
->end()
->end()
->end()
;
}
private function addClientSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->children()
->arrayNode('clients')
->useAttributeAsKey('name')
->prototype('array')
->children()
->scalarNode('wsdl')->isRequired()->end()
->scalarNode('user_agent')->end()
->scalarNode('cache_type')
->validate()
->ifNotInArray($this->cacheTypes)
->thenInvalid(sprintf('The cache type has to be either %s', implode(', ', $this->cacheTypes)))
->end()
->end()
->arrayNode('classmap')
->useAttributeAsKey('name')
->prototype('scalar')
->end()
->end()
->end()
->end()
;
}
private function addServicesSection(ArrayNodeDefinition $rootNode)
{
$rootNode
@ -60,6 +115,12 @@ class Configuration
->thenInvalid("Service binding style has to be either 'rpc-literal' or 'document-wrapped'")
->end()
->end()
->scalarNode('cache_type')
->validate()
->ifNotInArray($this->cacheTypes)
->thenInvalid(sprintf('The cache type has to be either %s', implode(', ', $this->cacheTypes)))
->end()
->end()
->end()
->end()
->end()

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="besimple.soap.client.builder.class">BeSimple\SoapBundle\Soap\SoapClientBuilder</parameter>
<parameter key="besimple.soap.classmap.class">BeSimple\SoapCommon\Classmap</parameter>
</parameters>
<services>
<service id="besimple.soap.client.builder" class="%besimple.soap.client.builder.class%" abstract="true">
<argument /> <!-- wsdl URI -->
<argument type="collection">
<argument key="debug">%kernel.debug%</argument>
</argument>
<argument type="service" id="besimple.soap.classmap" />
<argument type="service" id="besimple.soap.converter.collection" />
<argument type="service" id="besimple.soap.cache" />
</service>
<service id="besimple.soap.client" factory-service="besimple.soap.client.builder" factory-method="build" class="%besimple.soap.client.builder.class%" abstract="true" />
<service id="besimple.soap.classmap" class="%besimple.soap.classmap.class%" abstract="true" />
</services>
</container>

View File

@ -5,13 +5,13 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="besimple.soap.converter.repository.class">BeSimple\SoapBundle\Converter\ConverterRepository</parameter>
<parameter key="besimple.soap.converter.date_time.class">BeSimple\SoapBundle\Converter\DateTimeTypeConverter</parameter>
<parameter key="besimple.soap.converter.date.class">BeSimple\SoapBundle\Converter\DateTypeConverter</parameter>
<parameter key="besimple.soap.converter.collection.class">BeSimple\SoapCommon\Converter\TypeConverterCollection</parameter>
<parameter key="besimple.soap.converter.date_time.class">BeSimple\SoapCommon\Converter\DateTimeTypeConverter</parameter>
<parameter key="besimple.soap.converter.date.class">BeSimple\SoapCommon\Converter\DateTypeConverter</parameter>
</parameters>
<services>
<service id="besimple.soap.converter.repository" class="%besimple.soap.converter.repository.class%" />
<service id="besimple.soap.converter.collection" class="%besimple.soap.converter.collection.class%" />
<service id="besimple.soap.converter.date_time" class="%besimple.soap.converter.date_time.class%" public="false">
<tag name="besimple.soap.converter" />

21
Resources/config/soap.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="besimple.soap.cache.class">BeSimple\SoapBundle\Cache</parameter>
<parameter key="besimple.soap.cache.directory">%kernel.cache_dir%/besimple/soap</parameter>
</parameters>
<services>
<service id="besimple.soap.cache" class="%besimple.soap.cache.class%">
<argument>%kernel.debug%</argument>
<argument>%besimple.soap.cache.type%</argument>
<argument>%besimple.soap.cache.directory%</argument>
<argument>%besimple.soap.cache.lifetime%</argument>
<argument>%besimple.soap.cache.limit%</argument>
</service>
</services>
</container>

View File

@ -15,6 +15,7 @@
<parameter key="besimple.soap.binder.response.documentwrapped.class">BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedResponseMessageBinder</parameter>
<parameter key="besimple.soap.definition.dumper.wsdl.rpcliteral.class">BeSimple\SoapBundle\ServiceDefinition\Dumper\WsdlDumper</parameter>
<parameter key="besimple.soap.type.repository.class">BeSimple\SoapBundle\Converter\TypeRepository</parameter>
<parameter key="besimple.soap.server.classmap.class">BeSimple\SoapCommon\Classmap</parameter>
</parameters>
<services>
@ -23,39 +24,48 @@
<service id="besimple.soap.context.rpcliteral" class="%besimple.soap.context.class%" abstract="true">
<argument type="service" id="besimple.soap.definition.loader" />
<argument type="service" id="besimple.soap.definition.dumper.wsdl.rpcliteral" />
<argument type="service" id="besimple.soap.server.classmap" />
<argument type="service" id="besimple.soap.type.repository" />
<argument type="service" id="besimple.soap.converter.repository" />
<argument type="service" id="besimple.soap.converter.collection" />
<argument type="collection">
<argument key="cache_dir">%besimple.soap.cache_dir%</argument>
<argument key="debug">%kernel.debug%</argument>
<argument key="cache_type">null</argument>
<argument key="binder_request_header_class">%besimple.soap.binder.request_header.rpcliteral.class%</argument>
<argument key="binder_request_class">%besimple.soap.binder.request.rpcliteral.class%</argument>
<argument key="binder_response_class">%besimple.soap.binder.response.rpcliteral.class%</argument>
</argument>
<argument type="service" id="besimple.soap.cache" />
</service>
<service id="besimple.soap.context.documentwrapped" class="%besimple.soap.context.class%" abstract="true">
<argument type="service" id="besimple.soap.definition.loader" />
<argument type="service" id="besimple.soap.definition.dumper.wsdl.documentwrapped" />
<argument type="service" id="besimple.soap.server.classmap" />
<argument type="service" id="besimple.soap.type.repository" />
<argument type="service" id="besimple.soap.converter.repository" />
<argument type="service" id="besimple.soap.converter.collection" />
<argument type="collection">
<argument key="cache_dir">%besimple.soap.cache_dir%</argument>
<argument key="debug">%kernel.debug%</argument>
<argument key="cache_type">null</argument>
<argument key="binder_request_header_class">%besimple.soap.binder.request_header.documentwrapped.class%</argument>
<argument key="binder_request_class">%besimple.soap.binder.request.documentwrapped.class%</argument>
<argument key="binder_response_class">%besimple.soap.binder.response.documentwrapped.class%</argument>
</argument>
<argument type="service" id="besimple.soap.cache" />
</service>
<service id="besimple.soap.definition.dumper.wsdl.rpcliteral" class="%besimple.soap.definition.dumper.wsdl.rpcliteral.class%">
<argument type="service" id="besimple.soap.definition.loader.annot_complextype" />
<argument type="service" id="besimple.soap.server.classmap" />
<argument type="service" id="besimple.soap.type.repository" />
<argument type="collection">
<argument key="stylesheet">%besimple.soap.definition.dumper.options.stylesheet%</argument>
</argument>
</service>
<service id="besimple.soap.server.classmap" class="%besimple.soap.server.classmap.class%" public="false" />
<service id="besimple.soap.type.repository" class="%besimple.soap.type.repository.class%">
<call method="addXmlNamespace">
<argument>xsd</argument>

26
Resources/doc/cache.rst Normal file
View File

@ -0,0 +1,26 @@
Cache
=====
Configuration
-------------
Configure the cache of PHP Soap WSDL in your config file:
.. code-block:: yaml
# app/config/config.yml
be_simple_soap:
cache:
type: disk
lifetime: 86400
limit: 5
The cache type can be: **none**, **disk** (default value), **memory**, **disk_memory**.
The lifetime in seconds of a WSDL file in the cache (**86400 is the default value by PHP**).
The limit is the maximum number of in-memory cached WSDL files (**5 is the default value by PHP**).
If you want more information you can visit the following page `PHP Soap runtime configuration`_.
.. _`PHP Soap runtime configuration`: http://www.php.net/manual/en/soap.configuration.php

View File

@ -1,9 +1,11 @@
==================
BeSimpleSoapBundle
==================
The BeSimpleSoapBundle is a Symfony2 bundle to build WSDL and SOAP based web services.
It is based on the `ckWebServicePlugin`_ for symfony.
---------------
Reference Guide
---------------
@ -11,19 +13,25 @@ Reference Guide
:maxdepth: 1
:numbered:
reference/installation
reference/configuration
reference/types
installation
cache
Tutorial
--------
----------
SoapServer
----------
.. toctree::
:maxdepth: 1
:numbered:
tutorial/array
tutorial/complex_type
tutorial/header
soapserver/configuration
soapserver/types
soapserver/tutorials
----------
SoapClient
----------
Coming soon.
.. _`ckWebServicePlugin`: http://www.symfony-project.org/plugins/ckWebServicePlugin

View File

@ -4,8 +4,39 @@ Installation
Requirements
------------
Install and enable PHP's SOAP extension
Download `Zend\\Soap`_ and `Zend\\Mime`_ or add in `deps` file
Install and enable PHP's SOAP extension.
Download `BeSimple\\SoapCommon`_ and `BeSimple\\SoapServer`_ (only for the server part) and/or `BeSimple\\SoapClient`_ (only for ther client part).
.. code-block:: ini
; deps file
[BeSimple\SoapCommon]
git=http://github.com/BeSimple/SoapCommon
target=/besimple-soapcommon
[BeSimple\SoapClient]
git=http://github.com/BeSimple/SoapClient
target=/besimple-soapclient
[BeSimple\SoapServer]
git=http://github.com/BeSimple/SoapServer
target=/besimple-soapserver
Add `BeSimple` libraries in autoload.php
.. code-block:: php
// app/autoload.php
$loader->registerNamespaces(array(
'BeSimple\\SoapCommon' => __DIR__.'/../vendor/besimple-soapcommon',
'BeSimple\\SoapServer' => __DIR__.'/../vendor/besimple-soapserver',
'BeSimple\\SoapClient' => __DIR__.'/../vendor/besimple-soapclient',
// your other namespaces
));
Download `Zend\\Soap`_ and `Zend\\Mime`_ or add in `deps` file. `Zend` library is required only for the server part.
.. code-block:: ini
@ -67,4 +98,7 @@ Add `BeSimpleSoapBundle` in your Kernel class
.. _`Zend\\Soap`: http://github.com/BeSimple/zend-soap
.. _`Zend\\Mime`: http://github.com/BeSimple/zend-mime
.. _`BeSimple\\SoapCommon`: http://github.com/BeSimple/BeSimpleSoapCommon
.. _`BeSimple\\SoapServer`: http://github.com/BeSimple/BeSimpleSoapServer
.. _`BeSimple\\SoapClient`: http://github.com/BeSimple/BeSimpleSoapClient
.. _`Download`: http://github.com/BeSimple/BeSimpleSoapBundle

View File

@ -50,4 +50,9 @@ Annotations for Controllers
{
return $this->container->get('besimple.soap.response')->setReturnValue(sprintf('Hello %s!', $name));
}
}
}
Get your WSDL
-------------
To access your WSDL go to the following address: http://localhost/app_dev.php/ws/DemoApi?wsdl

View File

@ -0,0 +1,9 @@
Tutorials
=========
.. toctree::
:maxdepth: 1
tutorial/array
tutorial/complex_type
tutorial/header

View File

@ -18,21 +18,25 @@ use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
use BeSimple\SoapBundle\Util\Assert;
use BeSimple\SoapBundle\Util\QName;
use BeSimple\SoapCommon\Classmap;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class WsdlDumper implements DumperInterface
{
private $loader;
private $classmap;
private $typeRepository;
private $options;
private $wsdl;
private $definition;
public function __construct(AnnotationComplexTypeLoader $loader, TypeRepository $typeRepository, array $options)
public function __construct(AnnotationComplexTypeLoader $loader, Classmap $classmap, TypeRepository $typeRepository, array $options)
{
$this->loader = $loader;
$this->classmap = $classmap;
$this->typeRepository = $typeRepository;
$this->options = $options;
}
@ -42,7 +46,7 @@ class WsdlDumper implements DumperInterface
Assert::thatArgumentNotNull('definition', $definition);
$this->definition = $definition;
$this->wsdl = new Wsdl($this->typeRepository, $definition->getName(), $definition->getNamespace(), new WsdlTypeStrategy($this->loader, $definition));
$this->wsdl = new Wsdl($this->typeRepository, $definition->getName(), $definition->getNamespace(), new WsdlTypeStrategy($this->loader, $this->classmap, $definition));
$port = $this->wsdl->addPortType($this->getPortTypeName());
$binding = $this->wsdl->addBinding($this->getBindingName(), $this->qualify($this->getPortTypeName()));

View File

@ -15,6 +15,8 @@ use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
use BeSimple\SoapBundle\ServiceDefinition\Strategy\ComplexType;
use BeSimple\SoapBundle\Util\String;
use BeSimple\SoapCommon\Classmap;
use Zend\Soap\Exception;
use Zend\Soap\Wsdl as BaseWsdl;
use Zend\Soap\Wsdl\Strategy;
@ -30,14 +32,16 @@ class WsdlTypeStrategy implements Strategy
private $context;
private $loader;
private $classmap;
private $definition;
private $typeStrategy;
private $arrayStrategy;
public function __construct(AnnotationComplexTypeLoader $loader, ServiceDefinition $definition)
public function __construct(AnnotationComplexTypeLoader $loader, Classmap $classmap, ServiceDefinition $definition)
{
$this->loader = $loader;
$this->classmap = $classmap;
$this->definition = $definition;
}
@ -86,7 +90,7 @@ class WsdlTypeStrategy implements Strategy
private function getTypeStrategy()
{
if (!$this->typeStrategy) {
$this->typeStrategy = new ComplexType($this->loader, $this->definition);
$this->typeStrategy = new ComplexType($this->loader, $this->classmap, $this->definition);
$this->typeStrategy->setContext($this->context);
}

View File

@ -12,6 +12,7 @@ namespace BeSimple\SoapBundle\ServiceDefinition\Strategy;
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
use BeSimple\SoapCommon\Classmap;
use Zend\Soap\Wsdl;
use Zend\Soap\Wsdl\Strategy\AbstractStrategy;
@ -21,11 +22,13 @@ use Zend\Soap\Wsdl\Strategy\AbstractStrategy;
class ComplexType extends AbstractStrategy
{
private $loader;
private $classmap;
private $definition;
public function __construct(AnnotationComplexTypeLoader $loader, $definition)
public function __construct(AnnotationComplexTypeLoader $loader, Classmap $classmap, $definition)
{
$this->loader = $loader;
$this->classmap = $classmap;
$this->definition = $definition;
}
@ -50,6 +53,8 @@ class ComplexType extends AbstractStrategy
$soapTypeName = Wsdl::translateType($type);
$soapType = 'tns:'.$soapTypeName;
$this->classmap->add($soapTypeName, $type);
// Register type here to avoid recursion
$this->getContext()->addType($type, $soapType);

View File

@ -0,0 +1,77 @@
<?php
namespace BeSimple\SoapBundle\Soap;
use BeSimple\SoapCommon\Classmap;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapClient\SoapClientBuilder as BaseSoapClientBuilder;
class SoapClientBuilder extends BaseSoapClientBuilder
{
protected $soapClient;
public function __construct($wsdl, array $options, Classmap $classmap = null, TypeConverterCollection $converters = null)
{
parent::__construct();
$this->checkOptions($options);
$this
->withWsdl($wsdl)
->withTrace($options['debug'])
;
if (isset($options['user_agent'])) {
$this->withUserAgent($options['user_agent']);
}
if (isset($options['cache_type'])) {
$this->withWsdlCache($options['cache_type']);
}
if ($classmap) {
$this->withClassmap($classmap);
}
if ($converters) {
$this->withTypeConverters($converters);
}
}
public function build()
{
if (!$this->soapClient) {
$this->soapClient = parent::build();
}
return $this->soapClient;
}
protected function checkOptions(array $options)
{
$checkOptions = array(
'debug' => false,
'cache_type' => null,
'exceptions' => true,
'user_agent' => 'BeSimpleSoap',
);
// check option names and live merge, if errors are encountered Exception will be thrown
$invalid = array();
$isInvalid = false;
foreach ($options as $key => $value) {
if (!array_key_exists($key, $checkOptions)) {
$isInvalid = true;
$invalid[] = $key;
}
}
if ($isInvalid) {
throw new \InvalidArgumentException(sprintf(
'The "%s" class does not support the following options: "%s".',
get_class($this),
implode('\', \'', $invalid)
));
}
}
}

View File

@ -1,77 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Soap;
use BeSimple\SoapBundle\Converter\ConverterRepository;
use Zend\Soap\Wsdl;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class SoapServerFactory
{
private $wsdlFile;
private $classmap;
private $converters;
private $debug;
public function __construct($wsdlFile, array $classmap, ConverterRepository $converters, $debug = false)
{
$this->wsdlFile = $wsdlFile;
$this->classmap = $this->fixSoapServerClassmap($classmap);
$this->converters = $converters;
$this->debug = $debug;
}
public function create($request, $response)
{
return new \SoapServer(
$this->wsdlFile,
array(
'classmap' => $this->classmap,
'typemap' => $this->createSoapServerTypemap($request, $response),
'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
'cache_wsdl' => $this->debug ? WSDL_CACHE_NONE : WSDL_CACHE_DISK,
)
);
}
private function createSoapServerTypemap($request, $response)
{
$typemap = array();
foreach($this->converters->getTypeConverters() as $typeConverter) {
$typemap[] = 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 $typemap;
}
private function fixSoapServerClassmap($classmap)
{
$classmapFixed = array();
foreach ($classmap as $class => $definition) {
$classmapFixed[Wsdl::translateType($class)] = $class;
}
return $classmapFixed;
}
}

View File

@ -1,43 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Tests\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\Converter\DateTimeTypeConverter;
/**
* UnitTest for \BeSimple\SoapBundle\Converter\DateTimeTypeConverter.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
class DateTimeTypeConverterTest extends \PHPUnit_Framework_TestCase
{
public function testConvertXmlToPhp()
{
$converter = new DateTimeTypeConverter();
$dateXml = '<sometag>2002-10-10T12:00:00-05:00</sometag>';
$date = $converter->convertXmlToPhp(new SoapRequest(), $dateXml);
$this->assertEquals(new \DateTime('2002-10-10T12:00:00-05:00'), $date);
}
public function testConvertPhpToXml()
{
$converter = new DateTimeTypeConverter();
$date = new \DateTime('2002-10-10T12:00:00-05:00');
$dateXml = $converter->convertPhpToXml(new SoapResponse(), $date);
$this->assertEquals('<dateTime>2002-10-10T12:00:00-05:00</dateTime>', $dateXml);
}
}

View File

@ -1,41 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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 BeSimple\SoapBundle\Tests\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\Converter\DateTypeConverter;
/**
* UnitTest for \BeSimple\SoapBundle\Converter\DateTimeTypeConverter.
*/
class DateTypeConverterTest extends \PHPUnit_Framework_TestCase
{
public function testConvertXmlToPhp()
{
$converter = new DateTypeConverter();
$dateXml = '<sometag>2002-10-10</sometag>';
$date = $converter->convertXmlToPhp(new SoapRequest(), $dateXml);
$this->assertEquals(new \DateTime('2002-10-10'), $date);
}
public function testConvertPhpToXml()
{
$converter = new DateTypeConverter();
$date = new \DateTime('2002-10-10');
$dateXml = $converter->convertPhpToXml(new SoapResponse(), $date);
$this->assertEquals('<date>2002-10-10</date>', $dateXml);
}
}

View File

@ -10,12 +10,14 @@
namespace BeSimple\SoapBundle;
use BeSimple\SoapBundle\Converter\ConverterRepository;
use BeSimple\SoapBundle\Converter\TypeRepository;
use BeSimple\SoapBundle\ServiceBinding\MessageBinderInterface;
use BeSimple\SoapBundle\ServiceBinding\ServiceBinder;
use BeSimple\SoapBundle\ServiceDefinition\Dumper\DumperInterface;
use BeSimple\SoapBundle\Soap\SoapServerFactory;
use BeSimple\SoapCommon\Classmap;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapServer\SoapServerBuilder;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Loader\LoaderInterface;
@ -36,14 +38,16 @@ class WebServiceContext
private $serviceDefinition;
private $serviceBinder;
private $serverFactory;
private $serverBuilder;
public function __construct(LoaderInterface $loader, DumperInterface $dumper, TypeRepository $typeRepository, ConverterRepository $converterRepository, array $options) {
public function __construct(LoaderInterface $loader, DumperInterface $dumper, Classmap $classmap, TypeRepository $typeRepository, TypeConverterCollection $converters, array $options) {
$this->loader = $loader;
$this->wsdlFileDumper = $dumper;
$this->typeRepository = $typeRepository;
$this->converterRepository = $converterRepository;
$this->classmap = $classmap;
$this->typeRepository = $typeRepository;
$this->converters = $converters;
$this->options = $options;
}
@ -96,17 +100,22 @@ class WebServiceContext
return $this->serviceBinder;
}
public function getServerFactory()
public function getServerBuilder()
{
if (null === $this->serverFactory) {
$this->serverFactory = new SoapServerFactory(
$this->getWsdlFile(),
$this->serviceDefinition->getDefinitionComplexTypes(),
$this->converterRepository,
$this->options['debug']
);
if (null === $this->serverBuilder) {
$this->serverBuilder = SoapServerBuilder::createWithDefaults()
->withWsdl($this->getWsdlFile())
->withClassmap($this->classmap)
->withTypeConverters($this->converters)
;
if (!$this->options['debug']) {
$this->serverBuilder->withWsdlCacheNone();
} elseif (null !== $this->options['cache_type']) {
$this->serverBuilder->withWsdlCache($this->options['cache_type']);
}
}
return $this->serverFactory;
return $this->serverBuilder;
}
}