diff --git a/README.markdown b/README.markdown
index ef95312..8cd5bbc 100644
--- a/README.markdown
+++ b/README.markdown
@@ -37,8 +37,9 @@ QuickStart
// src/Acme/DemoBundle/Controller/DemoController.php
/**
- * @ws:Method('hello')
- * @ws:Param('name', type = 'string')
+ * @ws:Method("Hello")
+ * @ws:Param("name", type = "string")
+ * @ws:Result(type = "string")
*/
public function helloAction($name)
{
diff --git a/Resources/config/annotations.xml b/Resources/config/annotations.xml
index 1bb69de..9b10ecf 100644
--- a/Resources/config/annotations.xml
+++ b/Resources/config/annotations.xml
@@ -5,8 +5,8 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
- Doctrine\Common\Annotations\AnnotationReader
- Doctrine\Common\Annotations\Parser
+ Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationReader
+ Bundle\WebServiceBundle\ServiceDefinition\Loader\AnnotationParser
diff --git a/ServiceDefinition/Annotation/Method.php b/ServiceDefinition/Annotation/Method.php
new file mode 100644
index 0000000..f91abd0
--- /dev/null
+++ b/ServiceDefinition/Annotation/Method.php
@@ -0,0 +1,33 @@
+
+ *
+ * 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;
+
+class Method
+{
+ private $name;
+ private $service;
+
+ public function __construct($values)
+ {
+ $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;
+ }
+
+ public function getService()
+ {
+ return $this->service;
+ }
+}
\ No newline at end of file
diff --git a/ServiceDefinition/Annotation/Param.php b/ServiceDefinition/Annotation/Param.php
new file mode 100644
index 0000000..6bc3d55
--- /dev/null
+++ b/ServiceDefinition/Annotation/Param.php
@@ -0,0 +1,28 @@
+
+ *
+ * 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;
+
+class Param extends TypedElement
+{
+ private $name;
+
+ public function __construct($values)
+ {
+ parent::__construct($values);
+
+ $this->name = $values['value'];
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+}
\ No newline at end of file
diff --git a/ServiceDefinition/Annotation/Result.php b/ServiceDefinition/Annotation/Result.php
new file mode 100644
index 0000000..429c50b
--- /dev/null
+++ b/ServiceDefinition/Annotation/Result.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;
+
+class Result extends TypedElement
+{
+ public function __construct($values)
+ {
+ parent::__construct($values);
+ }
+}
\ No newline at end of file
diff --git a/ServiceDefinition/Annotation/TypedElement.php b/ServiceDefinition/Annotation/TypedElement.php
new file mode 100644
index 0000000..eb75b66
--- /dev/null
+++ b/ServiceDefinition/Annotation/TypedElement.php
@@ -0,0 +1,40 @@
+
+ *
+ * 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/Loader/AnnotationClassLoader.php b/ServiceDefinition/Loader/AnnotationClassLoader.php
index abac95e..ee82665 100644
--- a/ServiceDefinition/Loader/AnnotationClassLoader.php
+++ b/ServiceDefinition/Loader/AnnotationClassLoader.php
@@ -1,59 +1,41 @@
+ * (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.
*/
+
namespace Bundle\WebServiceBundle\ServiceDefinition\Loader;
-use Doctrine\Common\Annotations\AnnotationReader;
-use Symfony\Component\Config\Resource\FileResource;
+
+
+use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition;
+use Bundle\WebServiceBundle\ServiceDefinition\Method;
+use Bundle\WebServiceBundle\ServiceDefinition\Argument;
+use Bundle\WebServiceBundle\ServiceDefinition\Type;
+
+use Bundle\WebServiceBundle\ServiceDefinition\Annotation\Method as MethodAnnotation;
+
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Config\Loader\LoaderResolver;
/**
- * AnnotationClassLoader loads routing information from a PHP class and its methods.
+ * AnnotationClassLoader loads ServiceDefinition from a PHP class and its methods.
*
- * You need to define an implementation for the getRouteDefaults() method. Most of the
- * time, this method should define some PHP callable to be called for the route
- * (a controller in MVC speak).
+ * Based on \Symfony\Component\Routing\Loader\AnnotationClassLoader
*
- * The @Route annotation can be set on the class (for global parameters),
- * and on each method.
- *
- * The @Route annotation main value is the route pattern. The annotation also
- * recognizes three parameters: requirements, options, and name. The name parameter
- * is mandatory. Here is an example of how you should be able to use it:
- *
- * /**
- * * @Route("/Blog")
- * * /
- * class Blog
- * {
- * /**
- * * @Route("/", name="blog_index")
- * * /
- * public function index()
- * {
- * }
- *
- * /**
- * * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
- * * /
- * public function show()
- * {
- * }
- * }
- *
- * @author Fabien Potencier
+ * @author Christian Kerl
*/
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';
+
protected $reader;
/**
@@ -67,33 +49,72 @@ class AnnotationClassLoader implements LoaderInterface
}
/**
- * Loads from annotations from a class.
+ * Loads a ServiceDefinition from annotations from a class.
*
* @param string $class A class name
* @param string $type The resource type
*
- * @return RouteCollection A RouteCollection instance
+ * @return ServiceDefinition A ServiceDefinition instance
*
* @throws \InvalidArgumentException When route can't be parsed
*/
public function load($class, $type = null)
{
- if (!class_exists($class)) {
+ if (!class_exists($class))
+ {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
$class = new \ReflectionClass($class);
- $collection = new RouteCollection();
- $collection->addResource(new FileResource($class->getFileName()));
-
- foreach ($class->getMethods() as $method) {
+ $definition = new ServiceDefinition();
+
+ foreach ($class->getMethods() as $method)
+ {
+ $wsMethodAnnot = $this->reader->getMethodAnnotation($method, $this->wsMethodAnnotationClass);
+ if($wsMethodAnnot !== null)
+ {
+ $wsParamAnnots = $this->reader->getMethodAnnotations($method, $this->wsParamAnnotationClass);
+ $wsResultAnnot = $this->reader->getMethodAnnotation($method, $this->wsResultAnnotationClass);
+
+ $serviceMethod = new Method();
+ $serviceMethod->setName($wsMethodAnnot->getName($method->getName()));
+ $serviceMethod->setController($this->getController($method, $wsMethodAnnot));
+
+ foreach($wsParamAnnots as $wsParamAnnot)
+ {
+ $serviceArgument = new Argument();
+ $serviceArgument->setName($wsParamAnnot->getName());
+ $serviceArgument->setType(new Type($wsParamAnnot->getPhpType(), $wsParamAnnot->getXmlType()));
+
+ $serviceMethod->getArguments()->add($serviceArgument);
+ }
+
+ if($wsResultAnnot !== null)
+ {
+ $serviceMethod->setReturn(new Type($wsResultAnnot->getPhpType(), $wsResultAnnot->getXmlType()));
+ }
+
+ $definition->getMethods()->add($serviceMethod);
+ }
}
- return $collection;
+ return $definition;
}
+ private function getController(\ReflectionMethod $method, MethodAnnotation $annotation)
+ {
+ if($annotation->getService() !== null)
+ {
+ return $annotation->getService() . ':' . $method->name;
+ }
+ else
+ {
+ return $method->class . '::' . $method->name;
+ }
+ }
+
/**
* Returns true if this class supports the given resource.
*
diff --git a/ServiceDefinition/Loader/AnnotationFileLoader.php b/ServiceDefinition/Loader/AnnotationFileLoader.php
index d0cbf73..6c13d7d 100644
--- a/ServiceDefinition/Loader/AnnotationFileLoader.php
+++ b/ServiceDefinition/Loader/AnnotationFileLoader.php
@@ -1,14 +1,14 @@
+ * (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.
*/
+
namespace Bundle\WebServiceBundle\ServiceDefinition\Loader;
use Bundle\WebServiceBundle\ServiceDefinition\ServiceDefinition;
@@ -21,7 +21,9 @@ use Symfony\Component\Config\FileLocator;
* AnnotationFileLoader loads ServiceDefinition from annotations set
* on a PHP class and its methods.
*
- * @author Fabien Potencier
+ * Based on \Symfony\Component\Routing\Loader\AnnotationFileLoader
+ *
+ * @author Christian Kerl
*/
class AnnotationFileLoader extends FileLoader
{
@@ -50,20 +52,21 @@ class AnnotationFileLoader extends FileLoader
* @param string $file A PHP file path
* @param string $type The resource type
*
- * @return RouteCollection A RouteCollection instance
+ * @return ServiceDefinition A ServiceDefinition instance
*
- * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
+ * @throws \InvalidArgumentException When the file does not exist
*/
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
- $definiton = new ServiceDefinition();
+ $definition = new ServiceDefinition();
+
if ($class = $this->findClass($path)) {
-
+ $definition = $this->loader->load($class, $type);
}
-
- return $definiton;
+
+ return $definition;
}
/**
diff --git a/ServiceDefinition/Loader/AnnotationParser.php b/ServiceDefinition/Loader/AnnotationParser.php
new file mode 100644
index 0000000..7b6f523
--- /dev/null
+++ b/ServiceDefinition/Loader/AnnotationParser.php
@@ -0,0 +1,52 @@
+
+ *
+ * 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
new file mode 100644
index 0000000..81e3f03
--- /dev/null
+++ b/ServiceDefinition/Loader/AnnotationReader.php
@@ -0,0 +1,40 @@
+
+ *
+ * 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