abstracted docblock comment extraction, implemented in JmsMetadataParser to get parameter descriptions

This commit is contained in:
Evan Villemez 2012-08-31 14:57:42 -04:00
parent 65c634d32b
commit 8c3466f6ed
7 changed files with 86 additions and 49 deletions

View File

@ -18,6 +18,7 @@ use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
class ApiDocExtractor class ApiDocExtractor
{ {
@ -40,16 +41,22 @@ class ApiDocExtractor
*/ */
private $reader; private $reader;
/**
* @var \Nelmio\ApiDocBundle\Util\DocCommentExtractor
*/
private $commentExtractor;
/** /**
* @var array \Nelmio\ApiDocBundle\Parser\ParserInterface * @var array \Nelmio\ApiDocBundle\Parser\ParserInterface
*/ */
private $parsers = array(); private $parsers = array();
public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader) public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor)
{ {
$this->container = $container; $this->container = $container;
$this->router = $router; $this->router = $router;
$this->reader = $reader; $this->reader = $reader;
$this->commentExtractor = $commentExtractor;
} }
/** /**
@ -208,7 +215,7 @@ class ApiDocExtractor
// description // description
if (null === $annotation->getDescription()) { if (null === $annotation->getDescription()) {
$comments = explode("\n", $this->getDocCommentText($method)); $comments = explode("\n", $this->commentExtractor->getDocCommentText($method));
// just set the first line // just set the first line
$comment = trim($comments[0]); $comment = trim($comments[0]);
$comment = preg_replace("#\n+#", ' ', $comment); $comment = preg_replace("#\n+#", ' ', $comment);
@ -221,7 +228,7 @@ class ApiDocExtractor
} }
// doc // doc
$annotation->setDocumentation($this->getDocCommentText($method)); $annotation->setDocumentation($this->commentExtractor->getDocCommentText($method));
// input (populates 'parameters' for the formatters) // input (populates 'parameters' for the formatters)
if (null !== $input = $annotation->getInput()) { if (null !== $input = $annotation->getInput()) {
@ -271,7 +278,7 @@ class ApiDocExtractor
} }
$paramDocs = array(); $paramDocs = array();
foreach (explode("\n", $this->getDocComment($method)) as $line) { foreach (explode("\n", $this->commentExtractor->getDocComment($method)) as $line) {
if (preg_match('{^@param (.+)}', trim($line), $matches)) { if (preg_match('{^@param (.+)}', trim($line), $matches)) {
$paramDocs[] = $matches[1]; $paramDocs[] = $matches[1];
} }
@ -308,45 +315,6 @@ class ApiDocExtractor
return $annotation; return $annotation;
} }
/**
* @param \Reflector $reflected
* @return string
*/
protected function getDocComment(\Reflector $reflected)
{
$comment = $reflected->getDocComment();
// let's clean the doc block
$comment = str_replace('/**', '', $comment);
$comment = str_replace('*', '', $comment);
$comment = str_replace('*/', '', $comment);
$comment = str_replace("\r", '', trim($comment));
$comment = preg_replace("#^\n[ \t]+[*]?#i", "\n", trim($comment));
$comment = preg_replace("#[\t ]+#i", ' ', trim($comment));
$comment = str_replace("\"", "\\\"", $comment);
return $comment;
}
/**
* @param \Reflector $reflected
* @return string
*/
protected function getDocCommentText(\Reflector $reflected)
{
$comment = $reflected->getDocComment();
// Remove PHPDoc
$comment = preg_replace('/^\s+\* @[\w0-9]+.*/msi', '', $comment);
// let's clean the doc block
$comment = str_replace('/**', '', $comment);
$comment = str_replace('*/', '', $comment);
$comment = preg_replace('/^\s*\* ?/m', '', $comment);
return trim($comment);
}
/** /**
* Parses annotations for a given method, and adds new information to the given ApiDoc * Parses annotations for a given method, and adds new information to the given ApiDoc
* annotation. Useful to extract information from the FOSRestBundle annotations. * annotation. Useful to extract information from the FOSRestBundle annotations.

View File

@ -12,6 +12,7 @@
namespace Nelmio\ApiDocBundle\Parser; namespace Nelmio\ApiDocBundle\Parser;
use Metadata\MetadataFactoryInterface; use Metadata\MetadataFactoryInterface;
use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
/** /**
* Uses the JMS metadata factory to extract input/output model information * Uses the JMS metadata factory to extract input/output model information
@ -19,12 +20,23 @@ use Metadata\MetadataFactoryInterface;
class JmsMetadataParser implements ParserInterface class JmsMetadataParser implements ParserInterface
{ {
/**
* @var \Metadata\MetadataFactoryInterface
*/
private $factory;
/**
* @var \Nelmio\ApiDocBundle\Util\DocCommentExtractor
*/
private $commentExtractor;
/** /**
* Constructor, requires JMS Metadata factory * Constructor, requires JMS Metadata factory
*/ */
public function __construct(MetadataFactoryInterface $factory) public function __construct(MetadataFactoryInterface $factory, DocCommentExtractor $commentExtractor)
{ {
$this->factory = $factory; $this->factory = $factory;
$this->commentExtractor = $commentExtractor;
} }
/** /**
@ -148,9 +160,9 @@ class JmsMetadataParser implements ParserInterface
protected function getDescription($className, $propertyName) protected function getDescription($className, $propertyName)
{ {
$description = "No description."; $ref = new \ReflectionClass($className);
$extracted = $this->commentExtractor->getDocCommentText($ref->getProperty($propertyName));
//TODO: abstract docblock parsing utility and implement here $description = !empty($extracted) ? $extracted : "No description.";
return $description; return $description;
} }

View File

@ -10,6 +10,7 @@
<services> <services>
<service id="nelmio_api_doc.parser.jms_metadata_parser" class="%nelmio_api_doc.parser.jms_metadata_parser.class%"> <service id="nelmio_api_doc.parser.jms_metadata_parser" class="%nelmio_api_doc.parser.jms_metadata_parser.class%">
<argument type="service" id="jms_serializer.metadata_factory" /> <argument type="service" id="jms_serializer.metadata_factory" />
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
<tag name="nelmio_api_doc.extractor.parser" /> <tag name="nelmio_api_doc.extractor.parser" />
</service> </service>
</services> </services>

View File

@ -7,13 +7,17 @@
<parameter key="nelmio_api_doc.extractor.api_doc_extractor.class">Nelmio\ApiDocBundle\Extractor\ApiDocExtractor</parameter> <parameter key="nelmio_api_doc.extractor.api_doc_extractor.class">Nelmio\ApiDocBundle\Extractor\ApiDocExtractor</parameter>
<parameter key="nelmio_api_doc.form.extension.description_form_type_extension.class">Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension</parameter> <parameter key="nelmio_api_doc.form.extension.description_form_type_extension.class">Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension</parameter>
<parameter key="nelmio_api_doc.twig.extension.extra_markdown.class">Nelmio\ApiDocBundle\Twig\Extension\MarkdownExtension</parameter> <parameter key="nelmio_api_doc.twig.extension.extra_markdown.class">Nelmio\ApiDocBundle\Twig\Extension\MarkdownExtension</parameter>
<parameter key="nelmio_api_doc.doc_comment_extractor.class">Nelmio\ApiDocBundle\Util\DocCommentExtractor</parameter>
</parameters> </parameters>
<services> <services>
<service id='nelmio_api_doc.doc_comment_extractor' class='%nelmio_api_doc.doc_comment_extractor.class%' />
<service id="nelmio_api_doc.extractor.api_doc_extractor" class="%nelmio_api_doc.extractor.api_doc_extractor.class%"> <service id="nelmio_api_doc.extractor.api_doc_extractor" class="%nelmio_api_doc.extractor.api_doc_extractor.class%">
<argument type="service" id="service_container"/> <argument type="service" id="service_container"/>
<argument type="service" id="router" /> <argument type="service" id="router" />
<argument type="service" id="annotation_reader" /> <argument type="service" id="annotation_reader" />
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
</service> </service>
<service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%"> <service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%">

View File

@ -20,6 +20,8 @@ class JmsNested
/** /**
* Epic description. * Epic description.
* *
* With multiple lines.
*
* @JMS\Type("array<integer>") * @JMS\Type("array<integer>")
*/ */
public $baz; public $baz;

