Rewrited Definition of WebService and WSDL dumper

This commit is contained in:
Francis Besset
2013-10-15 11:46:12 +02:00
parent 391a3f10b8
commit c830097430
42 changed files with 1430 additions and 1093 deletions

View File

@ -1,7 +1,7 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
@ -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 <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
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.
*

View File

@ -1,7 +1,7 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
@ -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;
}
}

View File

@ -1,7 +1,7 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>

View File

@ -1,145 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapBundle\ServiceDefinition\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;
}
}