Add 'src/BeSimple/SoapBundle/' from commit 'e99f707b105c0a0472260d8d42a5a14a7fb7a211'
git-subtree-dir: src/BeSimple/SoapBundle git-subtree-mainline:9a8d23fa23
git-subtree-split:e99f707b10
This commit is contained in:
@ -0,0 +1,56 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class ComplexType extends Configuration
|
||||
{
|
||||
private $name;
|
||||
private $value;
|
||||
private $isNillable = false;
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function isNillable()
|
||||
{
|
||||
return $this->isNillable;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function setNillable($isNillable)
|
||||
{
|
||||
$this->isNillable = (bool) $isNillable;
|
||||
}
|
||||
|
||||
public function getAliasName()
|
||||
{
|
||||
return 'complextype';
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* Based on \Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
abstract class Configuration implements ConfigurationInterface
|
||||
{
|
||||
public function __construct(array $values)
|
||||
{
|
||||
foreach ($values as $k => $v) {
|
||||
if (!method_exists($this, $name = 'set'.$k)) {
|
||||
throw new \RuntimeException(sprintf('Unknown key "%s" for annotation "@%s".', $k, get_class($this)));
|
||||
}
|
||||
|
||||
$this->$name($v);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* Based on \Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
interface ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* Returns the alias name for an annotated configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getAliasName();
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Header extends Param
|
||||
{
|
||||
public function getAliasName()
|
||||
{
|
||||
return 'header';
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Method extends Configuration
|
||||
{
|
||||
private $value;
|
||||
private $service;
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getService()
|
||||
{
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function setService($service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function getAliasName()
|
||||
{
|
||||
return 'method';
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Param extends Configuration implements TypedElementInterface
|
||||
{
|
||||
private $value;
|
||||
private $phpType;
|
||||
private $xmlType;
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getPhpType()
|
||||
{
|
||||
return $this->phpType;
|
||||
}
|
||||
|
||||
public function getXmlType()
|
||||
{
|
||||
return $this->xmlType;
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function setPhpType($phpType)
|
||||
{
|
||||
$this->phpType = $phpType;
|
||||
}
|
||||
|
||||
public function setXmlType($xmlType)
|
||||
{
|
||||
$this->xmlType = $xmlType;
|
||||
}
|
||||
|
||||
public function getAliasName()
|
||||
{
|
||||
return 'param';
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
*/
|
||||
class Result extends Configuration implements TypedElementInterface
|
||||
{
|
||||
private $phpType;
|
||||
private $xmlType;
|
||||
|
||||
public function getPhpType()
|
||||
{
|
||||
return $this->phpType;
|
||||
}
|
||||
|
||||
public function getXmlType()
|
||||
{
|
||||
return $this->xmlType;
|
||||
}
|
||||
|
||||
public function setPhpType($phpType)
|
||||
{
|
||||
$this->phpType = $phpType;
|
||||
}
|
||||
|
||||
public function setXmlType($xmlType)
|
||||
{
|
||||
$this->xmlType = $xmlType;
|
||||
}
|
||||
|
||||
public function getAliasName()
|
||||
{
|
||||
return 'result';
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?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\ServiceDefinition\Annotation;
|
||||
|
||||
interface TypedElementInterface
|
||||
{
|
||||
function getPhpType();
|
||||
function getXmlType();
|
||||
function setPhpType($phpType);
|
||||
function setXmlType($xmlType);
|
||||
}
|
43
src/BeSimple/SoapBundle/ServiceDefinition/Argument.php
Normal file
43
src/BeSimple/SoapBundle/ServiceDefinition/Argument.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\ServiceDefinition;
|
||||
|
||||
class Argument
|
||||
{
|
||||
private $name;
|
||||
private $type;
|
||||
|
||||
public function __construct($name = null, Type $type = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->setType($type);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType(Type $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
51
src/BeSimple/SoapBundle/ServiceDefinition/ComplexType.php
Normal file
51
src/BeSimple/SoapBundle/ServiceDefinition/ComplexType.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?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\ServiceDefinition;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class ComplexType
|
||||
{
|
||||
private $name;
|
||||
private $value;
|
||||
private $isNillable = false;
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function isNillable()
|
||||
{
|
||||
return $this->isNillable;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function setNillable($isNillable)
|
||||
{
|
||||
$this->isNillable = (bool) $isNillable;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?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\ServiceDefinition\Dumper;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
|
||||
|
||||
interface DumperInterface
|
||||
{
|
||||
function dumpServiceDefinition(ServiceDefinition $definition, $endpoint);
|
||||
}
|
78
src/BeSimple/SoapBundle/ServiceDefinition/Dumper/Wsdl.php
Normal file
78
src/BeSimple/SoapBundle/ServiceDefinition/Dumper/Wsdl.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?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\ServiceDefinition\Dumper;
|
||||
|
||||
use BeSimple\SoapBundle\Converter\TypeRepository;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Type;
|
||||
use Zend\Soap\Wsdl as BaseWsdl;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class Wsdl extends BaseWsdl
|
||||
{
|
||||
private $typeRepository;
|
||||
|
||||
public function __construct(TypeRepository $typeRepository, $name, $uri, $strategy = true)
|
||||
{
|
||||
$this->typeRepository = $typeRepository;
|
||||
|
||||
parent::__construct($name, $uri, $strategy);
|
||||
}
|
||||
|
||||
public function getType($type)
|
||||
{
|
||||
if ($type instanceof Type) {
|
||||
$xmlType = $type->getXmlType();
|
||||
} else {
|
||||
$xmlType = $this->typeRepository->getXmlTypeMapping($type);
|
||||
}
|
||||
|
||||
return $xmlType ?: $this->addComplexType($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate PHP type into WSDL QName
|
||||
*
|
||||
* @param string $type
|
||||
* @return string QName
|
||||
*/
|
||||
public function translateType($type)
|
||||
{
|
||||
if (isset($this->classMap[$type])) {
|
||||
return $this->classMap[$type];
|
||||
}
|
||||
|
||||
if ($type[0] == '\\') {
|
||||
$type = substr($type, 1);
|
||||
}
|
||||
|
||||
return str_replace('\\', '.', $type);
|
||||
}
|
||||
|
||||
public function addBindingOperationHeader(\DOMElement $bindingOperation, array $headers, array $baseBinding)
|
||||
{
|
||||
foreach ($headers as $header) {
|
||||
$inputNode = $bindingOperation->getElementsByTagName('input')->item(0);
|
||||
|
||||
$headerNode = $this->toDomDocument()->createElement('soap:header');
|
||||
$headerNode->setAttribute('part', $header);
|
||||
|
||||
foreach ($baseBinding as $name => $value) {
|
||||
$headerNode->setAttribute($name, $value);
|
||||
}
|
||||
|
||||
$inputNode->appendChild($headerNode);
|
||||
}
|
||||
|
||||
return $bindingOperation;
|
||||
}
|
||||
}
|
177
src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlDumper.php
Normal file
177
src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlDumper.php
Normal file
@ -0,0 +1,177 @@
|
||||
<?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\ServiceDefinition\Dumper;
|
||||
|
||||
use BeSimple\SoapBundle\Converter\TypeRepository;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Method;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Type;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
|
||||
use BeSimple\SoapBundle\Util\Assert;
|
||||
use BeSimple\SoapBundle\Util\QName;
|
||||
|
||||
/**
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
*/
|
||||
class WsdlDumper implements DumperInterface
|
||||
{
|
||||
private $loader;
|
||||
private $typeRepository;
|
||||
private $options;
|
||||
|
||||
private $wsdl;
|
||||
private $definition;
|
||||
|
||||
public function __construct(AnnotationComplexTypeLoader $loader, TypeRepository $typeRepository, array $options)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->typeRepository = $typeRepository;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function dumpServiceDefinition(ServiceDefinition $definition, $endpoint)
|
||||
{
|
||||
Assert::thatArgumentNotNull('definition', $definition);
|
||||
|
||||
$this->definition = $definition;
|
||||
$this->wsdl = new Wsdl($this->typeRepository, $definition->getName(), $definition->getNamespace(), new WsdlTypeStrategy($this->loader, $definition));
|
||||
$port = $this->wsdl->addPortType($this->getPortTypeName());
|
||||
$binding = $this->wsdl->addBinding($this->getBindingName(), $this->qualify($this->getPortTypeName()));
|
||||
|
||||
$this->wsdl->addSoapBinding($binding, 'rpc');
|
||||
$this->wsdl->addService($this->getServiceName(), $this->getPortName(), $this->qualify($this->getBindingName()), $endpoint);
|
||||
|
||||
foreach ($definition->getMethods() as $method) {
|
||||
$requestHeaderParts =
|
||||
$requestParts =
|
||||
$responseParts = array();
|
||||
|
||||
foreach ($method->getHeaders() as $header) {
|
||||
$requestHeaderParts[$header->getName()] = $this->wsdl->getType($header->getType()->getPhpType());
|
||||
}
|
||||
|
||||
foreach ($method->getArguments() as $argument) {
|
||||
$requestParts[$argument->getName()] = $this->wsdl->getType($argument->getType()->getPhpType());
|
||||
}
|
||||
|
||||
if ($method->getReturn() !== null) {
|
||||
$responseParts['return'] = $this->wsdl->getType($method->getReturn()->getPhpType());
|
||||
}
|
||||
|
||||
if (!empty($requestHeaderParts)) {
|
||||
$this->wsdl->addMessage($this->getRequestHeaderMessageName($method), $requestHeaderParts);
|
||||
}
|
||||
$this->wsdl->addMessage($this->getRequestMessageName($method), $requestParts);
|
||||
$this->wsdl->addMessage($this->getResponseMessageName($method), $responseParts);
|
||||
|
||||
$portOperation = $this->wsdl->addPortOperation(
|
||||
$port,
|
||||
$method->getName(),
|
||||
$this->qualify($this->getRequestMessageName($method)),
|
||||
$this->qualify($this->getResponseMessageName($method))
|
||||
);
|
||||
|
||||
$baseBinding =
|
||||
$inputBinding =
|
||||
$outputBinding = array(
|
||||
'use' => 'literal',
|
||||
'namespace' => $definition->getNamespace(),
|
||||
'encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
);
|
||||
|
||||
if (!empty($requestParts)) {
|
||||
$portOperation->setAttribute('parameterOrder', implode(' ', array_keys($requestParts)));
|
||||
|
||||
$inputBinding['parts'] = implode(' ', array_keys($requestParts));
|
||||
}
|
||||
|
||||
if (!empty($responseParts)) {
|
||||
$outputBinding['parts'] = implode(' ', array_keys($responseParts));
|
||||
}
|
||||
|
||||
$bindingOperation = $this->wsdl->addBindingOperation(
|
||||
$binding,
|
||||
$method->getName(),
|
||||
$inputBinding,
|
||||
$outputBinding
|
||||
);
|
||||
$bindingOperation = $this->wsdl->addBindingOperationHeader(
|
||||
$bindingOperation,
|
||||
array_keys($requestHeaderParts),
|
||||
array_merge(array('message' => $this->qualify($this->getRequestHeaderMessageName($method))), $baseBinding)
|
||||
);
|
||||
|
||||
$this->wsdl->addSoapOperation($bindingOperation, $this->getSoapOperationName($method));
|
||||
}
|
||||
|
||||
$this->definition = null;
|
||||
|
||||
$dom = $this->wsdl->toDomDocument();
|
||||
$dom->formatOutput = true;
|
||||
|
||||
if ($this->options['stylesheet']) {
|
||||
$stylesheet = $dom->createProcessingInstruction('xml-stylesheet', sprintf('type="text/xsl" href="%s"', $this->options['stylesheet']));
|
||||
|
||||
$dom->insertBefore($stylesheet, $dom->documentElement);
|
||||
}
|
||||
|
||||
return $this->wsdl->toXml();
|
||||
}
|
||||
|
||||
protected function qualify($name, $namespace = null)
|
||||
{
|
||||
if($namespace === null) {
|
||||
$namespace = $this->definition->getNamespace();
|
||||
}
|
||||
|
||||
return $this->wsdl->toDomDocument()->lookupPrefix($namespace).':'.$name;
|
||||
}
|
||||
|
||||
protected function getPortName()
|
||||
{
|
||||
return $this->definition->getName().'Port';
|
||||
}
|
||||
|
||||
protected function getPortTypeName()
|
||||
{
|
||||
return $this->definition->getName().'PortType';
|
||||
}
|
||||
|
||||
protected function getBindingName()
|
||||
{
|
||||
return $this->definition->getName().'Binding';
|
||||
}
|
||||
|
||||
protected function getServiceName()
|
||||
{
|
||||
return $this->definition->getName().'Service';
|
||||
}
|
||||
|
||||
protected function getRequestHeaderMessageName(Method $method)
|
||||
{
|
||||
return $method->getName().'Header';
|
||||
}
|
||||
|
||||
protected function getRequestMessageName(Method $method)
|
||||
{
|
||||
return $method->getName().'Request';
|
||||
}
|
||||
|
||||
protected function getResponseMessageName(Method $method)
|
||||
{
|
||||
return $method->getName().'Response';
|
||||
}
|
||||
|
||||
protected function getSoapOperationName(Method $method)
|
||||
{
|
||||
return $this->definition->getNamespace().$method->getName();
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
<?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\ServiceDefinition\Dumper;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Strategy\ComplexType;
|
||||
use BeSimple\SoapBundle\Util\String;
|
||||
|
||||
use Zend\Soap\Exception;
|
||||
use Zend\Soap\Wsdl as BaseWsdl;
|
||||
use Zend\Soap\Wsdl\ComplexTypeStrategy\ComplexTypeStrategyInterface;
|
||||
use Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence;
|
||||
|
||||
class WsdlTypeStrategy implements ComplexTypeStrategyInterface
|
||||
{
|
||||
/**
|
||||
* Context WSDL file
|
||||
*
|
||||
* @var \Zend\Soap\Wsdl|null
|
||||
*/
|
||||
private $context;
|
||||
|
||||
private $loader;
|
||||
private $definition;
|
||||
|
||||
private $typeStrategy;
|
||||
private $arrayStrategy;
|
||||
|
||||
public function __construct(AnnotationComplexTypeLoader $loader, ServiceDefinition $definition)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method accepts the current WSDL context file.
|
||||
*
|
||||
* @param \Zend\Soap\Wsdl $context
|
||||
*/
|
||||
public function setContext(BaseWsdl $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a complex type based on a strategy
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return string XSD type
|
||||
*
|
||||
* @throws \Zend\Soap\WsdlException
|
||||
*/
|
||||
public function addComplexType($type)
|
||||
{
|
||||
if (!$this->context) {
|
||||
throw new \LogicException(sprintf('Cannot add complex type "%s", no context is set for this composite strategy.', $type));
|
||||
}
|
||||
|
||||
$strategy = String::endsWith($type, '[]') ? $this->getArrayStrategy() : $this->getTypeStrategy();
|
||||
|
||||
return $strategy->addComplexType($type);
|
||||
}
|
||||
|
||||
private function getArrayStrategy()
|
||||
{
|
||||
if (!$this->arrayStrategy) {
|
||||
$this->arrayStrategy = new ArrayOfTypeSequence();
|
||||
$this->arrayStrategy->setContext($this->context);
|
||||
}
|
||||
|
||||
return $this->arrayStrategy;
|
||||
}
|
||||
|
||||
private function getTypeStrategy()
|
||||
{
|
||||
if (!$this->typeStrategy) {
|
||||
$this->typeStrategy = new ComplexType($this->loader, $this->definition);
|
||||
$this->typeStrategy->setContext($this->context);
|
||||
}
|
||||
|
||||
return $this->typeStrategy;
|
||||
}
|
||||
}
|
43
src/BeSimple/SoapBundle/ServiceDefinition/Header.php
Normal file
43
src/BeSimple/SoapBundle/ServiceDefinition/Header.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\ServiceDefinition;
|
||||
|
||||
class Header
|
||||
{
|
||||
private $name;
|
||||
private $type;
|
||||
|
||||
public function __construct($name = null, Type $type = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->setType($type);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
<?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\ServiceDefinition\Loader;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition as Definition;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\Config\Loader\LoaderResolverInterface;
|
||||
|
||||
/**
|
||||
* AnnotationClassLoader loads ServiceDefinition from a PHP class and its methods.
|
||||
*
|
||||
* Based on \Symfony\Component\Routing\Loader\AnnotationClassLoader
|
||||
*
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
*/
|
||||
class AnnotationClassLoader implements LoaderInterface
|
||||
{
|
||||
protected $reader;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Doctrine\Common\Annotations\Reader $reader
|
||||
*/
|
||||
public function __construct(Reader $reader)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a ServiceDefinition from annotations from a class.
|
||||
*
|
||||
* @param string $class A class name
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return \BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition A ServiceDefinition instance
|
||||
*
|
||||
* @throws \InvalidArgumentException When route can't be parsed
|
||||
*/
|
||||
public function load($class, $type = null)
|
||||
{
|
||||
if (!class_exists($class)) {
|
||||
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($class);
|
||||
$definition = new Definition\ServiceDefinition();
|
||||
|
||||
$serviceMethodHeaders = array();
|
||||
foreach ($this->reader->getClassAnnotations($class) as $annotation) {
|
||||
if ($annotation instanceof Annotation\Header) {
|
||||
$serviceMethodHeaders[$annotation->getValue()] = $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($class->getMethods() as $method) {
|
||||
$serviceArguments =
|
||||
$serviceHeaders = array();
|
||||
$serviceMethod =
|
||||
$serviceReturn = null;
|
||||
|
||||
foreach ($serviceMethodHeaders as $annotation) {
|
||||
$serviceHeaders[$annotation->getValue()] = new Definition\Header(
|
||||
$annotation->getValue(),
|
||||
$this->getArgumentType($method, $annotation)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->reader->getMethodAnnotations($method) as $annotation) {
|
||||
if ($annotation instanceof Annotation\Header) {
|
||||
$serviceHeaders[$annotation->getValue()] = new Definition\Header(
|
||||
$annotation->getValue(),
|
||||
$this->getArgumentType($method, $annotation)
|
||||
);
|
||||
} elseif ($annotation instanceof Annotation\Param) {
|
||||
$serviceArguments[] = new Definition\Argument(
|
||||
$annotation->getValue(),
|
||||
$this->getArgumentType($method, $annotation)
|
||||
);
|
||||
} elseif ($annotation instanceof Annotation\Method) {
|
||||
if ($serviceMethod) {
|
||||
throw new \LogicException(sprintf('@Soap\Method defined twice for "%s".', $method->getName()));
|
||||
}
|
||||
|
||||
$serviceMethod = new Definition\Method(
|
||||
$annotation->getValue(),
|
||||
$this->getController($class, $method, $annotation)
|
||||
);
|
||||
} elseif ($annotation instanceof Annotation\Result) {
|
||||
if ($serviceReturn) {
|
||||
throw new \LogicException(sprintf('@Soap\Result defined twice for "%s".', $method->getName()));
|
||||
}
|
||||
|
||||
$serviceReturn = new Definition\Type($annotation->getPhpType(), $annotation->getXmlType());
|
||||
}
|
||||
}
|
||||
|
||||
if (!$serviceMethod && (!empty($serviceArguments) || $serviceReturn)) {
|
||||
throw new \LogicException(sprintf('@Soap\Method non-existent for "%s".', $method->getName()));
|
||||
}
|
||||
|
||||
if ($serviceMethod) {
|
||||
$serviceMethod->setArguments($serviceArguments);
|
||||
$serviceMethod->setHeaders($serviceHeaders);
|
||||
|
||||
if (!$serviceReturn) {
|
||||
throw new \LogicException(sprintf('@Soap\Result non-existent for "%s".', $method->getName()));
|
||||
}
|
||||
|
||||
$serviceMethod->setReturn($serviceReturn);
|
||||
|
||||
$definition->getMethods()->add($serviceMethod);
|
||||
}
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $method
|
||||
* @param \BeSimple\SoapBundle\ServiceDefinition\Annotation\Method $annotation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getController(\ReflectionClass $class, \ReflectionMethod $method, Annotation\Method $annotation)
|
||||
{
|
||||
if(null !== $annotation->getService()) {
|
||||
return $annotation->getService() . ':' . $method->name;
|
||||
} else {
|
||||
return $class->name . '::' . $method->name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod $method
|
||||
* @param \BeSimple\SoapBundle\ServiceDefinition\Annotation\Param $annotation
|
||||
*
|
||||
* @return \BeSimple\SoapBundle\ServiceDefinition\Type
|
||||
*/
|
||||
private function getArgumentType(\ReflectionMethod $method, Annotation\Param $annotation)
|
||||
{
|
||||
$phpType = $annotation->getPhpType();
|
||||
$xmlType = $annotation->getXmlType();
|
||||
|
||||
if (null === $phpType) {
|
||||
foreach ($method->getParameters() as $param) {
|
||||
if ($param->name === $annotation->getName()) {
|
||||
$phpType = $param->getClass()->name;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Definition\Type($phpType, $xmlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean True if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the loader resolver.
|
||||
*
|
||||
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
|
||||
*/
|
||||
public function setResolver(LoaderResolverInterface $resolver)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the loader resolver.
|
||||
*
|
||||
* @return LoaderResolverInterface A LoaderResolverInterface instance
|
||||
*/
|
||||
public function getResolver()
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<?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\ServiceDefinition\Loader;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition\ComplexType;
|
||||
use BeSimple\SoapBundle\Util\Collection;
|
||||
|
||||
/**
|
||||
* AnnotationComplexTypeLoader loads ServiceDefinition from a PHP class and its methods.
|
||||
*
|
||||
* Based on \Symfony\Component\Routing\Loader\AnnotationClassLoader
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class AnnotationComplexTypeLoader extends AnnotationClassLoader
|
||||
{
|
||||
private $complexTypeClass = 'BeSimple\SoapBundle\ServiceDefinition\Annotation\ComplexType';
|
||||
|
||||
/**
|
||||
* Loads a ServiceDefinition from annotations from a class.
|
||||
*
|
||||
* @param string $class A class name
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return ServiceDefinition A ServiceDefinition instance
|
||||
*
|
||||
* @throws \InvalidArgumentException When route can't be parsed
|
||||
*/
|
||||
public function load($class, $type = null)
|
||||
{
|
||||
if (!class_exists($class)) {
|
||||
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($class);
|
||||
$collection = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\ComplexType');
|
||||
|
||||
foreach ($class->getProperties() as $property) {
|
||||
$complexType = $this->reader->getPropertyAnnotation($property, $this->complexTypeClass);
|
||||
|
||||
if ($complexType) {
|
||||
$propertyComplexType = new ComplexType();
|
||||
$propertyComplexType->setValue($complexType->getValue());
|
||||
$propertyComplexType->setNillable($complexType->isNillable());
|
||||
$propertyComplexType->setName($property->getName());
|
||||
$collection->add($propertyComplexType);
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
<?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\ServiceDefinition\Loader;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* AnnotationFileLoader loads ServiceDefinition from annotations set
|
||||
* on a PHP class and its methods.
|
||||
*
|
||||
* Based on \Symfony\Component\Routing\Loader\AnnotationFileLoader
|
||||
*
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
*/
|
||||
class AnnotationFileLoader extends FileLoader
|
||||
{
|
||||
protected $loader;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param AnnotationClassLoader $loader An AnnotationClassLoader instance
|
||||
* @param string|array $paths A path or an array of paths where to look for resources
|
||||
*/
|
||||
public function __construct(FileLocator $locator, AnnotationClassLoader $loader, $paths = array())
|
||||
{
|
||||
if (!function_exists('token_get_all')) {
|
||||
throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.');
|
||||
}
|
||||
|
||||
parent::__construct($locator, $paths);
|
||||
|
||||
$this->loader = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads from annotations from a file.
|
||||
*
|
||||
* @param string $file A PHP file path
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return ServiceDefinition A ServiceDefinition instance
|
||||
*
|
||||
* @throws \InvalidArgumentException When the file does not exist
|
||||
*/
|
||||
public function load($file, $type = null)
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
if ($class = $this->findClass($path)) {
|
||||
return $definition = $this->loader->load($class, $type);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean True if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full class name for the first class in the file.
|
||||
*
|
||||
* @param string $file A PHP file path
|
||||
*
|
||||
* @return string|false Full class name if found, false otherwise
|
||||
*/
|
||||
protected function findClass($file)
|
||||
{
|
||||
$class = false;
|
||||
$namespace = false;
|
||||
$tokens = token_get_all(file_get_contents($file));
|
||||
while ($token = array_shift($tokens)) {
|
||||
if (!is_array($token)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true === $class && T_STRING === $token[0]) {
|
||||
return $namespace.'\\'.$token[1];
|
||||
}
|
||||
|
||||
if (true === $namespace && T_STRING === $token[0]) {
|
||||
$namespace = '';
|
||||
do {
|
||||
$namespace .= $token[1];
|
||||
$token = array_shift($tokens);
|
||||
} while ($tokens && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
|
||||
}
|
||||
|
||||
if (T_CLASS === $token[0]) {
|
||||
$class = true;
|
||||
}
|
||||
|
||||
if (T_NAMESPACE === $token[0]) {
|
||||
$namespace = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
<?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\ServiceDefinition\Loader;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Argument;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Header;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Method;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Type;
|
||||
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
|
||||
|
||||
use Symfony\Component\Config\Loader\FileLoader;
|
||||
|
||||
class XmlFileLoader extends FileLoader
|
||||
{
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
public function load($file, $type = null)
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
$xml = $this->parseFile($path);
|
||||
|
||||
$definition = new ServiceDefinition();
|
||||
$definition->setName((string) $xml['name']);
|
||||
$definition->setNamespace((string) $xml['namespace']);
|
||||
|
||||
foreach($xml->header as $header) {
|
||||
$definition->getHeaders()->add($this->parseHeader($header));
|
||||
}
|
||||
|
||||
foreach($xml->method as $method) {
|
||||
$definition->getMethods()->add($this->parseMethod($method));
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement $node
|
||||
*
|
||||
* @return \BeSimple\SoapBundle\ServiceDefinition\Header
|
||||
*/
|
||||
protected function parseHeader(\SimpleXMLElement $node)
|
||||
{
|
||||
return new Header((string)$node['name'], $this->parseType($node->type));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement $node
|
||||
*
|
||||
* @return \BeSimple\SoapBundle\ServiceDefinition\Method
|
||||
*/
|
||||
protected function parseMethod(\SimpleXMLElement $node)
|
||||
{
|
||||
$method = new Method((string)$node['name'], (string)$node['controller']);
|
||||
|
||||
foreach($node->argument as $argument) {
|
||||
$method->getArguments()->add($this->parseArgument($argument));
|
||||
}
|
||||
|
||||
$method->setReturn($this->parseType($node->return->type));
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement $node
|
||||
*
|
||||
* @return \BeSimple\SoapBundle\ServiceDefinition\Argument
|
||||
*/
|
||||
protected function parseArgument(\SimpleXMLElement $node)
|
||||
{
|
||||
$argument = new Argument((string)$node['name'], $this->parseType($node->type));
|
||||
|
||||
return $argument;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SimpleXMLElement $node
|
||||
*
|
||||
* @return \BeSimple\SoapBundle\ServiceDefinition\Type
|
||||
*/
|
||||
protected function parseType(\SimpleXMLElement $node)
|
||||
{
|
||||
$namespaces = $node->getDocNamespaces(true);
|
||||
$qname = explode(':', $node['xml-type'], 2);
|
||||
$xmlType = sprintf('{%s}%s', $namespaces[$qname[0]], $qname[1]);
|
||||
|
||||
return new Type((string)$node['php-type'], $xmlType, (string)$node['converter']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*
|
||||
* @return \SimpleXMLElement
|
||||
*/
|
||||
protected function parseFile($file)
|
||||
{
|
||||
$dom = new \DOMDocument();
|
||||
libxml_use_internal_errors(true);
|
||||
if (!$dom->load($file, LIBXML_COMPACT)) {
|
||||
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
|
||||
}
|
||||
if (!$dom->schemaValidate(__DIR__.'/schema/servicedefinition-1.0.xsd')) {
|
||||
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
|
||||
}
|
||||
$dom->validateOnParse = true;
|
||||
$dom->normalizeDocument();
|
||||
libxml_use_internal_errors(false);
|
||||
|
||||
return simplexml_import_dom($dom);
|
||||
}
|
||||
|
||||
protected function getXmlErrors()
|
||||
{
|
||||
$errors = array();
|
||||
foreach (libxml_get_errors() as $error) {
|
||||
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
|
||||
LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
|
||||
$error->code,
|
||||
trim($error->message),
|
||||
$error->file ? $error->file : 'n/a',
|
||||
$error->line,
|
||||
$error->column
|
||||
);
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors(false);
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://github.com/BeSimple/BeSimpleSoapBundle/servicedefinition/1.0/" xmlns:tns="http://github.com/BeSimple/BeSimpleSoapBundle/servicedefinition/1.0/" elementFormDefault="qualified">
|
||||
<element name="webservice" type="tns:WebserviceType" />
|
||||
<complexType name="WebserviceType">
|
||||
<sequence>
|
||||
<element name="header" type="tns:HeaderType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="method" type="tns:MethodType" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
<attribute name="name" type="string" use="required" />
|
||||
</complexType>
|
||||
|
||||
<complexType name="HeaderType">
|
||||
<complexContent>
|
||||
<extension base="tns:TransferObjectType">
|
||||
<sequence>
|
||||
<element name="exception" type="tns:ExceptionType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
<attribute name="name" type="ID" use="required" />
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
<complexType name="HeaderRefType">
|
||||
<attribute name="name" type="IDREF" />
|
||||
<attribute name="direction">
|
||||
<simpleType>
|
||||
<restriction base="string">
|
||||
<enumeration value="in" />
|
||||
<enumeration value="out" />
|
||||
<enumeration value="inout" />
|
||||
</restriction>
|
||||
</simpleType>
|
||||
</attribute>
|
||||
</complexType>
|
||||
|
||||
<complexType name="MethodType">
|
||||
<sequence>
|
||||
<element name="exception" type="tns:ExceptionType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="header" type="tns:HeaderRefType" minOccurs="0" maxOccurs="unbounded" />
|
||||
|
||||
<element name="argument" type="tns:ArgumentType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="return" type="tns:ReturnType" minOccurs="0" maxOccurs="1" />
|
||||
</sequence>
|
||||
<attribute name="name" type="string" use="required" />
|
||||
<attribute name="controller" type="string" use="required" />
|
||||
</complexType>
|
||||
|
||||
<complexType name="TransferObjectType" abstract="true">
|
||||
<sequence>
|
||||
<element name="type" type="tns:TypeConversionType" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="ExceptionType">
|
||||
<complexContent>
|
||||
<extension base="tns:TransferObjectType">
|
||||
<attribute name="name" type="string" use="required" />
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
<complexType name="ArgumentType">
|
||||
<complexContent>
|
||||
<extension base="tns:TransferObjectType">
|
||||
<attribute name="name" type="string" use="required" />
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
<complexType name="ReturnType">
|
||||
<complexContent>
|
||||
<extension base="tns:TransferObjectType" />
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
<complexType name="TypeConversionType">
|
||||
<attribute name="php-type" type="string" use="required" />
|
||||
<attribute name="xml-type" type="QName" use="required" />
|
||||
<attribute name="converter" type="string" use="optional" />
|
||||
</complexType>
|
||||
</schema>
|
86
src/BeSimple/SoapBundle/ServiceDefinition/Method.php
Normal file
86
src/BeSimple/SoapBundle/ServiceDefinition/Method.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?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\ServiceDefinition;
|
||||
|
||||
use BeSimple\SoapBundle\Util\Collection;
|
||||
|
||||
class Method
|
||||
{
|
||||
private $name;
|
||||
private $controller;
|
||||
private $arguments;
|
||||
private $headers;
|
||||
private $return;
|
||||
|
||||
public function __construct($name = null, $controller = null, array $headers = array(), array $arguments = array(), Type $return = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->setController($controller);
|
||||
$this->setHeaders($headers);
|
||||
$this->setArguments($arguments);
|
||||
|
||||
if ($return) {
|
||||
$this->setReturn($return);
|
||||
}
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getController()
|
||||
{
|
||||
return $this->controller;
|
||||
}
|
||||
|
||||
public function setController($controller)
|
||||
{
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
public function setHeaders(array $headers)
|
||||
{
|
||||
$this->headers = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\Header');
|
||||
$this->headers->addAll($headers);
|
||||
}
|
||||
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\Argument');
|
||||
$this->arguments->addAll($arguments);
|
||||
}
|
||||
|
||||
public function getReturn()
|
||||
{
|
||||
return $this->return;
|
||||
}
|
||||
|
||||
public function setReturn(Type $return)
|
||||
{
|
||||
$this->return = $return;
|
||||
}
|
||||
}
|
140
src/BeSimple/SoapBundle/ServiceDefinition/ServiceDefinition.php
Normal file
140
src/BeSimple/SoapBundle/ServiceDefinition/ServiceDefinition.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?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\ServiceDefinition;
|
||||
|
||||
use BeSimple\SoapBundle\Util\Collection;
|
||||
use BeSimple\SoapCommon\Classmap;
|
||||
|
||||
class ServiceDefinition
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $namespace;
|
||||
|
||||
/**
|
||||
* @var \BeSimple\SoapBundle\Util\Collection
|
||||
*/
|
||||
private $methods;
|
||||
|
||||
/**
|
||||
* @var \BeSimple\SoapCommon\Classmap
|
||||
*/
|
||||
private $classmap;
|
||||
|
||||
private $complexTypes = array();
|
||||
|
||||
public function __construct($name = null, $namespace = null, array $methods = array(), Classmap $classmap = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
$this->setNamespace($namespace);
|
||||
|
||||
$this->methods = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\Method');
|
||||
$this->setMethods($methods);
|
||||
|
||||
$this->classmap = $classmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
*/
|
||||
public function setNamespace($namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \BeSimple\SoapBundle\Util\Collection
|
||||
*/
|
||||
public function getMethods()
|
||||
{
|
||||
return $this->methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $methods
|
||||
*/
|
||||
public function setMethods(array $methods)
|
||||
{
|
||||
$this->methods->addAll($methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAllTypes()
|
||||
{
|
||||
$types = array();
|
||||
|
||||
foreach ($this->methods as $method) {
|
||||
foreach ($method->getArguments() as $argument) {
|
||||
$types[] = $argument->getType();
|
||||
}
|
||||
|
||||
foreach ($method->getHeaders() as $header) {
|
||||
$types[] = $header->getType();
|
||||
}
|
||||
|
||||
$types[] = $method->getReturn();
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
public function getClassmap()
|
||||
{
|
||||
return $this->classmap ?: array();
|
||||
}
|
||||
|
||||
public function setClassmap(Classmap $classmap)
|
||||
{
|
||||
$this->classmap = $classmap;
|
||||
}
|
||||
|
||||
public function addDefinitionComplexType($type, Collection $complexType)
|
||||
{
|
||||
$this->complexTypes[$type] = $complexType;
|
||||
}
|
||||
|
||||
public function getDefinitionComplexTypes()
|
||||
{
|
||||
return $this->complexTypes;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
<?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\ServiceDefinition\Strategy;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
|
||||
use Zend\Soap\Wsdl;
|
||||
use Zend\Soap\Wsdl\ComplexTypeStrategy\AbstractComplexTypeStrategy;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class ComplexType extends AbstractComplexTypeStrategy
|
||||
{
|
||||
private $loader;
|
||||
private $definition;
|
||||
|
||||
public function __construct(AnnotationComplexTypeLoader $loader, $definition)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a complex type by recursivly using all the class properties fetched via Reflection.
|
||||
*
|
||||
* @param string $type Name of the class to be specified
|
||||
* @return string XSD Type for the given PHP type
|
||||
*/
|
||||
public function addComplexType($type)
|
||||
{
|
||||
$classmap = $this->definition->getClassmap();
|
||||
|
||||
if (null !== $soapType = $this->scanRegisteredTypes($type)) {
|
||||
return $soapType;
|
||||
}
|
||||
|
||||
if (!$this->loader->supports($type)) {
|
||||
throw new \InvalidArgumentException(sprintf('Cannot add a complex type "%s" that is not an object or where class could not be found in "ComplexType" strategy.', $type));
|
||||
}
|
||||
|
||||
$dom = $this->getContext()->toDomDocument();
|
||||
|
||||
$soapTypeName = $this->getContext()->translateType($type);
|
||||
$soapType = 'tns:'.$soapTypeName;
|
||||
|
||||
if (!$classmap->has($soapTypeName)) {
|
||||
$classmap->add($soapTypeName, $type);
|
||||
}
|
||||
|
||||
// Register type here to avoid recursion
|
||||
$this->getContext()->addType($type, $soapType);
|
||||
|
||||
$complexType = $dom->createElement('xsd:complexType');
|
||||
$complexType->setAttribute('name', $soapTypeName);
|
||||
|
||||
$all = $dom->createElement('xsd:all');
|
||||
|
||||
$definitionComplexType = $this->loader->load($type);
|
||||
$this->definition->addDefinitionComplexType($type, $definitionComplexType);
|
||||
|
||||
foreach ($definitionComplexType as $annotationComplexType) {
|
||||
$element = $dom->createElement('xsd:element');
|
||||
$element->setAttribute('name', $propertyName = $annotationComplexType->getName());
|
||||
$element->setAttribute('type', $this->getContext()->getType(trim($annotationComplexType->getValue())));
|
||||
|
||||
if ($annotationComplexType->isNillable()) {
|
||||
$element->setAttribute('nillable', 'true');
|
||||
}
|
||||
|
||||
$all->appendChild($element);
|
||||
}
|
||||
|
||||
$complexType->appendChild($all);
|
||||
$this->getContext()->getSchema()->appendChild($complexType);
|
||||
|
||||
return $soapType;
|
||||
}
|
||||
}
|
60
src/BeSimple/SoapBundle/ServiceDefinition/Type.php
Normal file
60
src/BeSimple/SoapBundle/ServiceDefinition/Type.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?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\ServiceDefinition;
|
||||
|
||||
class Type
|
||||
{
|
||||
private $phpType;
|
||||
private $xmlType;
|
||||
private $converter;
|
||||
|
||||
public function __construct($phpType = null, $xmlType = null, $converter = null)
|
||||
{
|
||||
$this->setPhpType($phpType);
|
||||
$this->setXmlType($xmlType);
|
||||
$this->setConverter($converter);
|
||||
}
|
||||
|
||||
public function getPhpType()
|
||||
{
|
||||
return $this->phpType;
|
||||
}
|
||||
|
||||
public function setPhpType($phpType)
|
||||
{
|
||||
$phpType = $phpType;
|
||||
if ($phpType[0] == '\\') {
|
||||
$phpType = substr($phpType, 1);
|
||||
}
|
||||
|
||||
$this->phpType = $phpType;
|
||||
}
|
||||
|
||||
public function getXmlType()
|
||||
{
|
||||
return $this->xmlType;
|
||||
}
|
||||
|
||||
public function setXmlType($xmlType)
|
||||
{
|
||||
$this->xmlType = $xmlType;
|
||||
}
|
||||
|
||||
public function getConverter()
|
||||
{
|
||||
return $this->converter;
|
||||
}
|
||||
|
||||
public function setConverter($converter)
|
||||
{
|
||||
$this->converter = $converter;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user