View File

@ -232,7 +232,9 @@ class SimpleFormatterTest extends WebTestCase
'baz' => array( 'baz' => array(
'dataType' => 'array of integers', 'dataType' => 'array of integers',
'required' => false, 'required' => false,
'description' => 'No description.', 'description' => 'Epic description.
With multiple lines.',
'readonly' => false, 'readonly' => false,
) )
) )
@ -258,7 +260,9 @@ class SimpleFormatterTest extends WebTestCase
'baz' => array( 'baz' => array(
'dataType' => 'array of integers', 'dataType' => 'array of integers',
'required' => false, 'required' => false,
'description' => 'No description.', 'description' => 'Epic description.
With multiple lines.',
'readonly' => false, 'readonly' => false,
) )
) )

View File

@ -0,0 +1,46 @@
<?php
namespace Nelmio\ApiDocBundle\Util;
class DocCommentExtractor
{
/**
* @param \Reflector $reflected
* @return string
*/
public function getDocComment(\Reflector $reflected)
{
$comment = $reflected->getDocComment();
// let's clean the doc block
$comment = str_replace('/**', '', $comment);
$comment = str_replace('*', '', $comment);
$comment = str_replace('*/', '', $comment);
$comment = str_replace("\r", '', trim($comment));
$comment = preg_replace("#^\n[ \t]+[*]?#i", "\n", trim($comment));
$comment = preg_replace("#[\t ]+#i", ' ', trim($comment));
$comment = str_replace("\"", "\\\"", $comment);
return $comment;
}
/**
* @param \Reflector $reflected
* @return string
*/
public function getDocCommentText(\Reflector $reflected)
{
$comment = $reflected->getDocComment();
// Remove PHPDoc
$comment = preg_replace('/^\s+\* @[\w0-9]+.*/msi', '', $comment);
// let's clean the doc block
$comment = str_replace('/**', '', $comment);
$comment = str_replace('*/', '', $comment);
$comment = preg_replace('/^\s*\* ?/m', '', $comment);
return trim($comment);
}
}