diff --git a/src/BeSimple/SoapBundle/Controller/SoapWebServiceController.php b/src/BeSimple/SoapBundle/Controller/SoapWebServiceController.php index d65e434..01cd065 100644 --- a/src/BeSimple/SoapBundle/Controller/SoapWebServiceController.php +++ b/src/BeSimple/SoapBundle/Controller/SoapWebServiceController.php @@ -64,6 +64,7 @@ class SoapWebServiceController extends ContainerAware $this->soapRequest = SoapRequest::createFromHttpRequest($this->container->get('request')); $this->soapServer = $webServiceContext ->getServerBuilder() + ->withSoapVersion11() ->withHandler($this) ->build() ; diff --git a/src/BeSimple/SoapBundle/DependencyInjection/BeSimpleSoapExtension.php b/src/BeSimple/SoapBundle/DependencyInjection/BeSimpleSoapExtension.php index 3db1218..1536d8d 100644 --- a/src/BeSimple/SoapBundle/DependencyInjection/BeSimpleSoapExtension.php +++ b/src/BeSimple/SoapBundle/DependencyInjection/BeSimpleSoapExtension.php @@ -148,9 +148,9 @@ class BeSimpleSoapExtension extends Extension $options = $container ->getDefinition('besimple.soap.context.'.$bindingSuffix) - ->getArgument(5); + ->getArgument(2); - $definition->replaceArgument(5, array_merge($options, $config)); + $definition->replaceArgument(2, array_merge($options, $config)); } private function getCacheType($type) diff --git a/src/BeSimple/SoapBundle/Resources/config/loaders.xml b/src/BeSimple/SoapBundle/Resources/config/loaders.xml index 4347f94..4b609ba 100644 --- a/src/BeSimple/SoapBundle/Resources/config/loaders.xml +++ b/src/BeSimple/SoapBundle/Resources/config/loaders.xml @@ -29,10 +29,13 @@ + + + diff --git a/src/BeSimple/SoapBundle/Resources/config/webservice.xml b/src/BeSimple/SoapBundle/Resources/config/webservice.xml index cd1a689..8170b1f 100644 --- a/src/BeSimple/SoapBundle/Resources/config/webservice.xml +++ b/src/BeSimple/SoapBundle/Resources/config/webservice.xml @@ -13,8 +13,7 @@ BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedRequestMessageBinder BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedRequestHeaderMessageBinder BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedResponseMessageBinder - BeSimple\SoapBundle\ServiceDefinition\Dumper\WsdlDumper - BeSimple\SoapBundle\Converter\TypeRepository + BeSimple\SoapCommon\Definition\Type\TypeRepository BeSimple\SoapServer\Classmap @@ -28,9 +27,6 @@ - - - %besimple.soap.cache.dir% @@ -45,9 +41,6 @@ - - - %besimple.soap.cache.dir% @@ -60,42 +53,35 @@ - - - - - %besimple.soap.definition.dumper.options.stylesheet% - - - + xsd http://www.w3.org/2001/XMLSchema - + string xsd:string - + boolean xsd:boolean - + int xsd:int - + float xsd:float - + date xsd:date - + dateTime xsd:dateTime diff --git a/src/BeSimple/SoapBundle/ServiceBinding/MessageBinderInterface.php b/src/BeSimple/SoapBundle/ServiceBinding/MessageBinderInterface.php index 85ca02f..7cda7d4 100644 --- a/src/BeSimple/SoapBundle/ServiceBinding/MessageBinderInterface.php +++ b/src/BeSimple/SoapBundle/ServiceBinding/MessageBinderInterface.php @@ -11,6 +11,7 @@ namespace BeSimple\SoapBundle\ServiceBinding; use BeSimple\SoapBundle\ServiceDefinition\Method; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; /** * @author Christian Kerl @@ -23,5 +24,5 @@ interface MessageBinderInterface * * @return mixed */ - function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array()); -} \ No newline at end of file + function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository); +} diff --git a/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestHeaderMessageBinder.php b/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestHeaderMessageBinder.php index 15fcf0c..05fe83d 100644 --- a/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestHeaderMessageBinder.php +++ b/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestHeaderMessageBinder.php @@ -11,6 +11,7 @@ namespace BeSimple\SoapBundle\ServiceBinding; use BeSimple\SoapBundle\ServiceDefinition\Method; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; /** * @author Francis Besset @@ -24,10 +25,11 @@ class RpcLiteralRequestHeaderMessageBinder extends RpcLiteralRequestMessageBinde $this->header = $header; } - public function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array()) + public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository) { + $this->typeRepository = $typeRepository; $headerDefinition = $messageDefinition->getHeaders()->get($this->header); - return $this->processType($headerDefinition->getType()->getPhpType(), $message, $definitionComplexTypes); + return $this->processType($headerDefinition->getType(), $message); } -} \ No newline at end of file +} diff --git a/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestMessageBinder.php b/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestMessageBinder.php index 6f8b36e..872adc0 100644 --- a/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestMessageBinder.php +++ b/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralRequestMessageBinder.php @@ -15,6 +15,9 @@ namespace BeSimple\SoapBundle\ServiceBinding; use BeSimple\SoapBundle\ServiceDefinition\Method; use BeSimple\SoapBundle\ServiceDefinition\Strategy\MethodComplexType; use BeSimple\SoapBundle\ServiceDefinition\Strategy\PropertyComplexType; +use BeSimple\SoapCommon\Definition\Type\ArrayOfType; +use BeSimple\SoapCommon\Definition\Type\ComplexType; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; use BeSimple\SoapCommon\Util\MessageBinder; /** @@ -23,19 +26,20 @@ use BeSimple\SoapCommon\Util\MessageBinder; */ class RpcLiteralRequestMessageBinder implements MessageBinderInterface { - private $messageRefs = array(); - private $definitionComplexTypes; + protected $typeRepository; - public function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array()) + private $messageRefs = array(); + + public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository) { - $this->definitionComplexTypes = $definitionComplexTypes; + $this->typeRepository = $typeRepository; $result = array(); $i = 0; - foreach ($messageDefinition->getArguments() as $argument) { + foreach ($messageDefinition->getInput()->all() as $argument) { if (isset($message[$i])) { - $result[$argument->getName()] = $this->processType($argument->getType()->getPhpType(), $message[$i]); + $result[$argument->getName()] = $this->processType($argument->getType(), $message[$i]); } $i++; @@ -48,15 +52,21 @@ class RpcLiteralRequestMessageBinder implements MessageBinderInterface { $isArray = false; - if (preg_match('/^([^\[]+)\[\]$/', $phpType, $match)) { + $type = $this->typeRepository->getType($phpType); + if ($type instanceof ArrayOfType) { $isArray = true; - $array = array(); - $phpType = $match[1]; + $arrayType = $type; + + $type = $this->typeRepository->getType($type->get('item')->getType()); } // @TODO Fix array reference - if (isset($this->definitionComplexTypes[$phpType])) { + if ($type instanceof ComplexType) { + $phpType = $type->getPhpType(); + if ($isArray) { + $array = array(); + if (isset($message->item)) { foreach ($message->item as $complexType) { $array[] = $this->checkComplexType($phpType, $complexType); @@ -98,12 +108,12 @@ class RpcLiteralRequestMessageBinder implements MessageBinderInterface $this->messageRefs[$hash] = $message; $messageBinder = new MessageBinder($message); - foreach ($this->definitionComplexTypes[$phpType]['properties'] as $type) { + foreach ($this->typeRepository->getType($phpType)->all() as $type) { $property = $type->getName(); $value = $messageBinder->readProperty($property); if (null !== $value) { - $value = $this->processType($type->getValue(), $value); + $value = $this->processType($type->getType(), $value); $messageBinder->writeProperty($property, $value); } diff --git a/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralResponseMessageBinder.php b/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralResponseMessageBinder.php index 34d1edd..6e600c8 100644 --- a/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralResponseMessageBinder.php +++ b/src/BeSimple/SoapBundle/ServiceBinding/RpcLiteralResponseMessageBinder.php @@ -15,6 +15,9 @@ namespace BeSimple\SoapBundle\ServiceBinding; use BeSimple\SoapBundle\ServiceDefinition\Method; use BeSimple\SoapBundle\ServiceDefinition\Strategy\PropertyComplexType; use BeSimple\SoapBundle\ServiceDefinition\Strategy\MethodComplexType; +use BeSimple\SoapCommon\Definition\Type\ArrayOfType; +use BeSimple\SoapCommon\Definition\Type\ComplexType; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; use BeSimple\SoapCommon\Util\MessageBinder; /** @@ -23,26 +26,32 @@ use BeSimple\SoapCommon\Util\MessageBinder; */ class RpcLiteralResponseMessageBinder implements MessageBinderInterface { + protected $typeRepository; + private $messageRefs = array(); - private $definitionComplexTypes; - public function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array()) + public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository) { - $this->definitionComplexTypes = $definitionComplexTypes; + $this->typeRepository = $typeRepository; - return $this->processType($messageDefinition->getReturn()->getPhpType(), $message); + return $this->processType($messageDefinition->getOutput()->get('return')->getType(), $message); } private function processType($phpType, $message) { $isArray = false; - if (preg_match('/^([^\[]+)\[\]$/', $phpType, $match)) { + $type = $this->typeRepository->getType($phpType); + if ($type instanceof ArrayOfType) { $isArray = true; - $phpType = $match[1]; + $arrayType = $type; + + $type = $this->typeRepository->getType($type->get('item')->getType()); } - if (isset($this->definitionComplexTypes[$phpType])) { + if ($type instanceof ComplexType) { + $phpType = $type->getPhpType(); + if ($isArray) { $array = array(); @@ -83,12 +92,12 @@ class RpcLiteralResponseMessageBinder implements MessageBinderInterface } $messageBinder = new MessageBinder($message); - foreach ($this->definitionComplexTypes[$phpType]['properties'] as $type) { + foreach ($this->typeRepository->getType($phpType)->all() as $type) { $property = $type->getName(); $value = $messageBinder->readProperty($property); if (null !== $value) { - $value = $this->processType($type->getValue(), $value); + $value = $this->processType($type->getType(), $value); $messageBinder->writeProperty($property, $value); } diff --git a/src/BeSimple/SoapBundle/ServiceBinding/ServiceBinder.php b/src/BeSimple/SoapBundle/ServiceBinding/ServiceBinder.php index e9e4254..c31f4fd 100644 --- a/src/BeSimple/SoapBundle/ServiceBinding/ServiceBinder.php +++ b/src/BeSimple/SoapBundle/ServiceBinding/ServiceBinder.php @@ -11,7 +11,7 @@ namespace BeSimple\SoapBundle\ServiceBinding; use BeSimple\SoapBundle\ServiceDefinition\Header; -use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition; +use BeSimple\SoapBundle\ServiceDefinition\Definition; use BeSimple\SoapBundle\Soap\SoapHeader; /** @@ -40,12 +40,12 @@ class ServiceBinder private $responseMessageBinder; /** - * @param ServiceDefinition $definition + * @param Definition $definition * @param MessageBinderInterface $requestHeaderMessageBinder * @param MessageBinderInterface $requestMessageBinder * @param MessageBinderInterface $responseMessageBinder */ - public function __construct(ServiceDefinition $definition, MessageBinderInterface $requestHeaderMessageBinder, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder) { + public function __construct(Definition $definition, MessageBinderInterface $requestHeaderMessageBinder, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder) { $this->definition = $definition; $this->requestHeaderMessageBinder = $requestHeaderMessageBinder; @@ -62,7 +62,7 @@ class ServiceBinder */ public function isServiceHeader($method, $header) { - return $this->definition->getMethods()->get($method)->getHeaders()->has($header); + return $this->definition->getMethod($method)->getHeader($header); } /** @@ -72,7 +72,7 @@ class ServiceBinder */ public function isServiceMethod($method) { - return $this->definition->getMethods()->has($method); + return null !== $this->definition->getMethod($method); } /** @@ -84,11 +84,11 @@ class ServiceBinder */ public function processServiceHeader($method, $header, $data) { - $methodDefinition = $this->definition->getMethods()->get($method); - $headerDefinition = $methodDefinition->getHeaders()->get($header); + $methodDefinition = $this->definition->getMethod($method); + $headerDefinition = $methodDefinition->getHeader($header); $this->requestHeaderMessageBinder->setHeader($header); - $data = $this->requestHeaderMessageBinder->processMessage($methodDefinition, $data, $this->definition->getDefinitionComplexTypes()); + $data = $this->requestHeaderMessageBinder->processMessage($methodDefinition, $data, $this->definition->getTypeRepository()); return new SoapHeader($this->definition->getNamespace(), $headerDefinition->getName(), $data); } @@ -101,11 +101,11 @@ class ServiceBinder */ public function processServiceMethodArguments($method, $arguments) { - $methodDefinition = $this->definition->getMethods()->get($method); + $methodDefinition = $this->definition->getMethod($method); return array_merge( array('_controller' => $methodDefinition->getController()), - $this->requestMessageBinder->processMessage($methodDefinition, $arguments, $this->definition->getDefinitionComplexTypes()) + $this->requestMessageBinder->processMessage($methodDefinition, $arguments, $this->definition->getTypeRepository()) ); } @@ -117,8 +117,8 @@ class ServiceBinder */ public function processServiceMethodReturnValue($name, $return) { - $methodDefinition = $this->definition->getMethods()->get($name); + $methodDefinition = $this->definition->getMethod($name); - return $this->responseMessageBinder->processMessage($methodDefinition, $return, $this->definition->getDefinitionComplexTypes()); + return $this->responseMessageBinder->processMessage($methodDefinition, $return, $this->definition->getTypeRepository()); } -} \ No newline at end of file +} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Argument.php b/src/BeSimple/SoapBundle/ServiceDefinition/Argument.php deleted file mode 100644 index b1f8849..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Argument.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * 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; - } -} \ No newline at end of file diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/ComplexType.php b/src/BeSimple/SoapBundle/ServiceDefinition/ComplexType.php index 2d78bbe..d0ae464 100644 --- a/src/BeSimple/SoapBundle/ServiceDefinition/ComplexType.php +++ b/src/BeSimple/SoapBundle/ServiceDefinition/ComplexType.php @@ -1,8 +1,10 @@ + * (c) Francis Besset * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. @@ -48,4 +50,4 @@ class ComplexType { $this->isNillable = (bool) $isNillable; } -} \ No newline at end of file +} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Definition.php b/src/BeSimple/SoapBundle/ServiceDefinition/Definition.php new file mode 100644 index 0000000..4afd642 --- /dev/null +++ b/src/BeSimple/SoapBundle/ServiceDefinition/Definition.php @@ -0,0 +1,46 @@ + + * (c) Francis Besset + * + * 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\SoapCommon\Definition\Definition as BaseDefinition; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; + +/** + * @author Christian Kerl + * @author Francis Besset + */ +class Definition extends BaseDefinition +{ + private $complexTypes; + + public function __construct(TypeRepository $typeRepository) + { + $this->typeRepository = $typeRepository; + + $this->setOptions(array()); + } + + public function setName($name) + { + $this->name = $name; + + return $this; + } + + public function setNamespace($namespace) + { + $this->namespace = $namespace; + + return $this; + } +} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/DumperInterface.php b/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/DumperInterface.php deleted file mode 100644 index 3b8b257..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/DumperInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * 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); -} \ No newline at end of file diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/Wsdl.php b/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/Wsdl.php deleted file mode 100644 index e8e4721..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/Wsdl.php +++ /dev/null @@ -1,80 +0,0 @@ - - * - * 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 - */ -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) { - return $type->getXmlType(); - } - - if ('\\' === $type[0]) { - $type = substr($type, 1); - } - - if (!$xmlType = $this->typeRepository->getXmlTypeMapping($type)) { - $xmlType = $this->addComplexType($type); - } - - return $xmlType; - } - - /** - * 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]; - } - - 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; - } -} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlDumper.php b/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlDumper.php deleted file mode 100644 index abe64c3..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlDumper.php +++ /dev/null @@ -1,177 +0,0 @@ - - * - * 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 - */ -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(); - } -} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlTypeStrategy.php b/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlTypeStrategy.php deleted file mode 100644 index 96207ea..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Dumper/WsdlTypeStrategy.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * 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; - } -} \ No newline at end of file diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Header.php b/src/BeSimple/SoapBundle/ServiceDefinition/Header.php deleted file mode 100644 index 53cc4cf..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Header.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * 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; - } -} \ No newline at end of file diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationClassLoader.php b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationClassLoader.php index 2ce9db4..2a5bd12 100644 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationClassLoader.php +++ b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationClassLoader.php @@ -1,7 +1,7 @@ * (c) Francis Besset @@ -14,6 +14,8 @@ namespace BeSimple\SoapBundle\ServiceDefinition\Loader; use BeSimple\SoapBundle\ServiceDefinition as Definition; use BeSimple\SoapBundle\ServiceDefinition\Annotation; +use BeSimple\SoapCommon\Definition\Type\ComplexType; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; use Doctrine\Common\Annotations\Reader; @@ -26,19 +28,23 @@ use Symfony\Component\Config\Loader\LoaderResolverInterface; * Based on \Symfony\Component\Routing\Loader\AnnotationClassLoader * * @author Christian Kerl + * @author Francis Besset */ class AnnotationClassLoader extends Loader { protected $reader; + protected $typeRepository; + /** * Constructor. * * @param \Doctrine\Common\Annotations\Reader $reader */ - public function __construct(Reader $reader) + public function __construct(Reader $reader, TypeRepository $typeRepository) { $this->reader = $reader; + $this->typeRepository = $typeRepository; } /** @@ -58,39 +64,26 @@ class AnnotationClassLoader extends Loader } $class = new \ReflectionClass($class); - $definition = new Definition\ServiceDefinition(); + $definition = new Definition\Definition($this->typeRepository); - $serviceMethodHeaders = array(); + $sharedHeaders = array(); foreach ($this->reader->getClassAnnotations($class) as $annotation) { if ($annotation instanceof Annotation\Header) { - $serviceMethodHeaders[$annotation->getValue()] = $annotation; + $sharedHeaders[$annotation->getValue()] = $this->loadType($annotation->getPhpType()); } } foreach ($class->getMethods() as $method) { - $serviceArguments = - $serviceHeaders = array(); + $serviceHeaders = $sharedHeaders; + $serviceArguments = 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) - ); + $serviceHeaders[$annotation->getValue()] = $this->loadType($annotation->getPhpType()); } elseif ($annotation instanceof Annotation\Param) { - $serviceArguments[] = new Definition\Argument( - $annotation->getValue(), - $this->getArgumentType($method, $annotation) - ); + $serviceArguments[$annotation->getValue()] = $this->loadType($annotation->getPhpType()); } elseif ($annotation instanceof Annotation\Method) { if ($serviceMethod) { throw new \LogicException(sprintf('@Soap\Method defined twice for "%s".', $method->getName())); @@ -98,6 +91,7 @@ class AnnotationClassLoader extends Loader $serviceMethod = new Definition\Method( $annotation->getValue(), + $this->typeRepository, $this->getController($class, $method, $annotation) ); } elseif ($annotation instanceof Annotation\Result) { @@ -105,7 +99,7 @@ class AnnotationClassLoader extends Loader throw new \LogicException(sprintf('@Soap\Result defined twice for "%s".', $method->getName())); } - $serviceReturn = new Definition\Type($annotation->getPhpType(), $annotation->getXmlType()); + $serviceReturn = $annotation->getPhpType(); } } @@ -114,16 +108,21 @@ class AnnotationClassLoader extends Loader } if ($serviceMethod) { - $serviceMethod->setArguments($serviceArguments); - $serviceMethod->setHeaders($serviceHeaders); + foreach ($serviceHeaders as $name => $type) { + $serviceMethod->addHeader($name, $type); + } + + foreach ($serviceArguments as $name => $type) { + $serviceMethod->addInput($name, $type); + } if (!$serviceReturn) { throw new \LogicException(sprintf('@Soap\Result non-existent for "%s".', $method->getName())); } - $serviceMethod->setReturn($serviceReturn); + $serviceMethod->setOutput($this->loadType($serviceReturn)); - $definition->getMethods()->add($serviceMethod); + $definition->addMethod($serviceMethod); } } @@ -169,6 +168,30 @@ class AnnotationClassLoader extends Loader return new Definition\Type($phpType, $xmlType); } + private function loadType($phpType) + { + if (false !== $arrayOf = $this->typeRepository->getArrayOf($phpType)) { + $this->loadType($arrayOf); + } + + if (!$this->typeRepository->hasType($phpType)) { + $complexTypeResolver = $this->resolve($phpType, 'annotation_complextype'); + if (!$complexTypeResolver) { + throw new Exception(); + } + + $loaded = $complexTypeResolver->load($phpType); + $complexType = new ComplexType($phpType, $loaded['alias']); + foreach ($loaded['properties'] as $name => $property) { + $complexType->add($name, $this->loadType($property->getValue()), $property->isNillable()); + } + + $this->typeRepository->addComplexType($complexType); + } + + return $phpType; + } + /** * Returns true if this class supports the given resource. * diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationComplexTypeLoader.php b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationComplexTypeLoader.php index 987cf5d..1d3e095 100644 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationComplexTypeLoader.php +++ b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationComplexTypeLoader.php @@ -1,7 +1,7 @@ * (c) Francis Besset @@ -65,4 +65,17 @@ class AnnotationComplexTypeLoader extends AnnotationClassLoader return $annotations; } + + /** + * 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) && class_exists($resource) && 'annotation_complextype' === $type; + } } diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationFileLoader.php b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationFileLoader.php index a7841fa..8e362c3 100644 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationFileLoader.php +++ b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/AnnotationFileLoader.php @@ -1,7 +1,7 @@ * (c) Francis Besset diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/XmlFileLoader.php b/src/BeSimple/SoapBundle/ServiceDefinition/Loader/XmlFileLoader.php deleted file mode 100644 index 2039002..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Loader/XmlFileLoader.php +++ /dev/null @@ -1,145 +0,0 @@ - - * (c) Francis Besset - * - * 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; - } -} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Method.php b/src/BeSimple/SoapBundle/ServiceDefinition/Method.php index a03053f..9d3f593 100644 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Method.php +++ b/src/BeSimple/SoapBundle/ServiceDefinition/Method.php @@ -1,8 +1,10 @@ + * (c) Francis Besset * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. @@ -10,36 +12,22 @@ namespace BeSimple\SoapBundle\ServiceDefinition; -use BeSimple\SoapBundle\Util\Collection; +use BeSimple\SoapCommon\Definition\Method as BaseMethod; +use BeSimple\SoapCommon\Definition\Type\TypeRepository; -class Method +/** + * @author Christian Kerl + * @author Francis Besset + */ +class Method extends BaseMethod { - 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) + public function __construct($name, TypeRepository $typeRepository, $controller) { - $this->setName($name); - $this->setController($controller); - $this->setHeaders($headers); - $this->setArguments($arguments); + parent::__construct($name, $typeRepository); - if ($return) { - $this->setReturn($return); - } - } - - public function getName() - { - return $this->name; - } - - public function setName($name) - { - $this->name = $name; + $this->controller = $controller; } public function getController() @@ -47,40 +35,8 @@ class Method return $this->controller; } - public function setController($controller) + public function getVersions() { - $this->controller = $controller; + return array(\SOAP_1_1); } - - 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; - } -} \ No newline at end of file +} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/ServiceDefinition.php b/src/BeSimple/SoapBundle/ServiceDefinition/ServiceDefinition.php deleted file mode 100644 index 8cfe302..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/ServiceDefinition.php +++ /dev/null @@ -1,151 +0,0 @@ - - * - * 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 hasDefinitionComplexType($type) - { - return isset($this->complexTypes[$type]); - } - - public function addDefinitionComplexType($type, array $definition) - { - if ($this->hasDefinitionComplexType($type)) { - return false; - } - - $this->complexTypes[$type] = $definition; - - return true; - } - - public function getDefinitionComplexTypes() - { - return $this->complexTypes; - } -} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Strategy/ComplexType.php b/src/BeSimple/SoapBundle/ServiceDefinition/Strategy/ComplexType.php deleted file mode 100644 index d38d871..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Strategy/ComplexType.php +++ /dev/null @@ -1,89 +0,0 @@ - - * (c) Francis Besset - * - * 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 - */ -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($classname) - { - $classmap = $this->definition->getClassmap(); - if ($classmap->hasByClassname($classname)) { - return 'tns:'.$classmap->getByClassname($classname); - } - - if (!$this->loader->supports($classname)) { - throw new \InvalidArgumentException(sprintf('Cannot add ComplexType "%s" because it is not an object or the class could not be found.', $classname)); - } - - $definitionComplexType = $this->loader->load($classname); - $classnameAlias = isset($definitionComplexType['alias']) ? $definitionComplexType['alias'] : $classname; - - $type = $this->getContext()->translateType($classnameAlias); - $xmlType = 'tns:'.$type; - - // Register type here to avoid recursion - $classmap->add($type, $classname); - $this->addXmlDefinition($definitionComplexType, $classname, $type); - - return $xmlType; - } - - private function addXmlDefinition(array $definitionComplexType, $classname, $type) - { - $dom = $this->getContext()->toDomDocument(); - $complexType = $dom->createElement('xsd:complexType'); - $complexType->setAttribute('name', $type); - - $all = $dom->createElement('xsd:all'); - - $elements = array(); - foreach ($definitionComplexType['properties'] as $property) { - $element = $dom->createElement('xsd:element'); - $element->setAttribute('name', $property->getName()); - $element->setAttribute('type', $this->getContext()->getType($property->getValue())); - - if ($property->isNillable()) { - $element->setAttribute('nillable', 'true'); - } - - $all->appendChild($element); - } - - $complexType->appendChild($all); - $this->getContext()->getSchema()->appendChild($complexType); - - $this->definition->addDefinitionComplexType($classname, $definitionComplexType); - } -} diff --git a/src/BeSimple/SoapBundle/ServiceDefinition/Type.php b/src/BeSimple/SoapBundle/ServiceDefinition/Type.php deleted file mode 100644 index 2855689..0000000 --- a/src/BeSimple/SoapBundle/ServiceDefinition/Type.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * 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; - } -} \ No newline at end of file diff --git a/src/BeSimple/SoapBundle/WebServiceContext.php b/src/BeSimple/SoapBundle/WebServiceContext.php index 6e3249a..694cfc5 100644 --- a/src/BeSimple/SoapBundle/WebServiceContext.php +++ b/src/BeSimple/SoapBundle/WebServiceContext.php @@ -3,6 +3,7 @@ * This file is part of the BeSimpleSoapBundle. * * (c) Christian Kerl + * (c) Francis Besset * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. @@ -10,13 +11,12 @@ namespace BeSimple\SoapBundle; -use BeSimple\SoapBundle\Converter\TypeRepository; use BeSimple\SoapBundle\ServiceBinding\MessageBinderInterface; use BeSimple\SoapBundle\ServiceBinding\ServiceBinder; use BeSimple\SoapBundle\ServiceDefinition\Dumper\DumperInterface; -use BeSimple\SoapCommon\Classmap; use BeSimple\SoapCommon\Converter\TypeConverterCollection; +use BeSimple\SoapWsdl\Dumper\Dumper; use BeSimple\SoapServer\SoapServerBuilder; use Symfony\Component\Config\ConfigCache; @@ -26,43 +26,31 @@ use Symfony\Component\Config\Loader\LoaderInterface; * WebServiceContext. * * @author Christian Kerl + * @author Francis Besset */ class WebServiceContext { - private $classmap; - - private $typeRepository; private $converterRepository; - private $wsdlFileDumper; - private $options; private $serviceDefinition; private $serviceBinder; private $serverBuilder; - public function __construct(LoaderInterface $loader, DumperInterface $dumper, Classmap $classmap, TypeRepository $typeRepository, TypeConverterCollection $converters, array $options) + public function __construct(LoaderInterface $loader, TypeConverterCollection $converters, array $options) { - $this->loader = $loader; - $this->wsdlFileDumper = $dumper; - - $this->classmap = $classmap; - - $this->typeRepository = $typeRepository; - $this->converters = $converters; - - // Issue #6: keep the debug because the cache is invalid - $options['debug'] = true; - $this->options = $options; + $this->loader = $loader; + $this->converters = $converters; + $this->options = $options; } public function getServiceDefinition() { if (null === $this->serviceDefinition) { - $cacheDefinition = new ConfigCache(sprintf('%s/%s.definition.php', $this->options['cache_dir'], $this->options['name']), $this->options['debug']); - if ($cacheDefinition->isFresh()) { - $this->serviceDefinition = include (string) $cacheDefinition; + $cache = new ConfigCache(sprintf('%s/%s.definition.php', $this->options['cache_dir'], $this->options['name']), $this->options['debug']); + if ($cache->isFresh()) { + $this->serviceDefinition = include (string) $cache; } else { if (!$this->loader->supports($this->options['resource'], $this->options['resource_type'])) { throw new \LogicException(sprintf('Cannot load "%s" (%s)', $this->options['resource'], $this->options['resource_type'])); @@ -72,10 +60,7 @@ class WebServiceContext $this->serviceDefinition->setName($this->options['name']); $this->serviceDefinition->setNamespace($this->options['namespace']); - $this->serviceDefinition->setClassmap($this->classmap); - $this->classmap = null; - - $this->typeRepository->fixTypeInformation($this->serviceDefinition); + $cache->write('serviceDefinition), true).');'); } } @@ -89,19 +74,21 @@ class WebServiceContext public function getWsdlFile($endpoint = null) { - $file = sprintf('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint)); - $cacheWsdl = new ConfigCache($file, $this->options['debug']); + $file = sprintf ('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint)); + $cache = new ConfigCache($file, $this->options['debug']); - if(!$cacheWsdl->isFresh()) { - $serviceDefinition = $this->getServiceDefinition(); + if(!$cache->isFresh()) { + $definition = $this->getServiceDefinition(); - $cacheWsdl->write($this->wsdlFileDumper->dumpServiceDefinition($serviceDefinition, $endpoint)); + if ($endpoint) { + $definition->setOption('location', $endpoint); + } - $cacheDefinition = new ConfigCache(sprintf('%s/%s.definition.php', $this->options['cache_dir'], $this->options['name']), $this->options['debug']); - $cacheDefinition->write('write($dumper->dump()); } - return (string) $cacheWsdl; + return (string) $cache; } public function getServiceBinder() @@ -123,7 +110,7 @@ class WebServiceContext if (null === $this->serverBuilder) { $this->serverBuilder = SoapServerBuilder::createWithDefaults() ->withWsdl($this->getWsdlFile()) - ->withClassmap($this->getServiceDefinition()->getClassmap()) + ->withClassmap($this->getServiceDefinition()->getTypeRepository()->getClassmap()) ->withTypeConverters($this->converters) ; diff --git a/src/BeSimple/SoapCommon/Definition/Definition.php b/src/BeSimple/SoapCommon/Definition/Definition.php new file mode 100644 index 0000000..7d9f742 --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Definition.php @@ -0,0 +1,148 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition; + +use BeSimple\SoapCommon\Definition\Type\TypeRepository; + +/** + * @author Francis Besset + */ +class Definition +{ + protected $name; + protected $namespace; + + protected $typeRepository; + + protected $options; + protected $methods; + + public function __construct($name, $namespace, TypeRepository $typeRepository, array $options = array()) + { + $this->name = $name; + $this->namespace = $namespace; + $this->methods = array(); + + $this->typeRepository = $typeRepository; + + $this->setOptions($options); + } + + public function setOptions(array $options) + { + $this->options = array( + 'version' => \SOAP_1_1, + 'style' => \SOAP_RPC, + 'use' => \SOAP_LITERAL, + 'location' => null, + ); + + $invalid = array(); + foreach ($options as $key => $value) { + if (array_key_exists($key, $this->options)) { + $this->options[$key] = $value; + } else { + $invalid[] = $key; + } + } + + if ($invalid) { + throw new \InvalidArgumentException(sprintf('The Definition does not support the following options: "%s"', implode('", "', $invalid))); + } + + return $this; + } + + public function setOption($key, $value) + { + if (!array_key_exists($key, $this->options)) { + throw new \InvalidArgumentException(sprintf('The Definition does not support the "%s" option.', $key)); + } + + $this->options[$key] = $value; + + return $this; + } + + public function getOption($key) + { + if (!array_key_exists($key, $this->options)) { + throw new \InvalidArgumentException(sprintf('The Definition does not support the "%s" option.', $key)); + } + + return $this->options[$key]; + } + + public function getName() + { + return $this->name; + } + + public function getNamespace() + { + return $this->namespace; + } + + public function getType($phpType) + { + return $this->types[$phpType]; + } + + public function addType($phpType, $xmlType) + { + if (isset($$this->types[$phpType])) { + throw new \Exception(); + } + + $this->types[$phpType] = $xmlType; + } + + public function getMessages() + { + $messages = array(); + foreach ($this->methods as $method) { + $messages[] = $method->getHeaders(); + $messages[] = $method->getInput(); + $messages[] = $method->getOutput(); + } + + return $messages; + } + + public function getMethod($name, $default = null) + { + return isset($this->methods[$name]) ? $this->methods[$name] : $default; + } + + public function getMethods() + { + return $this->methods; + } + + public function addMethod(Method $method) + { + $name = $method->getName(); + if (isset($this->methods[$name])) { + throw new \Exception(sprintf('The method "%s" already exists', $name)); + } + + $this->methods[$name] = $method; + + return $method; + } + + public function getTypeRepository() + { + return $this->typeRepository; + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Message.php b/src/BeSimple/SoapCommon/Definition/Message.php new file mode 100644 index 0000000..caa78fe --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Message.php @@ -0,0 +1,61 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition; + +use BeSimple\SoapCommon\Definition\Type\TypeInterface; + +/** + * @author Francis Besset + */ +class Message +{ + protected $name; + protected $parts; + + public function __construct($name) + { + $this->name = $name; + $this->parts = array(); + } + + public function getName() + { + return $this->name; + } + + public function all() + { + return $this->parts; + } + + public function get($name, $default = null) + { + return isset($this->parts[$name]) ? $this->parts[$name] : $default; + } + + public function isEmpty() + { + return 0 === count($this->parts) ? true : false; + } + + public function add($name, $phpType, $nillable = false) + { + if ($phpType instanceof TypeInterface) { + $phpType = $phpType->getPhpType(); + } + + $this->parts[$name] = new Part($name, $phpType, $nillable); + + return $this; + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Method.php b/src/BeSimple/SoapCommon/Definition/Method.php new file mode 100644 index 0000000..a592e6a --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Method.php @@ -0,0 +1,98 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition; + +use BeSimple\SoapCommon\Definition\Type\TypeRepository; + +/** + * @author Francis Besset + */ +class Method +{ + private $name; + + private $headers; + private $input; + private $output; + private $fault; + + public function __construct($name, TypeRepository $typeRepository) + { + $this->name = $name; + + $this->headers = new Message($name.'Header', $typeRepository); + $this->input = new Message($name.'Request', $typeRepository); + $this->output = new Message($name.'Response', $typeRepository); + $this->fault = new Message($name.'Fault', $typeRepository); + } + + public function getName() + { + return $this->name; + } + + public function getDefinition() + { + return $this->definition; + } + + public function getVersions() + { + return array(\SOAP_1_1, \SOAP_1_2); + } + + public function getUse() + { + return \SOAP_LITERAL; + } + + public function addHeader($name, $type) + { + $this->headers->add($name, $type); + } + + public function addInput($name, $type) + { + $this->input->add($name, $type); + } + + public function setOutput($type) + { + $this->output->add('return', $type); + } + + public function getHeaders() + { + return $this->headers; + } + + public function getHeader($name, $default = null) + { + return $this->headers->get($name, $default); + } + + public function getInput() + { + return $this->input; + } + + public function getOutput() + { + return $this->output; + } + + public function getFault() + { + return $this->fault; + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Part.php b/src/BeSimple/SoapCommon/Definition/Part.php new file mode 100644 index 0000000..317f046 --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Part.php @@ -0,0 +1,55 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition; + +/** + * @author Francis Besset + */ +class Part +{ + protected $name; + protected $type; + protected $nillable; + + public function __construct($name, $type, $nillable = false) + { + $this->name = $name; + $this->type = $type; + $this->setNillable($nillable); + } + + public function getName() + { + return $this->name; + } + + public function getType() + { + return $this->type; + } + + public function setType($type) + { + $this->type = $type; + } + + public function isNillable() + { + return $this->nillable; + } + + public function setNillable($nillable) + { + $this->nillable = (boolean) $nillable; + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Type/ArrayOfType.php b/src/BeSimple/SoapCommon/Definition/Type/ArrayOfType.php new file mode 100644 index 0000000..6f05215 --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Type/ArrayOfType.php @@ -0,0 +1,30 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition\Type; + +/** + * @author Francis Besset + */ +class ArrayOfType extends ComplexType +{ + public function __construct($phpType, $arrayOf, $xmlTypeOf) + { + if ($arrayOf instanceof TypeInterface) { + $arrayOf = $arrayOf->getPhpType(); + } + + parent::__construct($phpType, 'ArrayOf'.ucfirst($xmlTypeOf ?: $arrayOf)); + + $this->add('item', $arrayOf); + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Type/ComplexType.php b/src/BeSimple/SoapCommon/Definition/Type/ComplexType.php new file mode 100644 index 0000000..99d6d3e --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Type/ComplexType.php @@ -0,0 +1,39 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition\Type; + +use BeSimple\SoapCommon\Definition\Message; + +/** + * @author Francis Besset + */ +class ComplexType extends Message implements TypeInterface +{ + public function __construct($phpType, $xmlType) + { + parent::__construct($xmlType); + + $this->phpType = $phpType; + $this->xmlType = $xmlType; + } + + public function getPhpType() + { + return $this->phpType; + } + + public function getXmlType() + { + return $this->xmlType; + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Type/Type.php b/src/BeSimple/SoapCommon/Definition/Type/Type.php new file mode 100644 index 0000000..7911c5a --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Type/Type.php @@ -0,0 +1,38 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition\Type; + +/** + * @author Francis Besset + */ +class Type implements TypeInterface +{ + protected $phpType; + protected $xmlType; + + public function __construct($phpType, $xmlType) + { + $this->phpType = $phpType; + $this->xmlType = $xmlType; + } + + public function getPhpType() + { + return $this->phpType; + } + + public function getXmlType() + { + return $this->xmlType; + } +} diff --git a/src/BeSimple/SoapCommon/Definition/Type/TypeInterface.php b/src/BeSimple/SoapCommon/Definition/Type/TypeInterface.php new file mode 100644 index 0000000..7263353 --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Type/TypeInterface.php @@ -0,0 +1,23 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition\Type; + +/** + * @author Francis Besset + */ +interface TypeInterface +{ + public function getPhpType(); + + public function getXmlType(); +} diff --git a/src/BeSimple/SoapCommon/Definition/Type/TypeRepository.php b/src/BeSimple/SoapCommon/Definition/Type/TypeRepository.php new file mode 100644 index 0000000..38d0f30 --- /dev/null +++ b/src/BeSimple/SoapCommon/Definition/Type/TypeRepository.php @@ -0,0 +1,135 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapCommon\Definition\Type; + +use BeSimple\SoapCommon\Classmap; + +/** + * @author Christian Kerl + * @author Francis Besset + */ +class TypeRepository +{ + const ARRAY_SUFFIX = '[]'; + + protected $xmlNamespaces = array(); + protected $types = array(); + + protected $classmap; + + public function __construct(Classmap $classmap = null) + { + $this->classmap = $classmap; + } + + public function getXmlNamespaces() + { + return $this->xmlNamespaces; + } + public function getXmlNamespace($prefix) + { + return $this->xmlNamespaces[$prefix]; + } + + public function addXmlNamespace($prefix, $url) + { + $this->xmlNamespaces[$prefix] = $url; + } + + public function getComplexTypes() + { + $types = array(); + foreach ($this->types as $type) { + if ($type instanceof ComplexType) { + $types[] = $type; + } + } + + return $types; + } + + public function getType($phpType) + { + if (!$this->hasType($phpType)) { + throw new \Exception(); + } + + return $this->types[$phpType]; + } + + public function addType($phpType, $xmlType) + { + return $this->types[$phpType] = $xmlType; + } + + public function addComplexType(ComplexType $type) + { + $phpType = $type->getPhpType(); + + $this->types[$phpType] = $type; + $this->addClassmap($type->getXmlType(), $phpType); + } + + public function hasType($type) + { + if ($type instanceof TypeInterface) { + $phpType = $type->getPhpType(); + + return !(!$this->hasType($phpType) || $type !== $this->getType($phpType)); + } + + if (isset($this->types[$type])) { + return true; + } + + if (false !== $arrayOf = $this->getArrayOf($type)) { + if ($this->hasType($arrayOf)) { + $xmlTypeOf = null; + $arrayOfType = $this->getType($arrayOf); + if ($arrayOfType instanceof ComplexType) { + $xmlTypeOf = $arrayOfType->getXmlType(); + } + + $arrayType = new ArrayOfType($type, $arrayOf, $xmlTypeOf); + $this->addType($type, $arrayType); + + return true; + } + } + + return false; + } + + public function getArrayOf($arrayType) + { + if (!preg_match('#(.*)'.preg_quote(static::ARRAY_SUFFIX, '#').'$#', $arrayType, $match)) { + return false; + } + + return $match[1]; + } + + public function getClassmap() + { + return $this->classmap; + } + + protected function addClassmap($xmlType, $phpType) + { + if (!$this->classmap) { + return; + } + + $this->classmap->add($xmlType, $phpType); + } +} diff --git a/src/BeSimple/SoapServer/SoapRequest.php b/src/BeSimple/SoapServer/SoapRequest.php index 8a03d7a..0964771 100644 --- a/src/BeSimple/SoapServer/SoapRequest.php +++ b/src/BeSimple/SoapServer/SoapRequest.php @@ -34,7 +34,7 @@ class SoapRequest extends CommonSoapRequest { $content = is_null($content) ? file_get_contents("php://input") : $content; $location = self::getCurrentUrl(); - $action = $_SERVER[SoapMessage::SOAP_ACTION_HEADER]; + $action = isset($_SERVER[SoapMessage::SOAP_ACTION_HEADER]) ? $_SERVER[SoapMessage::SOAP_ACTION_HEADER] : null; $contentType = $_SERVER[SoapMessage::CONTENT_TYPE_HEADER]; $request = new SoapRequest(); @@ -68,4 +68,4 @@ class SoapRequest extends CommonSoapRequest $url .= isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; return $url; } -} \ No newline at end of file +} diff --git a/src/BeSimple/SoapServer/SoapServer.php b/src/BeSimple/SoapServer/SoapServer.php index ced2ad0..045dcd6 100644 --- a/src/BeSimple/SoapServer/SoapServer.php +++ b/src/BeSimple/SoapServer/SoapServer.php @@ -158,4 +158,4 @@ class SoapServer extends \SoapServer ); } } -} \ No newline at end of file +} diff --git a/src/BeSimple/SoapWsdl/Dumper/AbstractVersion.php b/src/BeSimple/SoapWsdl/Dumper/AbstractVersion.php new file mode 100644 index 0000000..c67c035 --- /dev/null +++ b/src/BeSimple/SoapWsdl/Dumper/AbstractVersion.php @@ -0,0 +1,150 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapWsdl\Dumper; + +use BeSimple\SoapCommon\Definition\Method; + +/** + * @author Francis Besset + */ +abstract class AbstractVersion implements VersionInterface +{ + protected $soapNs; + + protected $typeNs; + + protected $name; + + protected $namespace; + + protected $portTypeName; + + protected $location; + + protected $style; + + protected $transport; + + protected $document; + + protected $bindingNode; + + protected $servicePortNode; + + public function __construct($soapNs, $typeNs, $name, $namespace, $portTypeName, $location, $style = \SOAP_RPC, $transport = 'http://schemas.xmlsoap.org/soap/http') + { + $this->soapNs = $soapNs; + $this->typeNs = $typeNs; + + $this->name = $name; + $this->namespace = $namespace; + $this->portTypeName = $portTypeName; + + $this->location = $location; + $this->style = $style; + $this->transport = $transport; + + $this->document = new \DOMDocument('1.0', 'utf-8'); + } + + public function getBindingNode() + { + if (!$this->bindingNode) { + $this->bindingNode = $this->document->createElement('binding'); + $this->bindingNode->setAttribute('name', $this->name.'Binding'); + $this->bindingNode->setAttribute('type', $this->portTypeName); + + $this->addSoapBinding(); + } + + return $this->bindingNode; + } + + public function getServicePortNode() + { + if (!$this->servicePortNode) { + $this->servicePortNode = $this->document->createElement('port'); + $this->servicePortNode->setAttribute('name', $this->name.'Port'); + $this->servicePortNode->setAttribute('binding', $this->typeNs.':'.$this->name.'Binding'); + + $this->addSoapAddress(); + } + + return $this->servicePortNode; + } + + public function addOperation(Method $method) + { + $operation = $this->document->createElement('operation'); + $operation->setAttribute('name', $method->getName()); + + $soapOperation = $this->document->createElement($this->soapNs.':operation'); + $soapOperation->setAttribute('soapAction', $this->namespace.$method->getName()); + $operation->appendChild($soapOperation); + + $this->getBindingNode()->appendChild($operation); + + $use = \SOAP_LITERAL === $method->getUse() ? 'literal' : 'encoded'; + + $input = $this->document->createElement('input'); + $operation->appendChild($input); + + $soapBody = $this->document->createElement($this->soapNs.':body'); + $soapBody->setAttribute('use', $use); + $soapBody->setAttribute('namespace', $this->namespace); + $soapBody->setAttribute('encodingStyle', $this->getEncodingStyle()); + $input->appendChild($soapBody); + + $headers = $method->getHeaders(); + if (!$headers->isEmpty()) { + foreach ($headers->all() as $part) { + $soapHeader = $this->document->createElement($this->soapNs.':header'); + $soapHeader->setAttribute('part', $part->getName()); + $soapHeader->setAttribute('message', $this->typeNs.':'.$headers->getName()); + $soapHeader->setAttribute('use', $use); + $soapHeader->setAttribute('namespace', $this->namespace); + $soapHeader->setAttribute('encodingStyle', $this->getEncodingStyle()); + $input->appendChild($soapHeader); + } + } + + $output = $this->document->createElement('output'); + $soapBody = $this->document->createElement($this->soapNs.':body'); + $soapBody->setAttribute('use', $use); + $soapBody->setAttribute('namespace', $this->namespace); + $soapBody->setAttribute('encodingStyle', $this->getEncodingStyle()); + $output->appendChild($soapBody); + $operation->appendChild($output); + } + + protected function addSoapBinding() + { + $soapBinding = $this->document->createElement($this->soapNs.':binding'); + $soapBinding->setAttribute('transport', $this->transport); + $soapBinding->setAttribute('style', \SOAP_RPC === $this->style ? 'rpc' : 'document'); + + $this->bindingNode->appendChild($soapBinding); + + return $soapBinding; + } + + protected function addSoapAddress() + { + $soapAddress = $this->document->createElement($this->soapNs.':address'); + $soapAddress->setAttribute('location', $this->location); + + $this->servicePortNode->appendChild($soapAddress); + + return $soapAddress; + } +} diff --git a/src/BeSimple/SoapWsdl/Dumper/Dumper.php b/src/BeSimple/SoapWsdl/Dumper/Dumper.php new file mode 100644 index 0000000..da5d586 --- /dev/null +++ b/src/BeSimple/SoapWsdl/Dumper/Dumper.php @@ -0,0 +1,345 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapWsdl\Dumper; + +use BeSimple\SoapCommon\Definition\Definition; +use BeSimple\SoapCommon\Definition\Method; +use BeSimple\SoapCommon\Definition\Part; +use BeSimple\SoapCommon\Definition\Type\ArrayOfType; +use BeSimple\SoapCommon\Definition\Type\ComplexType; + +/** + * @author Francis Besset + */ +class Dumper +{ + const XML_NS = 'xmlns'; + const XML_NS_URI = 'http://www.w3.org/2000/xmlns/'; + + const WSDL_NS = 'wsdl'; + const WSDL_NS_URI = 'http://schemas.xmlsoap.org/wsdl/'; + + const SOAP_NS = 'soap'; + const SOAP_NS_URI = 'http://schemas.xmlsoap.org/wsdl/soap/'; + + const SOAP12_NS = 'soap12'; + const SOAP12_NS_URI = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + + const SOAP_ENC_NS = 'soap-enc'; + const SOAP_ENC_URI = 'http://schemas.xmlsoap.org/soap/encoding/'; + + const XSD_NS = 'xsd'; + const XSD_NS_URI = 'http://www.w3.org/2001/XMLSchema'; + + const TYPES_NS = 'tns'; + + protected $definition; + protected $options; + + protected $version11; + protected $version12; + + protected $document; + protected $domDefinitions; + protected $domSchema; + protected $domService; + protected $domPortType; + + public function __construct(Definition $definition, array $options = array()) + { + $this->definition = $definition; + $this->document = new \DOMDocument('1.0', 'utf-8'); + + $this->setOptions($options); + } + + public function setOptions(array $options) + { + $this->options = array( + 'version11_class' => 'BeSimple\\SoapWsdl\\Dumper\\Version11', + 'version12_class' => 'BeSimple\\SoapWsdl\\Dumper\\Version12', + 'version11_name' => $this->definition->getName(), + 'version12_name' => $this->definition->getName().'12', + ); + + $invalid = array(); + foreach ($options as $key => $value) { + if (array_key_exists($key, $this->options)) { + $this->options[$key] = $value; + } else { + $invalid[] = $key; + } + } + + if ($invalid) { + throw new \InvalidArgumentException(sprintf('The Definition does not support the following options: "%s"', implode('", "', $invalid))); + } + + return $this; + } + + public function setOption($key, $value) + { + if (!array_key_exists($key, $this->options)) { + throw new \InvalidArgumentException(sprintf('The Definition does not support the "%s" option.', $key)); + } + + $this->options[$key] = $value; + + return $this; + } + + public function getOption($key) + { + if (!array_key_exists($key, $this->options)) { + throw new \InvalidArgumentException(sprintf('The Definition does not support the "%s" option.', $key)); + } + + return $this->options[$key]; + } + + public function dump() + { + $this->addDefinitions(); + $this->addMethods(); + $this->addService(); + + foreach (array($this->version11, $this->version12) as $version) { + if (!$version) { + continue; + } + + $this->appendVersion($version); + } + + $this->document->formatOutput = true; + + return $this->document->saveXML(); + } + + protected function appendVersion(VersionInterface $version) + { + $binding = $version->getBindingNode(); + $binding = $this->document->importNode($binding, true); + $this->domDefinitions->appendChild($binding); + + $servicePort = $version->getServicePortNode(); + $servicePort = $this->document->importNode($servicePort, true); + $this->domService->appendChild($servicePort); + } + + protected function addService() + { + $this->domService = $this->document->createElement('service'); + $this->domService->setAttribute('name', $this->definition->getName().'Service'); + + $this->domDefinitions->appendChild($this->domService); + + return $this->domService; + } + + protected function addDefinitions() + { + $this->domDefinitions = $this->document->createElement('definitions'); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS, static::WSDL_NS_URI); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS.':'.static::TYPES_NS, $this->definition->getNamespace()); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS.':'.static::SOAP_NS, static::SOAP_NS_URI); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS.':'.static::SOAP12_NS, static::SOAP12_NS_URI); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS.':'.static::XSD_NS, static::XSD_NS_URI); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS.':'.static::SOAP_ENC_NS, static::SOAP_ENC_URI); + $this->domDefinitions->setAttributeNS(static::XML_NS_URI, static::XML_NS.':'.static::WSDL_NS, static::WSDL_NS_URI); + + foreach ($this->definition->getTypeRepository()->getXmlNamespaces() as $prefix => $uri) { + $this->domDefinitions->setAttributeNs(static::XML_NS_URI, static::XML_NS.':'.$prefix, $uri); + } + + $this->domDefinitions->setAttribute('name', $this->definition->getName()); + $this->domDefinitions->setAttribute('targetNamespace', $this->definition->getNamespace()); + + $this->document->appendChild($this->domDefinitions); + } + + protected function addMethods() + { + $this->addPortType(); + $this->addComplexTypes(); + $this->addMessages($this->definition->getMessages()); + + foreach ($this->definition->getMethods() as $method) { + $this->addPortOperation($method); + + foreach ($method->getVersions() as $version) { + $this->getVersion($version)->addOperation($method); + } + } + } + + protected function addMessages(array $messages) + { + foreach ($messages as $message) { + if ($message->isEmpty()) { + continue; + } + + $messageElement = $this->document->createElement('message'); + $messageElement->setAttribute('name', $message->getName()); + + foreach ($message->all() as $part) { + $type = $this->definition->getTypeRepository()->getType($part->getType()); + + $partElement = $this->document->createElement('part'); + $partElement->setAttribute('name', $part->getName()); + + if ($type instanceof ComplexType) { + $partElement->setAttribute('type', static::TYPES_NS.':'.$type->getXmlType()); + } else { + $partElement->setAttribute('type', $type); + } + + $messageElement->appendChild($partElement); + } + + $this->domDefinitions->appendChild($messageElement); + } + } + + protected function addComplexTypes() + { + $types = $this->document->createElement('types'); + $this->domDefinitions->appendChild($types); + + $this->domSchema = $this->document->createElement(static::XSD_NS.':schema'); + $this->domSchema->setAttribute('targetNamespace', $this->definition->getNamespace()); + $types->appendChild($this->domSchema); + + foreach ($this->definition->getTypeRepository()->getComplexTypes() as $type) { + $this->addComplexType($type); + } + + return $types; + } + + protected function addComplexType(ComplexType $type) + { + $complexType = $this->document->createElement(static::XSD_NS.':complexType'); + $complexType->setAttribute('name', $type->getXmlType()); + + $all = $this->document->createElement(static::XSD_NS.':'.($type instanceof ArrayOfType ? 'sequence' : 'all')); + $complexType->appendChild($all); + + foreach ($type->all() as $child) { + $childType = $this->definition->getTypeRepository()->getType($child->getType()); + + $element = $this->document->createElement(static::XSD_NS.':element'); + $element->setAttribute('name', $child->getName()); + + if ($childType instanceof ComplexType) { + $name = $child->getName(); + if ($childType instanceof ArrayOfType) { + $name = $childType->getName(); + } elseif ($type instanceof ArrayOfType && $childType instanceof ComplexType) { + $name = $childType->getXmlType(); + } + + $element->setAttribute('type', static::TYPES_NS.':'.$name); + } else { + $element->setAttribute('type', $childType); + } + + if ($child->isNillable()) { + $element->setAttribute('nillable', 'true'); + } + + if ($type instanceof ArrayOfType) { + $element->setAttribute('minOccurs', 0); + $element->setAttribute('maxOccurs', 'unbounded'); + } + + $all->appendChild($element); + } + + $this->domSchema->appendChild($complexType); + } + + protected function addPortType() + { + $this->domPortType = $this->document->createElement('portType'); + $this->domPortType->setAttribute('name', $this->definition->getName().'PortType'); + + $this->domDefinitions->appendChild($this->domPortType); + } + + protected function addPortOperation(Method $method) + { + $operation = $this->document->createElement('operation'); + $operation->setAttribute('name', $method->getName()); + + foreach (array('input' => $method->getInput(), 'output' => $method->getOutput(), 'fault' => $method->getFault()) as $type => $message) { + if ($message->isEmpty()) { + continue; + } + + $node = $this->document->createElement($type); + $node->setAttribute('message', static::TYPES_NS.':'.$message->getName()); + + $operation->appendChild($node); + } + + $this->domPortType->appendChild($operation); + + return $operation; + } + + protected function getVersion($version) + { + if (\SOAP_1_2 === $version) { + return $this->getVersion12(); + } + + return $this->getVersion11(); + } + + protected function getVersion11() + { + if (!$this->version11) { + $this->version11 = new $this->options['version11_class']( + static::SOAP_NS, + static::TYPES_NS, + $this->options['version11_name'], + $this->definition->getNamespace(), + static::TYPES_NS.':'.$this->definition->getName().'PortType', + $this->definition->getOption('location'), + $this->definition->getOption('style') + ); + } + + return $this->version11; + } + + protected function getVersion12() + { + if (!$this->version12) { + $this->version12 = new $this->options['version12_class']( + static::SOAP12_NS, + static::TYPES_NS, + $this->options['version12_name'], + $this->definition->getNamespace(), + static::TYPES_NS.':'.$this->definition->getName().'PortType', + $this->definition->getOption('location'), + $this->definition->getOption('style') + ); + } + + return $this->version12; + } +} diff --git a/src/BeSimple/SoapWsdl/Dumper/Version11.php b/src/BeSimple/SoapWsdl/Dumper/Version11.php new file mode 100644 index 0000000..be6d0c8 --- /dev/null +++ b/src/BeSimple/SoapWsdl/Dumper/Version11.php @@ -0,0 +1,24 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapWsdl\Dumper; + +/** + * @author Francis Besset + */ +class Version11 extends AbstractVersion +{ + public function getEncodingStyle() + { + return 'http://schemas.xmlsoap.org/soap/encoding/'; + } +} diff --git a/src/BeSimple/SoapWsdl/Dumper/Version12.php b/src/BeSimple/SoapWsdl/Dumper/Version12.php new file mode 100644 index 0000000..ce65158 --- /dev/null +++ b/src/BeSimple/SoapWsdl/Dumper/Version12.php @@ -0,0 +1,24 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapWsdl\Dumper; + +/** + * @author Francis Besset + */ +class Version12 extends AbstractVersion +{ + public function getEncodingStyle() + { + return 'http://www.w3.org/2001/12/soap-encoding'; + } +} diff --git a/src/BeSimple/SoapWsdl/Dumper/VersionInterface.php b/src/BeSimple/SoapWsdl/Dumper/VersionInterface.php new file mode 100644 index 0000000..fa6b6b8 --- /dev/null +++ b/src/BeSimple/SoapWsdl/Dumper/VersionInterface.php @@ -0,0 +1,29 @@ + + * (c) Francis Besset + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace BeSimple\SoapWsdl\Dumper; + +use BeSimple\SoapCommon\Definition\Method; + +/** + * @author Francis Besset + */ +interface VersionInterface +{ + public function getBindingNode(); + + public function getServicePortNode(); + + public function addOperation(Method $method); + + public function getEncodingStyle(); +}