From 1c608ccf200b22c847f5ce01274d7683561e9a99 Mon Sep 17 00:00:00 2001 From: Francis Besset Date: Sun, 17 Jul 2011 10:46:54 +0200 Subject: [PATCH] The bundle is back! The definition of service has changed, read the README. --- Controller/SoapWebServiceController.php | 95 ++++++++----------- Converter/ConverterRepository.php | 13 +-- Converter/TypeConverterInterface.php | 2 - Converter/XopIncludeTypeConverter.php | 5 +- .../Compiler/WebServiceResolverPass.php | 36 +++++++ DependencyInjection/Configuration.php | 1 - DependencyInjection/WebServiceExtension.php | 55 +++++------ EventListener/ControllerListener.php | 64 +++++++++++++ README.markdown | 66 ++++++++++--- Resources/config/annotations.xml | 30 ------ Resources/config/loaders.xml | 40 ++++++++ .../config/routing/webservicecontroller.xml | 6 +- Resources/config/webservice.xml | 60 ++++-------- ...mentLiteralWrappedRequestMessageBinder.php | 2 +- ...entLiteralWrappedResponseMessageBinder.php | 2 +- .../RpcLiteralRequestMessageBinder.php | 6 +- ServiceBinding/ServiceBinder.php | 23 ++--- .../Annotation/Configuration.php | 30 ++++++ .../Annotation/ConfigurationInterface.php | 26 +++++ ServiceDefinition/Annotation/Method.php | 32 +++++-- ServiceDefinition/Annotation/Param.php | 44 +++++++-- ServiceDefinition/Annotation/Result.php | 32 ++++++- ServiceDefinition/Annotation/TypedElement.php | 40 -------- .../Annotation/TypedElementInterface.php | 19 ++++ ServiceDefinition/Dumper/WsdlDumper.php | 43 ++++----- .../Loader/AnnotationClassLoader.php | 75 +++++++++------ .../Loader/AnnotationFileLoader.php | 15 ++- ServiceDefinition/Loader/AnnotationParser.php | 52 ---------- ServiceDefinition/Loader/AnnotationReader.php | 39 -------- ServiceDefinition/Loader/XmlFileLoader.php | 23 ++--- ServiceDefinition/Method.php | 13 ++- ServiceDefinition/ServiceDefinition.php | 10 +- Soap/SoapAttachment.php | 4 +- Soap/SoapHeader.php | 4 +- Soap/SoapRequest.php | 8 +- Soap/SoapResponse.php | 2 +- Soap/SoapServerFactory.php | 36 +++---- Tests/Soap/SoapRequestTest.php | 2 +- .../{ => Soap}/api-servicedefinition.xml | 0 Tests/fixtures/{ => Soap}/api.wsdl | 0 Tests/fixtures/{ => Soap}/mtom/simple.txt | 0 Util/Assert.php | 6 +- Util/Collection.php | 17 +++- Util/QName.php | 7 +- Util/String.php | 33 ++++--- WebServiceBundle.php | 9 +- WebServiceContext.php | 36 ++++--- vendors.php | 13 ++- 48 files changed, 641 insertions(+), 535 deletions(-) create mode 100644 DependencyInjection/Compiler/WebServiceResolverPass.php create mode 100644 EventListener/ControllerListener.php delete mode 100644 Resources/config/annotations.xml create mode 100644 Resources/config/loaders.xml create mode 100644 ServiceDefinition/Annotation/Configuration.php create mode 100644 ServiceDefinition/Annotation/ConfigurationInterface.php delete mode 100644 ServiceDefinition/Annotation/TypedElement.php create mode 100644 ServiceDefinition/Annotation/TypedElementInterface.php delete mode 100644 ServiceDefinition/Loader/AnnotationParser.php delete mode 100644 ServiceDefinition/Loader/AnnotationReader.php rename Tests/fixtures/{ => Soap}/api-servicedefinition.xml (100%) rename Tests/fixtures/{ => Soap}/api.wsdl (100%) rename Tests/fixtures/{ => Soap}/mtom/simple.txt (100%) diff --git a/Controller/SoapWebServiceController.php b/Controller/SoapWebServiceController.php index 5c6b6b3..0970a18 100644 --- a/Controller/SoapWebServiceController.php +++ b/Controller/SoapWebServiceController.php @@ -10,28 +10,14 @@ namespace Bundle\WebServiceBundle\Controller; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; - -use Symfony\Component\HttpKernel\HttpKernelInterface; - -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\ContainerAware; - use Bundle\WebServiceBundle\Soap\SoapRequest; use Bundle\WebServiceBundle\Soap\SoapResponse; -use Bundle\WebServiceBundle\Soap\SoapHeader; -use Bundle\WebServiceBundle\Soap\SoapServerFactory; -use Bundle\WebServiceBundle\ServiceBinding\ServiceBinder; - -use Bundle\WebServiceBundle\Converter\ConverterRepository; - -use Bundle\WebServiceBundle\Util\String; +use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * - * * @author Christian Kerl */ class SoapWebServiceController extends ContainerAware @@ -57,54 +43,33 @@ class SoapWebServiceController extends ContainerAware protected $serviceBinder; /** - * @var \Symfony\Component\HttpKernel\HttpKernelInterface + * @return \Bundle\WebServiceBundle\Soap\SoapResponse */ - protected $kernel; - - public function __construct(ContainerInterface $container, HttpKernelInterface $kernel) + public function callAction($webservice) { - $this->setContainer($container); - $this->kernel = $kernel; - } - - public function getRequest() - { - return $this->soapRequest; - } - - public function getResponse() - { - return $this->soapResponse; - } - - public function call($webservice) - { - $webServiceContext = $this->container->get('webservice.context.' . $webservice); - - $this->soapRequest = SoapRequest::createFromHttpRequest($this->container->get('request')); - + $webServiceContext = $this->container->get('webservice.context.'.$webservice); $this->serviceBinder = $webServiceContext->getServiceBinder(); - $this->soapServer = $webServiceContext->getServerFactory()->create($this->soapRequest, $this->soapResponse); + $this->soapRequest = SoapRequest::createFromHttpRequest($this->container->get('request')); + $this->soapServer = $webServiceContext->getServerFactory()->create($this->soapRequest, $this->soapResponse); $this->soapServer->setObject($this); ob_start(); - { - $this->soapServer->handle($this->soapRequest->getSoapMessage()); - } - $soapResponseContent = ob_get_clean(); - - $this->soapResponse->setContent($soapResponseContent); + $this->soapServer->handle($this->soapRequest->getSoapMessage()); + $this->soapResponse->setContent(ob_get_clean()); return $this->soapResponse; } - public function definition($webservice) + /** + * @return Symfony\Component\HttpFoundation\Response + */ + public function definitionAction($webservice) { - $webServiceContext = $this->container->get('webservice.context.' . $webservice); - $request = $this->container->get('request'); + $webServiceContext = $this->container->get('webservice.context.'.$webservice); + $request = $this->container->get('request'); - if($request->query->has('WSDL')) { + if ($request->query->has('wsdl') || $request->query->has('WSDL')) { $endpoint = $this->container->get('router')->generate('_webservice_call', array('webservice' => $webservice), true); $response = new Response($webServiceContext->getWsdlFileContent($endpoint)); @@ -129,7 +94,7 @@ class SoapWebServiceController extends ContainerAware */ public function __call($method, $arguments) { - if($this->serviceBinder->isServiceHeader($method)) { + if ($this->serviceBinder->isServiceHeader($method)) { // collect request soap headers $this->soapRequest->getSoapHeaders()->add( $this->serviceBinder->processServiceHeader($method, $arguments[0]) @@ -138,18 +103,18 @@ class SoapWebServiceController extends ContainerAware return; } - if($this->serviceBinder->isServiceMethod($method)) { + if ($this->serviceBinder->isServiceMethod($method)) { $this->soapRequest->attributes->add( $this->serviceBinder->processServiceMethodArguments($method, $arguments) ); // forward to controller - $response = $this->kernel->handle($this->soapRequest, HttpKernelInterface::SUB_REQUEST, false); + $response = $this->container->get('http_kernel')->handle($this->soapRequest, HttpKernelInterface::SUB_REQUEST, false); $this->soapResponse = $this->checkResponse($response); // add response soap headers to soap server - foreach($this->soapResponse->getSoapHeaders() as $header) { + foreach ($this->soapResponse->getSoapHeaders() as $header) { $this->soapServer->addSoapHeader($header->toNativeSoapHeader()); } @@ -172,10 +137,26 @@ class SoapWebServiceController extends ContainerAware */ protected function checkResponse(Response $response) { - if($response == null || !$response instanceof SoapResponse) { + if (null === $response || !$response instanceof SoapResponse) { throw new \InvalidArgumentException(); } return $response; } + + /** + * @return \Bundle\WebServiceBundle\Soap\SoapRequest + */ + public function getRequest() + { + return $this->soapRequest; + } + + /** + * @return \Bundle\WebServiceBundle\Soap\SoapResponse + */ + public function getResponse() + { + return $this->soapResponse; + } } \ No newline at end of file diff --git a/Converter/ConverterRepository.php b/Converter/ConverterRepository.php index 8882a4d..536a654 100644 --- a/Converter/ConverterRepository.php +++ b/Converter/ConverterRepository.php @@ -10,22 +10,15 @@ namespace Bundle\WebServiceBundle\Converter; -/** - * - * @author Christian Kerl - */ -use Bundle\WebServiceBundle\SoapKernel; - use Symfony\Component\DependencyInjection\ContainerInterface; +/** + * @author Christian Kerl + */ class ConverterRepository { private $typeConverters = array(); - public function __construct() - { - } - public function addTypeConverter(TypeConverterInterface $converter) { $this->typeConverters[] = $converter; diff --git a/Converter/TypeConverterInterface.php b/Converter/TypeConverterInterface.php index 096cb0b..4945f8e 100644 --- a/Converter/TypeConverterInterface.php +++ b/Converter/TypeConverterInterface.php @@ -11,11 +11,9 @@ namespace Bundle\WebServiceBundle\Converter; use Bundle\WebServiceBundle\Soap\SoapRequest; - use Bundle\WebServiceBundle\Soap\SoapResponse; /** - * * @author Christian Kerl */ interface TypeConverterInterface diff --git a/Converter/XopIncludeTypeConverter.php b/Converter/XopIncludeTypeConverter.php index 7f1037c..39d6e2f 100644 --- a/Converter/XopIncludeTypeConverter.php +++ b/Converter/XopIncludeTypeConverter.php @@ -11,13 +11,10 @@ namespace Bundle\WebServiceBundle\Converter; use Bundle\WebServiceBundle\Soap\SoapRequest; - use Bundle\WebServiceBundle\Soap\SoapResponse; - use Bundle\WebServiceBundle\Util\String; /** - * * @author Christian Kerl */ class XopIncludeTypeConverter implements TypeConverterInterface @@ -42,7 +39,7 @@ class XopIncludeTypeConverter implements TypeConverterInterface $ref = $include->getAttribute('href'); - if(String::startsWith($ref, 'cid:')) { + if (String::startsWith($ref, 'cid:')) { $cid = urldecode(substr($ref, 4)); return $request->getSoapAttachments()->get($cid)->getContent(); diff --git a/DependencyInjection/Compiler/WebServiceResolverPass.php b/DependencyInjection/Compiler/WebServiceResolverPass.php new file mode 100644 index 0000000..0969848 --- /dev/null +++ b/DependencyInjection/Compiler/WebServiceResolverPass.php @@ -0,0 +1,36 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + +/** + * Adds tagged webservice.definition.loader services to ebservice.definition.resolver service + * + * @author Francis Besset + */ +class WebServiceResolverPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (false === $container->hasDefinition('webservice.definition.loader.resolver')) { + return; + } + + $definition = $container->getDefinition('webservice.definition.loader.resolver'); + + foreach ($container->findTaggedServiceIds('webservice.definition.loader') as $id => $attributes) { + $definition->addMethodCall('addLoader', array(new Reference($id))); + } + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 2f83de3..cb280c6 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -10,7 +10,6 @@ namespace Bundle\WebServiceBundle\DependencyInjection; -use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; /** diff --git a/DependencyInjection/WebServiceExtension.php b/DependencyInjection/WebServiceExtension.php index c87aaa7..12e3d63 100644 --- a/DependencyInjection/WebServiceExtension.php +++ b/DependencyInjection/WebServiceExtension.php @@ -10,16 +10,12 @@ namespace Bundle\WebServiceBundle\DependencyInjection; -use Bundle\WebServiceBundle\Util\Assert; - -use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Definition\Processor; - +use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; - use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** @@ -29,6 +25,8 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; */ class WebServiceExtension extends Extension { + private $contextArguments; + // maps config options to service suffix' private $bindingConfigToServiceSuffixMap = array('rpc-literal' => '.rpcliteral', 'document-wrapped' => '.documentwrapped'); @@ -36,47 +34,46 @@ class WebServiceExtension extends Extension { $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('annotations.xml'); + $loader->load('loaders.xml'); $loader->load('webservice.xml'); - $processor = new Processor(); + $processor = new Processor(); $configuration = new Configuration(); $config = $processor->process($configuration->getConfigTree(), $configs); foreach($config['services'] as $name => $serviceConfig) { - $this->createWebServiceContext($name, $serviceConfig, $container); + $serviceConfig['name'] = $name; + $this->createWebServiceContext($serviceConfig, $container); } } - private function createWebServiceContext($name, array $config, ContainerBuilder $container) + private function createWebServiceContext(array $config, ContainerBuilder $container) { - $bindingDependentArguments = array(1, 3, 4); $bindingSuffix = $this->bindingConfigToServiceSuffixMap[$config['binding']]; unset($config['binding']); - $contextPrototype = $container->getDefinition('webservice.context'); - $contextPrototypeArguments = $contextPrototype->getArguments(); + if (null === $this->contextArguments) { + $this->contextArguments = $container + ->getDefinition('webservice.context') + ->getArguments() + ; + } - $contextId = 'webservice.context.'.$name; - $context = $container->setDefinition($contextId, new DefinitionDecorator('webservice.context')); + $contextId = 'webservice.context.'.$config['name']; + $context = $container->setDefinition($contextId, $definition = new DefinitionDecorator('webservice.context')); $arguments = array(); - foreach($bindingDependentArguments as $idx) { - $arguments[] = new Reference($contextPrototypeArguments[$idx].$bindingSuffix); + foreach($this->contextArguments as $i => $argument) { + if (in_array($i, array(1, 3, 4))) { + $argument = new Reference($argument->__toString().$bindingSuffix); + } elseif (5 === $i) { + $argument = array_merge($argument, $config); + } else { + $argument = new Reference($argument->__toString()); + } + + $definition->replaceArgument($i, $argument); } - $arguments[5] = array_merge($contextPrototypeArguments[5], $config); - - $context->setArguments($arguments); - } - - public function getNamespace() - { - return null; - } - - public function getXsdValidationBasePath() - { - return null; } } \ No newline at end of file diff --git a/EventListener/ControllerListener.php b/EventListener/ControllerListener.php new file mode 100644 index 0000000..5612372 --- /dev/null +++ b/EventListener/ControllerListener.php @@ -0,0 +1,64 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\EventListener; + +use Bundle\WebServiceBundle\ServiceDefinition\Annotation\ConfigurationInterface; + +use Doctrine\Common\Annotations\Reader; + +use Symfony\Component\HttpKernel\Event\FilterControllerEvent; + +/** + * Based on \Sensio\Bundle\FrameworkExtraBundle\EventListener\ControllerListener + * + * @author Francis Besset + */ +class ControllerListener +{ + /** + * @var \Doctrine\Common\Annotations\Reader + */ + protected $reader; + + /** + * Constructor. + * + * @param Reader $reader An Reader instance + */ + public function __construct(Reader $reader) + { + $this->reader = $reader; + } + + /** + * Modifies the Request object to apply configuration information found in + * controllers annotations like the template to render or HTTP caching + * configuration. + * + * @param FilterControllerEvent $event A FilterControllerEvent instance + */ + public function onKernelController(FilterControllerEvent $event) + { + if (!is_array($controller = $event->getController())) { + return; + } + + $object = new \ReflectionObject($controller[0]); + $method = $object->getMethod($controller[1]); + + $request = $event->getRequest(); + foreach ($this->reader->getMethodAnnotations($method) as $configuration) { + if ($configuration instanceof ConfigurationInterface) { + $request->attributes->set('_'.$configuration->getAliasName(), $configuration); + } + } + } +} \ No newline at end of file diff --git a/README.markdown b/README.markdown index 93d6f52..6d8f6d8 100644 --- a/README.markdown +++ b/README.markdown @@ -8,14 +8,46 @@ Requirements ------------ * Install and enable PHP's `SOAP` extension - * Download and add `Zend\Soap` library to `app/autoload.php` + * Download `Zend\Soap` + + git submodule add http://github.com/zendframework/zf2.git vendor/zend-framework + + * Add `Zend\Soap` library to `app/autoload.php` + + // app/autoload.php + $loader->registerNamespaces(array( + 'Zend\\Soap' => __DIR__.'/../vendor/zend-frameword/library', + // your other namespaces + )); QuickStart ---------- - * Put WebServiceBundle in your `src/Bundle` dir + * Put WebServiceBundle in your `vendor/bundles/Bundle` dir + + git submodule add https://github.com/BeSimple/BeSimpleSoapBundle.git vendor/bundles/WebServiceBundle + * Enable WebServiceBundle in your `app/AppKernel.php` + // app/AppKernel.php + public function registerBundles() + { + return array( + // ... + new new Bundle\WebServiceBundle\WebServiceBundle(), + // ... + ); + } + + * Register the Bundle namespace + + // app/autoload.php + $loader->registerNamespaces(array( + 'Bundle' => __DIR__.'/../vendor/bundles', + 'Zend\\Soap' => __DIR__.'/../vendor/zend-frameword/library', + // your other namespaces + )); + * Include the WebServiceBundle's routing configuration in `app/config/routing.yml` (you can choose the prefix arbitrarily) _ws: @@ -27,32 +59,40 @@ QuickStart web_service: services: DemoApi: - namespace: http://mysymfonyapp.com/ws/DemoApi/1.0/ + namespace: http://mysymfonyapp.com/ws/DemoApi/1.0/ binding: rpc-literal resource: "@AcmeDemoBundle/Controller/DemoController.php" resource_type: annotation * Annotate your controller methods - + // src/Acme/DemoBundle/Controller/DemoController.php - /** - * @ws:Method("Hello") - * @ws:Param("name", type = "string") - * @ws:Result(type = "string") - */ - public function helloAction($name) + use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Method; + use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Param; + use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Result; + use Bundle\WebServiceBundle\Soap\SoapResponse; + + class DemoController extends Controller { - return new SoapResponse(sprintf('Hello %s!', $name)); + /** + * @Method("Hello") + * @Param("name", phpType = "string") + * @Result(phpType = "string") + */ + public function helloAction($name) + { + return new SoapResponse(sprintf('Hello %s!', $name)); + } } * Open your web service endpoint * `http://localhost/app_dev.php/ws/DemoApi` - HTML documentation - * `http://localhost/app_dev.php/ws/DemoApi?WSDL` - WSDL file + * `http://localhost/app_dev.php/ws/DemoApi?wsdl` - WSDL file Test ---- - phpunit -c myapp src/Bundle/WebServiceBundle + phpunit -c phpunit.xml.dist [1]: http://www.symfony-project.org/plugins/ckWebServicePlugin \ No newline at end of file diff --git a/Resources/config/annotations.xml b/Resources/config/annotations.xml deleted file mode 100644 index 9b10ecf..0000000 --- a/Resources/config/annotations.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationReader - Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationParser - - - - - true - - Bundle\WebServiceBundle\ServiceDefinition\Annotation\ - ws - - - - - - - - - - - - - diff --git a/Resources/config/loaders.xml b/Resources/config/loaders.xml new file mode 100644 index 0000000..888d1ad --- /dev/null +++ b/Resources/config/loaders.xml @@ -0,0 +1,40 @@ + + + + + + Bundle\WebServiceBundle\EventListener\ControllerListener + Symfony\Component\Config\Loader\LoaderResolver + Symfony\Component\Config\Loader\DelegatingLoader + Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationDirectoryLoader + Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationFileLoader + Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationClassLoader + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Resources/config/routing/webservicecontroller.xml b/Resources/config/routing/webservicecontroller.xml index ae2c83b..a3e3df9 100644 --- a/Resources/config/routing/webservicecontroller.xml +++ b/Resources/config/routing/webservicecontroller.xml @@ -5,12 +5,14 @@ xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - webservice.controller:call + WebServiceBundle:SoapWebService:Call + xml POST - webservice.controller:definition + WebServiceBundle:SoapWebService:Definition + xml GET diff --git a/Resources/config/webservice.xml b/Resources/config/webservice.xml index 7fcdd2f..ebd14d4 100644 --- a/Resources/config/webservice.xml +++ b/Resources/config/webservice.xml @@ -4,64 +4,44 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - Symfony\Component\HttpKernel\Config\FileLocator - + Bundle\WebServiceBundle\Controller\SoapWebServiceController + Bundle\WebServiceBundle\WebServiceContext %kernel.cache_dir%/webservice + Bundle\WebServiceBundle\ServiceBinding\RpcLiteralRequestMessageBinder + Bundle\WebServiceBundle\ServiceBinding\RpcLiteralResponseMessageBinder + Bundle\WebServiceBundle\ServiceBinding\DocumentLiteralWrappedRequestMessageBinder + Bundle\WebServiceBundle\ServiceBinding\DocumentLiteralWrappedResponseMessageBinder + Bundle\WebServiceBundle\ServiceDefinition\Dumper\WsdlDumper + Bundle\WebServiceBundle\Converter\ConverterRepository - - - - - - + - %webservice.cache_dir% - - - - + - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/ServiceBinding/DocumentLiteralWrappedRequestMessageBinder.php b/ServiceBinding/DocumentLiteralWrappedRequestMessageBinder.php index df3e118..66b07a7 100644 --- a/ServiceBinding/DocumentLiteralWrappedRequestMessageBinder.php +++ b/ServiceBinding/DocumentLiteralWrappedRequestMessageBinder.php @@ -20,7 +20,7 @@ class DocumentLiteralWrappedRequestMessageBinder implements MessageBinderInterfa throw new \InvalidArgumentException(); } - $result = array(); + $result = array(); $message = $message[0]; foreach($messageDefinition->getArguments() as $argument) { diff --git a/ServiceBinding/DocumentLiteralWrappedResponseMessageBinder.php b/ServiceBinding/DocumentLiteralWrappedResponseMessageBinder.php index 9138fe2..5806852 100644 --- a/ServiceBinding/DocumentLiteralWrappedResponseMessageBinder.php +++ b/ServiceBinding/DocumentLiteralWrappedResponseMessageBinder.php @@ -17,7 +17,7 @@ class DocumentLiteralWrappedResponseMessageBinder implements MessageBinderInterf public function processMessage(Method $messageDefinition, $message) { $result = new \stdClass(); - $result->{$messageDefinition->getName() . 'Result'} = $message; + $result->{$messageDefinition->getName().'Result'} = $message; return $result; } diff --git a/ServiceBinding/RpcLiteralRequestMessageBinder.php b/ServiceBinding/RpcLiteralRequestMessageBinder.php index d845ed6..2269afc 100644 --- a/ServiceBinding/RpcLiteralRequestMessageBinder.php +++ b/ServiceBinding/RpcLiteralRequestMessageBinder.php @@ -17,10 +17,12 @@ class RpcLiteralRequestMessageBinder implements MessageBinderInterface public function processMessage(Method $messageDefinition, $message) { $result = array(); - $i = 0; + $i = 0; foreach($messageDefinition->getArguments() as $argument) { - $result[$argument->getName()] = $message[$i]; + if (isset($message[$i])) { + $result[$argument->getName()] = $message[$i]; + } $i++; } diff --git a/ServiceBinding/ServiceBinder.php b/ServiceBinding/ServiceBinder.php index abf0430..c2f860b 100644 --- a/ServiceBinding/ServiceBinder.php +++ b/ServiceBinding/ServiceBinder.php @@ -10,16 +10,10 @@ namespace Bundle\WebServiceBundle\ServiceBinding; -use Bundle\WebServiceBundle\Util\QName; - -use Bundle\WebServiceBundle\ServiceDefinition\Type; - -use Bundle\WebServiceBundle\Soap\SoapHeader; - -use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; use Bundle\WebServiceBundle\ServiceDefinition\Header; -use Bundle\WebServiceBundle\ServiceDefinition\Dumper\DumperInterface; -use Bundle\WebServiceBundle\ServiceDefinition\Loader\LoaderInterface; +use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; +use Bundle\WebServiceBundle\Soap\SoapHeader; +use Bundle\WebServiceBundle\Util\QName; class ServiceBinder { @@ -28,11 +22,6 @@ class ServiceBinder */ private $definition; - /** - * @var \Bundle\WebServiceBundle\ServiceDefinition\Dumper\DumperInterface - */ - private $definitionDumper; - /** * @var \Bundle\WebServiceBundle\ServiceBinding\MessageBinderInterface */ @@ -51,7 +40,7 @@ class ServiceBinder { $this->definition = $definition; - $this->requestMessageBinder = $requestMessageBinder; + $this->requestMessageBinder = $requestMessageBinder; $this->responseMessageBinder = $responseMessageBinder; } @@ -76,9 +65,9 @@ class ServiceBinder { $methodDefinition = $this->definition->getMethods()->get($name); - $result = array(); + $result = array(); $result['_controller'] = $methodDefinition->getController(); - $result = array_merge($result, $this->requestMessageBinder->processMessage($methodDefinition, $arguments)); + $result = array_merge($result, $this->requestMessageBinder->processMessage($methodDefinition, $arguments)); return $result; } diff --git a/ServiceDefinition/Annotation/Configuration.php b/ServiceDefinition/Annotation/Configuration.php new file mode 100644 index 0000000..2df78b2 --- /dev/null +++ b/ServiceDefinition/Annotation/Configuration.php @@ -0,0 +1,30 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; + +/** + * Based on \Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation + * + * @author Francis Besset + */ +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); + } + } +} \ No newline at end of file diff --git a/ServiceDefinition/Annotation/ConfigurationInterface.php b/ServiceDefinition/Annotation/ConfigurationInterface.php new file mode 100644 index 0000000..3c910bf --- /dev/null +++ b/ServiceDefinition/Annotation/ConfigurationInterface.php @@ -0,0 +1,26 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; + +/** + * Based on \Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface + * + * @author Francis Besset + */ +interface ConfigurationInterface +{ + /** + * Returns the alias name for an annotated configuration. + * + * @return string + */ + function getAliasName(); +} \ No newline at end of file diff --git a/ServiceDefinition/Annotation/Method.php b/ServiceDefinition/Annotation/Method.php index 2c0b53e..faf5ae4 100644 --- a/ServiceDefinition/Annotation/Method.php +++ b/ServiceDefinition/Annotation/Method.php @@ -10,24 +10,36 @@ namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; -class Method +/** + * @Annotation + */ +class Method extends Configuration { - private $name; + private $value; private $service; - public function __construct($values) + public function getValue() { - $this->name = isset($values['value']) ? $values['value'] : null; - $this->service = isset($values['service']) ? $values['service'] : null; - } - - public function getName($default = null) - { - return $this->name !== null ? $this->name : $default; + 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'; + } } \ No newline at end of file diff --git a/ServiceDefinition/Annotation/Param.php b/ServiceDefinition/Annotation/Param.php index 6bb4f0d..932fef3 100644 --- a/ServiceDefinition/Annotation/Param.php +++ b/ServiceDefinition/Annotation/Param.php @@ -10,19 +10,47 @@ namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; -class Param extends TypedElement +/** + * @Annotation + */ +class Param extends Configuration implements TypedElementInterface { - private $name; + private $value; + private $phpType; + private $xmlType; - public function __construct($values) + public function getValue() { - parent::__construct($values); - - $this->name = $values['value']; + return $this->value; } - public function getName() + public function getPhpType() { - return $this->name; + 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'; } } \ No newline at end of file diff --git a/ServiceDefinition/Annotation/Result.php b/ServiceDefinition/Annotation/Result.php index 596c5d2..c56a587 100644 --- a/ServiceDefinition/Annotation/Result.php +++ b/ServiceDefinition/Annotation/Result.php @@ -10,10 +10,36 @@ namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; -class Result extends TypedElement +/** + * @Annotation + */ +class Result extends Configuration implements TypedElementInterface { - public function __construct($values) + private $phpType; + private $xmlType; + + public function getPhpType() { - parent::__construct($values); + 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'; } } \ No newline at end of file diff --git a/ServiceDefinition/Annotation/TypedElement.php b/ServiceDefinition/Annotation/TypedElement.php deleted file mode 100644 index 9d7209c..0000000 --- a/ServiceDefinition/Annotation/TypedElement.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; - -abstract class TypedElement -{ - private $phpType; - private $xmlType; - - public function __construct($values) - { - foreach(array('type', 'phpType') as $key) - { - if(isset($values[$key])) - { - $this->phpType = $values[$key]; - } - } - - $this->xmlType = isset($values['xmlType']) ? $values['xmlType'] : null; - } - - public function getPhpType() - { - return $this->phpType; - } - - public function getXmlType() - { - return $this->xmlType; - } -} \ No newline at end of file diff --git a/ServiceDefinition/Annotation/TypedElementInterface.php b/ServiceDefinition/Annotation/TypedElementInterface.php new file mode 100644 index 0000000..b6c4fe5 --- /dev/null +++ b/ServiceDefinition/Annotation/TypedElementInterface.php @@ -0,0 +1,19 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Bundle\WebServiceBundle\ServiceDefinition\Annotation; + +interface TypedElementInterface +{ + function getPhpType(); + function getXmlType(); + function setPhpType($phpType); + function setXmlType($xmlType); +} \ No newline at end of file diff --git a/ServiceDefinition/Dumper/WsdlDumper.php b/ServiceDefinition/Dumper/WsdlDumper.php index c21556d..405d762 100644 --- a/ServiceDefinition/Dumper/WsdlDumper.php +++ b/ServiceDefinition/Dumper/WsdlDumper.php @@ -12,14 +12,11 @@ namespace Bundle\WebServiceBundle\ServiceDefinition\Dumper; use Bundle\WebServiceBundle\ServiceDefinition\Method; use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; - use Bundle\WebServiceBundle\Util\Assert; use Zend\Soap\Wsdl; - /** - * * @author Christian Kerl */ class WsdlDumper implements DumperInterface @@ -28,22 +25,20 @@ class WsdlDumper implements DumperInterface public function dumpServiceDefinition(ServiceDefinition $definition, array $options = array()) { - Assert::thatArgumentNotNull('definition', $definition); - $options = array_merge(array('endpoint' => ''), $options); + Assert::thatArgumentNotNull('definition', $definition); + $this->definition = $definition; - - $wsdl = new Wsdl($definition->getName(), $definition->getNamespace()); - - $port = $wsdl->addPortType($this->getPortTypeName()); - $binding = $wsdl->addBinding($this->getBindingName(), 'tns:' . $this->getPortTypeName()); + $wsdl = new Wsdl($definition->getName(), $definition->getNamespace()); + $port = $wsdl->addPortType($this->getPortTypeName()); + $binding = $wsdl->addBinding($this->getBindingName(), 'tns:' . $this->getPortTypeName()); $wsdl->addSoapBinding($binding, 'rpc'); $wsdl->addService($this->getServiceName(), $this->getPortName(), 'tns:' . $this->getBindingName(), $options['endpoint']); foreach($definition->getMethods() as $method) { - $requestParts = array(); + $requestParts = array(); $responseParts = array(); foreach($method->getArguments() as $argument) { @@ -61,15 +56,15 @@ class WsdlDumper implements DumperInterface $portOperation->setAttribute('parameterOrder', implode(' ', array_keys($requestParts))); $bindingInput = array( - 'parts' => implode(' ', array_keys($requestParts)), - 'use' => 'literal', - 'namespace' => $definition->getNamespace(), + 'parts' => implode(' ', array_keys($requestParts)), + 'use' => 'literal', + 'namespace' => $definition->getNamespace(), 'encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/', ); $bindingOutput = array( - 'parts' => implode(' ', array_keys($responseParts)), - 'use' => 'literal', - 'namespace' => $definition->getNamespace(), + 'parts' => implode(' ', array_keys($responseParts)), + 'use' => 'literal', + 'namespace' => $definition->getNamespace(), 'encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/', ); @@ -86,36 +81,36 @@ class WsdlDumper implements DumperInterface protected function getPortName() { - return $this->definition->getName() . 'Port'; + return $this->definition->getName().'Port'; } protected function getPortTypeName() { - return $this->definition->getName() . 'PortType'; + return $this->definition->getName().'PortType'; } protected function getBindingName() { - return $this->definition->getName() . 'Binding'; + return $this->definition->getName().'Binding'; } protected function getServiceName() { - return $this->definition->getName() . 'Service'; + return $this->definition->getName().'Service'; } protected function getRequestMessageName(Method $method) { - return $method->getName() . 'Request'; + return $method->getName().'Request'; } protected function getResponseMessageName(Method $method) { - return $method->getName() . 'Response'; + return $method->getName().'Response'; } protected function getSoapOperationName(Method $method) { - return $this->definition->getNamespace() . $method->getName(); + return $this->definition->getNamespace().$method->getName(); } } \ No newline at end of file diff --git a/ServiceDefinition/Loader/AnnotationClassLoader.php b/ServiceDefinition/Loader/AnnotationClassLoader.php index 4c97c34..bbbada0 100644 --- a/ServiceDefinition/Loader/AnnotationClassLoader.php +++ b/ServiceDefinition/Loader/AnnotationClassLoader.php @@ -8,17 +8,17 @@ * with this source code in the file LICENSE. */ - namespace Bundle\WebServiceBundle\ServiceDefinition\Loader; - - -use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; -use Bundle\WebServiceBundle\ServiceDefinition\Method; use Bundle\WebServiceBundle\ServiceDefinition\Argument; +use Bundle\WebServiceBundle\ServiceDefinition\Method; use Bundle\WebServiceBundle\ServiceDefinition\Type; - +use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Method as MethodAnnotation; +use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Param as ParamAnnotation; +use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Result as ResultAnnotation; + +use Doctrine\Common\Annotations\Reader; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderResolver; @@ -32,18 +32,18 @@ use Symfony\Component\Config\Loader\LoaderResolver; */ class AnnotationClassLoader implements LoaderInterface { - private $wsMethodAnnotationClass = 'Bundle\\WebServiceBundle\\ServiceDefinition\\Annotation\\Method'; - private $wsParamAnnotationClass = 'Bundle\\WebServiceBundle\\ServiceDefinition\\Annotation\\Param'; - private $wsResultAnnotationClass = 'Bundle\\WebServiceBundle\\ServiceDefinition\\Annotation\\Result'; + private $methodAnnotationClass = 'Bundle\\WebServiceBundle\\ServiceDefinition\\Annotation\\Method'; + private $paramAnnotationClass = 'Bundle\\WebServiceBundle\\ServiceDefinition\\Annotation\\Param'; + private $resultAnnotationClass = 'Bundle\\WebServiceBundle\\ServiceDefinition\\Annotation\\Result'; protected $reader; /** * Constructor. * - * @param AnnotationReader $reader + * @param \Doctrine\Common\Annotations\Reader $reader */ - public function __construct(AnnotationReader $reader) + public function __construct(Reader $reader) { $this->reader = $reader; } @@ -64,31 +64,46 @@ class AnnotationClassLoader implements LoaderInterface throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); } - $class = new \ReflectionClass($class); - + $class = new \ReflectionClass($class); $definition = new ServiceDefinition(); - foreach ($class->getMethods() as $method) { - $wsMethodAnnot = $this->reader->getMethodAnnotation($method, $this->wsMethodAnnotationClass); + $serviceArguments = array(); + $serviceMethod = + $serviceReturn = null; - if($wsMethodAnnot !== null) { - $wsParamAnnots = $this->reader->getMethodAnnotations($method, $this->wsParamAnnotationClass); - $wsResultAnnot = $this->reader->getMethodAnnotation($method, $this->wsResultAnnotationClass); + foreach ($this->reader->getMethodAnnotations($method) as $i => $annotation) { + if ($annotation instanceof ParamAnnotation) { + $serviceArguments[] = new Argument( + $annotation->getValue(), + new Type($annotation->getPhpType(), $annotation->getXmlType()) + ); + } elseif ($annotation instanceof MethodAnnotation) { + if ($serviceMethod) { + throw new \LogicException(sprintf('@Method defined twice for "%s".', $method->getName())); + } - $serviceMethod = new Method(); - $serviceMethod->setName($wsMethodAnnot->getName($method->getName())); - $serviceMethod->setController($this->getController($method, $wsMethodAnnot)); + $serviceMethod = new Method( + $annotation->getValue(), + $this->getController($method, $annotation) + ); + } elseif ($annotation instanceof ResultAnnotation) { + if ($serviceReturn) { + throw new \LogicException(sprintf('@Result defined twice for "%s".', $method->getName())); + } - foreach($wsParamAnnots as $wsParamAnnot) { - $serviceArgument = new Argument(); - $serviceArgument->setName($wsParamAnnot->getName()); - $serviceArgument->setType(new Type($wsParamAnnot->getPhpType(), $wsParamAnnot->getXmlType())); - - $serviceMethod->getArguments()->add($serviceArgument); + $serviceReturn = new Type($annotation->getPhpType(), $annotation->getXmlType()); } + } - if($wsResultAnnot !== null) { - $serviceMethod->setReturn(new Type($wsResultAnnot->getPhpType(), $wsResultAnnot->getXmlType())); + if (!$serviceMethod && (!empty($serviceArguments) || $serviceReturn)) { + throw new \LogicException(sprintf('@Method non-existent for "%s".', $method->getName())); + } + + if ($serviceMethod) { + $serviceMethod->setArguments($serviceArguments); + + if ($serviceReturn) { + $serviceMethod->setReturn($serviceReturn); } $definition->getMethods()->add($serviceMethod); @@ -100,7 +115,7 @@ class AnnotationClassLoader implements LoaderInterface private function getController(\ReflectionMethod $method, MethodAnnotation $annotation) { - if($annotation->getService() !== null) { + if(null !== $annotation->getService()) { return $annotation->getService() . ':' . $method->name; } else { return $method->class . '::' . $method->name; diff --git a/ServiceDefinition/Loader/AnnotationFileLoader.php b/ServiceDefinition/Loader/AnnotationFileLoader.php index 6d7f405..688e406 100644 --- a/ServiceDefinition/Loader/AnnotationFileLoader.php +++ b/ServiceDefinition/Loader/AnnotationFileLoader.php @@ -8,14 +8,13 @@ * with this source code in the file LICENSE. */ - namespace Bundle\WebServiceBundle\ServiceDefinition\Loader; use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; -use Symfony\Component\Config\Resource\FileResource; -use Symfony\Component\Config\Loader\FileLoader; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Loader\FileLoader; +use Symfony\Component\Config\Resource\FileResource; /** * AnnotationFileLoader loads ServiceDefinition from annotations set @@ -60,13 +59,11 @@ class AnnotationFileLoader extends FileLoader { $path = $this->locator->locate($file); - $definition = new ServiceDefinition(); - if ($class = $this->findClass($path)) { - $definition = $this->loader->load($class, $type); + return $definition = $this->loader->load($class, $type); } - return $definition; + return null; } /** @@ -91,9 +88,9 @@ class AnnotationFileLoader extends FileLoader */ protected function findClass($file) { - $class = false; + $class = false; $namespace = false; - $tokens = token_get_all(file_get_contents($file)); + $tokens = token_get_all(file_get_contents($file)); while ($token = array_shift($tokens)) { if (!is_array($token)) { continue; diff --git a/ServiceDefinition/Loader/AnnotationParser.php b/ServiceDefinition/Loader/AnnotationParser.php deleted file mode 100644 index afd9c1b..0000000 --- a/ServiceDefinition/Loader/AnnotationParser.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Bundle\WebServiceBundle\ServiceDefinition\Loader; - -use Doctrine\Common\Annotations\Lexer; -use Doctrine\Common\Annotations\Parser; - -/** - * AnnotationParser allows multiple annotations of the same class to be present. - * - * @author Christian Kerl - */ -class AnnotationParser extends Parser -{ - /** - * Annotations ::= Annotation {[ "*" ]* [Annotation]}* - * - * @return array - */ - public function Annotations() - { - $this->isNestedAnnotation = false; - - $annotations = array(); - $annot = $this->Annotation(); - - if ($annot !== false) { - $annotations[get_class($annot)][] = $annot; - $this->getLexer()->skipUntil(Lexer::T_AT); - } - - while ($this->getLexer()->lookahead !== null && $this->getLexer()->isNextToken(Lexer::T_AT)) { - $this->isNestedAnnotation = false; - $annot = $this->Annotation(); - - if ($annot !== false) { - $annotations[get_class($annot)][] = $annot; - $this->getLexer()->skipUntil(Lexer::T_AT); - } - } - - return $annotations; - } -} \ No newline at end of file diff --git a/ServiceDefinition/Loader/AnnotationReader.php b/ServiceDefinition/Loader/AnnotationReader.php deleted file mode 100644 index b65d48d..0000000 --- a/ServiceDefinition/Loader/AnnotationReader.php +++ /dev/null @@ -1,39 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Bundle\WebServiceBundle\ServiceDefinition\Loader; - -use Doctrine\Common\Annotations\AnnotationReader as BaseAnnotationReader; - -/** - * AnnotationReader. - * - * @author Christian Kerl - */ -class AnnotationReader extends BaseAnnotationReader -{ - public function getMethodAnnotation(\ReflectionMethod $method, $type) - { - $annotation = parent::getMethodAnnotation($method, $type); - - if($annotation !== null && count($annotation) > 1) { - throw new \LogicException(sprintf("There is more than one annotation of type '%s'!", $type)); - } - - return $annotation !== null ? $annotation[0] : null; - } - - public function getMethodAnnotations(\ReflectionMethod $method, $type = null) - { - $annotations = parent::getMethodAnnotations($method); - - return $type !== null && isset($annotations[$type]) ? $annotations[$type] : $annotations; - } -} \ No newline at end of file diff --git a/ServiceDefinition/Loader/XmlFileLoader.php b/ServiceDefinition/Loader/XmlFileLoader.php index feefed5..944980c 100644 --- a/ServiceDefinition/Loader/XmlFileLoader.php +++ b/ServiceDefinition/Loader/XmlFileLoader.php @@ -10,13 +10,13 @@ namespace Bundle\WebServiceBundle\ServiceDefinition\Loader; -use Symfony\Component\Config\Loader\FileLoader; - -use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; +use Bundle\WebServiceBundle\ServiceDefinition\Argument; use Bundle\WebServiceBundle\ServiceDefinition\Header; use Bundle\WebServiceBundle\ServiceDefinition\Method; -use Bundle\WebServiceBundle\ServiceDefinition\Argument; use Bundle\WebServiceBundle\ServiceDefinition\Type; +use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; + +use Symfony\Component\Config\Loader\FileLoader; class XmlFileLoader extends FileLoader { @@ -28,8 +28,7 @@ class XmlFileLoader extends FileLoader public function load($file, $type = null) { $path = $this->locator->locate($file); - - $xml = $this->parseFile($path); + $xml = $this->parseFile($path); $definition = new ServiceDefinition(); $definition->setName((string) $xml['name']); @@ -53,9 +52,7 @@ class XmlFileLoader extends FileLoader */ protected function parseHeader(\SimpleXMLElement $node) { - $header = new Header((string)$node['name'], $this->parseType($node->type)); - - return $header; + return new Header((string)$node['name'], $this->parseType($node->type)); } /** @@ -96,12 +93,10 @@ class XmlFileLoader extends FileLoader protected function parseType(\SimpleXMLElement $node) { $namespaces = $node->getDocNamespaces(true); - $qname = explode(':', $node['xml-type'], 2); - $xmlType = sprintf('{%s}%s', $namespaces[$qname[0]], $qname[1]); + $qname = explode(':', $node['xml-type'], 2); + $xmlType = sprintf('{%s}%s', $namespaces[$qname[0]], $qname[1]); - $type = new Type((string)$node['php-type'], $xmlType, (string)$node['converter']); - - return $type; + return new Type((string)$node['php-type'], $xmlType, (string)$node['converter']); } /** diff --git a/ServiceDefinition/Method.php b/ServiceDefinition/Method.php index 136f9a4..48bf99b 100644 --- a/ServiceDefinition/Method.php +++ b/ServiceDefinition/Method.php @@ -19,12 +19,15 @@ class Method private $arguments; private $return; - public function __construct($name = null, $controller = null, array $arguments = array(), $return = null) + public function __construct($name = null, $controller = null, array $arguments = array(), Type $return = null) { $this->setName($name); $this->setController($controller); $this->setArguments($arguments); - $this->setReturn($return); + + if ($return) { + $this->setReturn($return); + } } public function getName() @@ -52,9 +55,9 @@ class Method return $this->arguments; } - public function setArguments($arguments) + public function setArguments(array $arguments) { - $this->arguments = new Collection('getName'); + $this->arguments = new Collection('getName', 'Bundle\WebServiceBundle\ServiceDefinition\Argument'); $this->arguments->addAll($arguments); } @@ -63,7 +66,7 @@ class Method return $this->return; } - public function setReturn($return) + public function setReturn(Type $return) { $this->return = $return; } diff --git a/ServiceDefinition/ServiceDefinition.php b/ServiceDefinition/ServiceDefinition.php index b587b9e..9be4a9e 100644 --- a/ServiceDefinition/ServiceDefinition.php +++ b/ServiceDefinition/ServiceDefinition.php @@ -38,6 +38,10 @@ class ServiceDefinition { $this->setName($name); $this->setNamespace($namespace); + + $this->methods = new Collection('getName', 'Bundle\WebServiceBundle\ServiceDefinition\Method'); + $this->headers = new Collection('getName', 'Bundle\WebServiceBundle\ServiceDefinition\Header'); + $this->setMethods($methods); $this->setHeaders($headers); } @@ -85,9 +89,8 @@ class ServiceDefinition /** * @param array $methods */ - public function setMethods($methods) + public function setMethods(array $methods) { - $this->methods = new Collection('getName'); $this->methods->addAll($methods); } @@ -102,9 +105,8 @@ class ServiceDefinition /** * @param array $headers */ - public function setHeaders($headers) + public function setHeaders(array $headers) { - $this->headers = new Collection('getName'); $this->headers->addAll($headers); } } \ No newline at end of file diff --git a/Soap/SoapAttachment.php b/Soap/SoapAttachment.php index d9d07db..d5592ce 100644 --- a/Soap/SoapAttachment.php +++ b/Soap/SoapAttachment.php @@ -18,8 +18,8 @@ class SoapAttachment public function __construct($id, $type, $content) { - $this->id = $id; - $this->type = $type; + $this->id = $id; + $this->type = $type; $this->content = $content; } diff --git a/Soap/SoapHeader.php b/Soap/SoapHeader.php index 9c926ec..a66439a 100644 --- a/Soap/SoapHeader.php +++ b/Soap/SoapHeader.php @@ -19,8 +19,8 @@ class SoapHeader public function __construct($namespace, $name, $data) { $this->namespace = $namespace; - $this->name = $name; - $this->data = $data; + $this->name = $name; + $this->data = $data; } public function getNamespace() diff --git a/Soap/SoapRequest.php b/Soap/SoapRequest.php index 5cfbf6f..dc31d9a 100644 --- a/Soap/SoapRequest.php +++ b/Soap/SoapRequest.php @@ -53,9 +53,9 @@ class SoapRequest extends Request { parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content); - $this->soapMessage = null; - $this->soapHeaders = new Collection('getName'); - $this->soapAttachments = new Collection('getId'); + $this->soapMessage = null; + $this->soapHeaders = new Collection('getName', 'Bundle\WebServiceBundle\Soap\SoapHeader'); + $this->soapAttachments = new Collection('getId', 'Bundle\WebServiceBundle\Soap\SoapAttachment'); $this->setRequestFormat('soap'); } @@ -67,7 +67,7 @@ class SoapRequest extends Request */ public function getSoapMessage() { - if($this->soapMessage === null) { + if(null === $this->soapMessage) { $this->soapMessage = $this->initializeSoapMessage(); } diff --git a/Soap/SoapResponse.php b/Soap/SoapResponse.php index 46042cc..1f666ac 100644 --- a/Soap/SoapResponse.php +++ b/Soap/SoapResponse.php @@ -35,7 +35,7 @@ class SoapResponse extends Response { parent::__construct(); - $this->soapHeaders = new Collection('getName'); + $this->soapHeaders = new Collection('getName', 'Bundle\WebServiceBundle\Soap\SoapHeader'); $this->setReturnValue($returnValue); } diff --git a/Soap/SoapServerFactory.php b/Soap/SoapServerFactory.php index 6402649..d81ec7f 100644 --- a/Soap/SoapServerFactory.php +++ b/Soap/SoapServerFactory.php @@ -10,22 +10,14 @@ namespace Bundle\WebServiceBundle\Soap; -/** - * - * @author Christian Kerl - */ -use Bundle\WebServiceBundle\ServiceDefinition\Type; - -use Bundle\WebServiceBundle\ServiceDefinition\Dumper\FileDumper; - use Bundle\WebServiceBundle\Converter\ConverterRepository; - -use Bundle\WebServiceBundle\SoapKernel; - +use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; +use Bundle\WebServiceBundle\ServiceDefinition\Type; use Bundle\WebServiceBundle\Util\QName; -use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition; - +/** + * @author Christian Kerl + */ class SoapServerFactory { private $definition; @@ -35,17 +27,17 @@ class SoapServerFactory public function __construct(ServiceDefinition $definition, $wsdlFile, ConverterRepository $converters) { $this->definition = $definition; - $this->wsdlFile = $wsdlFile; + $this->wsdlFile = $wsdlFile; $this->converters = $converters; } - public function create(&$request, &$response) + public function create($request, $response) { $server = new \SoapServer( $this->wsdlFile, array( 'classmap' => $this->createSoapServerClassmap(), - 'typemap' => $this->createSoapServerTypemap($request, $response), + 'typemap' => $this->createSoapServerTypemap($request, $response), 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, ) ); @@ -53,20 +45,20 @@ class SoapServerFactory return $server; } - private function createSoapServerTypemap(&$request, &$response) + private function createSoapServerTypemap($request, $response) { $result = array(); foreach($this->converters->getTypeConverters() as $typeConverter) { $result[] = array( 'type_name' => $typeConverter->getTypeName(), - 'type_ns' => $typeConverter->getTypeNamespace(), - 'from_xml' => function($input) use (&$request, $typeConverter) { + 'type_ns' => $typeConverter->getTypeNamespace(), + 'from_xml' => function($input) use ($request, $typeConverter) { return $typeConverter->convertXmlToPhp($request, $input); }, - 'to_xml' => function($input) use (&$response, $typeConverter) { + 'to_xml' => function($input) use ($response, $typeConverter) { return $typeConverter->convertPhpToXml($response, $input); - } + }, ); } @@ -93,7 +85,7 @@ class SoapServerFactory private function addSoapServerClassmapEntry(&$classmap, Type $type) { // TODO: fix this hack - if($type->getXmlType() === null) return; + if(null === $type->getXmlType()) return; $xmlType = QName::fromPackedQName($type->getXmlType())->getName(); $phpType = $type->getPhpType(); diff --git a/Tests/Soap/SoapRequestTest.php b/Tests/Soap/SoapRequestTest.php index 1185ee6..81df88b 100644 --- a/Tests/Soap/SoapRequestTest.php +++ b/Tests/Soap/SoapRequestTest.php @@ -40,6 +40,6 @@ class SoapRequestTest extends \PHPUnit_Framework_TestCase private function loadRequestContentFixture($name) { - return file_get_contents(__DIR__ . '/fixtures/' . $name); + return file_get_contents(__DIR__.'/../Fixtures/Soap/'.$name); } } diff --git a/Tests/fixtures/api-servicedefinition.xml b/Tests/fixtures/Soap/api-servicedefinition.xml similarity index 100% rename from Tests/fixtures/api-servicedefinition.xml rename to Tests/fixtures/Soap/api-servicedefinition.xml diff --git a/Tests/fixtures/api.wsdl b/Tests/fixtures/Soap/api.wsdl similarity index 100% rename from Tests/fixtures/api.wsdl rename to Tests/fixtures/Soap/api.wsdl diff --git a/Tests/fixtures/mtom/simple.txt b/Tests/fixtures/Soap/mtom/simple.txt similarity index 100% rename from Tests/fixtures/mtom/simple.txt rename to Tests/fixtures/Soap/mtom/simple.txt diff --git a/Util/Assert.php b/Util/Assert.php index 95563ab..a80985a 100644 --- a/Util/Assert.php +++ b/Util/Assert.php @@ -16,8 +16,8 @@ namespace Bundle\WebServiceBundle\Util; */ class Assert { - const ARGUMENT_INVALID = "Argument '%s' is invalid!"; - const ARGUMENT_NULL = "Argument '%s' can't be null!"; + const ARGUMENT_INVALID = 'Argument "%s" is invalid.'; + const ARGUMENT_NULL = 'Argument "%s" can not be null.'; public static function thatArgument($name, $condition, $message = self::ARGUMENT_INVALID) { @@ -28,6 +28,6 @@ class Assert public static function thatArgumentNotNull($name, $value) { - self::thatArgument($name, $value != null, self::ARGUMENT_NULL); + self::thatArgument($name, null !== $value, self::ARGUMENT_NULL); } } diff --git a/Util/Collection.php b/Util/Collection.php index 8828900..97bbfee 100644 --- a/Util/Collection.php +++ b/Util/Collection.php @@ -13,16 +13,23 @@ namespace Bundle\WebServiceBundle\Util; class Collection implements \IteratorAggregate, \Countable { private $elements = array(); - private $keyPropertyGetter; + private $getter; + private $class; - public function __construct($keyPropertyGetter) + public function __construct($getter, $class = null) { - $this->keyPropertyGetter = $keyPropertyGetter; + $this->getter = $getter; + $this->class = $class; } public function add($element) { - $this->elements[call_user_func(array($element, $this->keyPropertyGetter))] = $element; + if ($this->class && !$element instanceof $this->class) { + throw new \InvalidArgument(sprintf('Cannot add class "%s" because it is not an instance of "%s"', get_class($element), $class)); + } + + $getter = $this->getter; + $this->elements[$element->$getter()] = $element; } public function addAll($elements) @@ -52,7 +59,7 @@ class Collection implements \IteratorAggregate, \Countable return count($this->elements); } - public function getIterator () + public function getIterator() { return new \ArrayIterator($this->elements); } diff --git a/Util/QName.php b/Util/QName.php index d2bf3f2..924138e 100644 --- a/Util/QName.php +++ b/Util/QName.php @@ -11,11 +11,13 @@ namespace Bundle\WebServiceBundle\Util; /** - * * @author Christian Kerl */ class QName { + private $namespace; + private $name; + public static function fromPackedQName($qname) { Assert::thatArgument('qname', preg_match('/^\{(.+)\}(.+)$/', $qname, $matches)); @@ -23,9 +25,6 @@ class QName return new self($matches[1], $matches[2]); } - private $namespace; - private $name; - public function __construct($namespace, $name) { $this->namespace = $namespace; diff --git a/Util/String.php b/Util/String.php index 0526453..d88192b 100644 --- a/Util/String.php +++ b/Util/String.php @@ -17,14 +17,14 @@ namespace Bundle\WebServiceBundle\Util; */ class String { - /** - * Checks if a string starts with a given string. - * - * @param string $str A string - * @param string $substr A string to check against - * - * @return bool True if str starts with substr - */ + /** + * Checks if a string starts with a given string. + * + * @param string $str A string + * @param string $substr A string to check against + * + * @return bool True if str starts with substr + */ public static function startsWith($str, $substr) { if(is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) { @@ -33,17 +33,16 @@ class String } /** - * Checks if a string ends with a given string. - * - * @param string $str A string - * @param string $substr A string to check against - * - * @return bool True if str ends with substr - */ + * Checks if a string ends with a given string. + * + * @param string $str A string + * @param string $substr A string to check against + * + * @return bool True if str ends with substr + */ public static function endsWith($str, $substr) { - if(is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) - { + if(is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) { return $substr == substr($str, strlen($str) - strlen($substr)); } } diff --git a/WebServiceBundle.php b/WebServiceBundle.php index 2ea3bb6..31c1a88 100644 --- a/WebServiceBundle.php +++ b/WebServiceBundle.php @@ -10,8 +10,9 @@ namespace Bundle\WebServiceBundle; -use Symfony\Component\DependencyInjection\ContainerBuilder; +use Bundle\WebServiceBundle\DependencyInjection\Compiler\WebServiceResolverPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; /** @@ -21,4 +22,10 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; */ class WebServiceBundle extends Bundle { + public function build(ContainerBuilder $container) + { + parent::build($container); + + $container->addCompilerPass(new WebServiceResolverPass()); + } } \ No newline at end of file diff --git a/WebServiceContext.php b/WebServiceContext.php index 8bdd949..f421595 100644 --- a/WebServiceContext.php +++ b/WebServiceContext.php @@ -10,16 +10,15 @@ namespace Bundle\WebServiceBundle; +use Bundle\WebServiceBundle\Converter\ConverterRepository; +use Bundle\WebServiceBundle\ServiceBinding\MessageBinderInterface; +use Bundle\WebServiceBundle\ServiceBinding\ServiceBinder; +use Bundle\WebServiceBundle\ServiceDefinition\Dumper\DumperInterface; +use Bundle\WebServiceBundle\Soap\SoapServerFactory; use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\Loader\LoaderInterface; -use Bundle\WebServiceBundle\Converter\ConverterRepository; -use Bundle\WebServiceBundle\ServiceBinding\ServiceBinder; -use Bundle\WebServiceBundle\ServiceBinding\MessageBinderInterface; -use Bundle\WebServiceBundle\ServiceDefinition\Dumper\DumperInterface; -use Bundle\WebServiceBundle\Soap\SoapServerFactory; - /** * WebServiceContext. * @@ -31,7 +30,6 @@ class WebServiceContext private $requestMessageBinder; private $responseMessageBinder; - private $serviceDefinitionLoader; private $wsdlFileDumper; private $options; @@ -40,13 +38,13 @@ class WebServiceContext private $serviceBinder; private $serverFactory; - public function __construct(LoaderInterface $loader, DumperInterface $dumper, ConverterRepository $converterRepository, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder, array $options) + public function __construct(LoaderInterface $loader, DumperInterface $dumper, ConverterRepository $converterRepository, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder, array $options = array()) { - $this->serviceDefinitionLoader = $loader; + $this->loader = $loader; $this->wsdlFileDumper = $dumper; - $this->converterRepository = $converterRepository; - $this->requestMessageBinder = $requestMessageBinder; + $this->converterRepository = $converterRepository; + $this->requestMessageBinder = $requestMessageBinder; $this->responseMessageBinder = $responseMessageBinder; $this->options = $options; @@ -54,12 +52,12 @@ class WebServiceContext public function getServiceDefinition() { - if($this->serviceDefinition === null) { - if(!$this->serviceDefinitionLoader->supports($this->options['resource'], $this->options['resource_type'])) { - throw new \LogicException(); + if (null === $this->serviceDefinition) { + 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'])); } - $this->serviceDefinition = $this->serviceDefinitionLoader->load($this->options['resource'], $this->options['resource_type']); + $this->serviceDefinition = $this->loader->load($this->options['resource'], $this->options['resource_type']); $this->serviceDefinition->setName($this->options['name']); $this->serviceDefinition->setNamespace($this->options['namespace']); } @@ -69,8 +67,8 @@ class WebServiceContext public function getWsdlFile($endpoint = null) { - $id = $endpoint !== null ? '.' . md5($endpoint) : ''; - $file = sprintf('%s/%s.wsdl', $this->options['cache_dir'], $this->options['name'] . $id); + $id = null !== $endpoint ? '.'. md5($endpoint) : ''; + $file = sprintf('%s/%s.wsdl', $this->options['cache_dir'], $this->options['name'].$id); $cache = new ConfigCache($file, true); if(!$cache->isFresh()) { @@ -87,7 +85,7 @@ class WebServiceContext public function getServiceBinder() { - if($this->serviceBinder === null) { + if (null === $this->serviceBinder) { $this->serviceBinder = new ServiceBinder($this->getServiceDefinition(), $this->requestMessageBinder, $this->responseMessageBinder); } @@ -96,7 +94,7 @@ class WebServiceContext public function getServerFactory() { - if($this->serverFactory === null) { + if (null === $this->serverFactory) { $this->serverFactory = new SoapServerFactory($this->getServiceDefinition(), $this->getWsdlFile(), $this->converterRepository); } diff --git a/vendors.php b/vendors.php index 47b53e5..1841c89 100755 --- a/vendors.php +++ b/vendors.php @@ -1,20 +1,19 @@ #!/usr/bin/env php + * (c) Christian Kerl * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. */ /* -CAUTION: This file installs the dependencies needed to run the I18nRoutingBundle test suite. +CAUTION: This file installs the dependencies needed to run the WebServiceBundle test suite. -https://github.com/BeSimple/I18nRoutingBundle +https://github.com/BeSimple/BeSimpleSoapBundle */