From 06271f824adbd6eaa429f716a4f8c5c8adfcb5d0 Mon Sep 17 00:00:00 2001 From: fieg Date: Mon, 25 Mar 2013 12:28:00 +0100 Subject: [PATCH 1/2] added support for JMS Serializer GroupsExclusionStrategy --- Extractor/ApiDocExtractor.php | 33 ++- Parser/FormTypeParser.php | 10 +- Parser/JmsMetadataParser.php | 45 +++- Parser/ParserInterface.php | 7 +- README.md | 23 +- Tests/Fixtures/app/AppKernel.php | 18 +- Tests/Parser/JmsMetadataParserTest.php | 332 +++++++++++++++++++++++-- composer.json | 1 + 8 files changed, 405 insertions(+), 64 deletions(-) diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index b9077e2..481e071 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -266,9 +266,11 @@ class ApiDocExtractor if (null !== $input = $annotation->getInput()) { $parameters = array(); + $normalizedInput = $this->normalizeClassParameter($input); + foreach ($this->parsers as $parser) { - if ($parser->supports($input)) { - $parameters = $parser->parse($input); + if ($parser->supports($normalizedInput)) { + $parameters = $parser->parse($normalizedInput); break; } } @@ -287,9 +289,11 @@ class ApiDocExtractor if (null !== $output = $annotation->getOutput()) { $response = array(); + $normalizedOutput = $this->normalizeClassParameter($output); + foreach ($this->parsers as $parser) { - if ($parser->supports($output)) { - $response = $parser->parse($output); + if ($parser->supports($normalizedOutput)) { + $response = $parser->parse($normalizedOutput); break; } } @@ -350,6 +354,27 @@ class ApiDocExtractor return $annotation; } + protected function normalizeClassParameter($input) + { + $defaults = array( + 'class' => '', + 'groups' => array(), + 'version' => null, + ); + + // normalize strings + if (is_string($input)) { + $input = array('class' => $input); + } + + // normalize groups + if (isset($input['groups']) && is_string($input['groups'])) { + $input['groups'] = array_map('trim', explode(',', $input['groups'])); + } + + return array_merge($defaults, $input); + } + /** * Parses annotations for a given method, and adds new information to the given ApiDoc * annotation. Useful to extract information from the FOSRestBundle annotations. diff --git a/Parser/FormTypeParser.php b/Parser/FormTypeParser.php index e0f0a60..f04a2d9 100644 --- a/Parser/FormTypeParser.php +++ b/Parser/FormTypeParser.php @@ -47,10 +47,12 @@ class FormTypeParser implements ParserInterface /** * {@inheritdoc} */ - public function supports($item) + public function supports(array $item) { + $className = $item['class']; + try { - if ($this->createForm($item)) { + if ($this->createForm($className)) { return true; } } catch (FormException $e) { @@ -65,8 +67,10 @@ class FormTypeParser implements ParserInterface /** * {@inheritdoc} */ - public function parse($type) + public function parse(array $item) { + $type = $item['class']; + if ($this->implementsType($type)) { $type = $this->getTypeInstance($type); } diff --git a/Parser/JmsMetadataParser.php b/Parser/JmsMetadataParser.php index 5ac634a..0882d0e 100644 --- a/Parser/JmsMetadataParser.php +++ b/Parser/JmsMetadataParser.php @@ -11,6 +11,10 @@ namespace Nelmio\ApiDocBundle\Parser; +use JMS\Serializer\Exclusion\GroupsExclusionStrategy; +use JMS\Serializer\GraphNavigator; +use JMS\Serializer\NavigatorContext; +use JMS\Serializer\SerializationContext; use Metadata\MetadataFactoryInterface; use Nelmio\ApiDocBundle\Util\DocCommentExtractor; use JMS\Serializer\Metadata\PropertyMetadata; @@ -22,7 +26,6 @@ use JMS\Serializer\Naming\PropertyNamingStrategyInterface; */ class JmsMetadataParser implements ParserInterface { - /** * @var \Metadata\MetadataFactoryInterface */ @@ -54,10 +57,12 @@ class JmsMetadataParser implements ParserInterface /** * {@inheritdoc} */ - public function supports($input) + public function supports(array $input) { + $className = $input['class']; + try { - if ($meta = $this->factory->getMetadataForClass($input)) { + if ($meta = $this->factory->getMetadataForClass($className)) { return true; } } catch (\ReflectionException $e) { @@ -69,9 +74,12 @@ class JmsMetadataParser implements ParserInterface /** * {@inheritdoc} */ - public function parse($input) + public function parse(array $input) { - return $this->doParse($input); + $className = $input['class']; + $groups = $input['groups']; + + return $this->doParse($className, array(), $groups, $version); } /** @@ -79,10 +87,11 @@ class JmsMetadataParser implements ParserInterface * * @param string $className Class to get all metadata for * @param array $visited Classes we've already visited to prevent infinite recursion. + * @param array $groups Groups to be used in the group exclusion strategy * @return array metadata for given class * @throws \InvalidArgumentException */ - protected function doParse($className, $visited = array()) + protected function doParse($className, $visited = array(), array $groups = array()) { $meta = $this->factory->getMetadataForClass($className); @@ -90,6 +99,9 @@ class JmsMetadataParser implements ParserInterface throw new \InvalidArgumentException(sprintf("No metadata found for class %s", $className)); } + $exclusionStrategies = array(); + $exclusionStrategies[] = new GroupsExclusionStrategy($groups); + $params = array(); // iterate over property metadata @@ -99,11 +111,19 @@ class JmsMetadataParser implements ParserInterface $dataType = $this->processDataType($item); + // apply exclusion strategies + foreach ($exclusionStrategies as $strategy) { + if (true === $strategy->shouldSkipProperty($item, SerializationContext::create())) { + continue 2; + } + } + $params[$name] = array( - 'dataType' => $dataType['normalized'], - 'required' => false, //TODO: can't think of a good way to specify this one, JMS doesn't have a setting for this - 'description' => $this->getDescription($className, $item), - 'readonly' => $item->readOnly + 'dataType' => $dataType['normalized'], + 'required' => false, + //TODO: can't think of a good way to specify this one, JMS doesn't have a setting for this + 'description' => $this->getDescription($className, $item), + 'readonly' => $item->readOnly ); // if class already parsed, continue, to avoid infinite recursion @@ -113,8 +133,8 @@ class JmsMetadataParser implements ParserInterface // check for nested classes with JMS metadata if ($dataType['class'] && null !== $this->factory->getMetadataForClass($dataType['class'])) { - $visited[] = $dataType['class']; - $params[$name]['children'] = $this->doParse($dataType['class'], $visited); + $visited[] = $dataType['class']; + $params[$name]['children'] = $this->doParse($dataType['class'], $visited, $groups); } } } @@ -206,5 +226,4 @@ class JmsMetadataParser implements ParserInterface return $extracted; } - } diff --git a/Parser/ParserInterface.php b/Parser/ParserInterface.php index fcdadf2..398b230 100644 --- a/Parser/ParserInterface.php +++ b/Parser/ParserInterface.php @@ -19,10 +19,10 @@ interface ParserInterface /** * Return true/false whether this class supports parsing the given class. * - * @param string $item The string type of input to parse. + * @param array $item containing the following fields: class, groups. Of which groups is optional * @return boolean */ - public function supports($item); + public function supports(array $item); /** * Returns an array of class property metadata where each item is a key (the property name) and @@ -37,6 +37,5 @@ interface ParserInterface * @param string $item The string type of input to parse. * @return array */ - public function parse($item); - + public function parse(array $item); } diff --git a/README.md b/README.md index 897fc2b..4a76bc1 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,28 @@ The following properties are available: * `filters`: an array of filters; * `input`: the input type associated to the method, currently this supports Form Types, and classes with JMS Serializer - metadata, useful for POST|PUT methods, either as FQCN or as form type (if it is registered in the form factory in the container) + metadata, useful for POST|PUT methods, either as FQCN or as form type (if it is registered in the form factory in the container). + When using a class with JMS Serializer metadata, you can + [use specific groups](http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies#creating-different-views-of-your-objects) + by using this syntax: + + ``` + input={ + "class"="Acme\Bundle\Entity\User", + "groups"={"update", "public"} + } + ``` + + In this case the groups 'update' and 'public' are used. + + Also supported are versions: + + ``` + input={ + "class"="Acme\Bundle\Entity\User", + "version"="2.3" + } + ``` * `output`: the output type associated with the response. Specified and parsed the same way as `input`. diff --git a/Tests/Fixtures/app/AppKernel.php b/Tests/Fixtures/app/AppKernel.php index 0ebbbb0..adc9506 100644 --- a/Tests/Fixtures/app/AppKernel.php +++ b/Tests/Fixtures/app/AppKernel.php @@ -12,23 +12,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional; // get the autoload file -$dir = __DIR__; -$lastDir = null; -while ($dir !== $lastDir) { - $lastDir = $dir; - - if (is_file($dir.'/autoload.php')) { - require_once $dir.'/autoload.php'; - break; - } - - if (is_file($dir.'/autoload.php.dist')) { - require_once $dir.'/autoload.php.dist'; - break; - } - - $dir = dirname($dir); -} +require_once __DIR__.'/../../../vendor/autoload.php'; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\HttpKernel\Kernel; diff --git a/Tests/Parser/JmsMetadataParserTest.php b/Tests/Parser/JmsMetadataParserTest.php index dd30b75..8d4acae 100644 --- a/Tests/Parser/JmsMetadataParserTest.php +++ b/Tests/Parser/JmsMetadataParserTest.php @@ -5,6 +5,7 @@ use Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested; use Nelmio\ApiDocBundle\Parser\JmsMetadataParser; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; +use JMS\Serializer\Naming\CamelCaseNamingStrategy; class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase { @@ -61,7 +62,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase ->method('translateName') ->will($this->returnValue('baz')); - $input = new JmsNested(); + $input = 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested'; $metadataFactory->expects($this->once()) ->method('getMetadataForClass') @@ -70,28 +71,315 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase $jmsMetadataParser = new JmsMetadataParser($metadataFactory, $propertyNamingStrategy, $docCommentExtractor); - $output = $jmsMetadataParser->parse($input); - - $this->assertEquals(array( - 'foo' => array( - 'dataType' => 'DateTime', - 'required' => false, - 'description' => '', - 'readonly' => false - ), - 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => '', - 'readonly' => false - ), - 'baz' => array( - 'dataType' => 'array of integers', - 'required' => false, - 'description' => '', - 'readonly' => false + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array(), + 'version' => null, ) - ), $output); + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'DateTime', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'baz' => array( + 'dataType' => 'array of integers', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ) + ), + $output + ); + } + + public function testParserWithGroups() + { + $metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); + $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') + ->disableOriginalConstructor() + ->getMock(); + + $propertyMetadataFoo = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'foo'); + $propertyMetadataFoo->type = array('name' => 'string'); + + $propertyMetadataBar = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'bar'); + $propertyMetadataBar->type = array('name' => 'string'); + $propertyMetadataBar->groups = array('Default', 'Special'); + + $propertyMetadataBaz = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'baz'); + $propertyMetadataBaz->type = array('name' => 'string'); + $propertyMetadataBaz->groups = array('Special'); + + $input = 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested'; + + $metadata = new ClassMetadata($input); + $metadata->addPropertyMetadata($propertyMetadataFoo); + $metadata->addPropertyMetadata($propertyMetadataBar); + $metadata->addPropertyMetadata($propertyMetadataBaz); + + $metadataFactory->expects($this->any()) + ->method('getMetadataForClass') + ->with($input) + ->will($this->returnValue($metadata)); + + $propertyNamingStrategy = new CamelCaseNamingStrategy(); + + $jmsMetadataParser = new JmsMetadataParser($metadataFactory, $propertyNamingStrategy, $docCommentExtractor); + + // No group specified. + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array(), + 'version' => null, + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); + + // Default group. + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array('Default'), + 'version' => null, + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); + + // Special group. + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array('Special'), + 'version' => null, + ) + ); + + $this->assertEquals( + array( + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'baz' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); + + // Default + Special groups. + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array('Default', 'Special'), + 'version' => null, + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'baz' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ) + ), + $output + ); + } + + public function testParserWithVersion() + { + $metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); + $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') + ->disableOriginalConstructor() + ->getMock(); + + $propertyMetadataFoo = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'foo'); + $propertyMetadataFoo->type = array('name' => 'string'); + + $propertyMetadataBar = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'bar'); + $propertyMetadataBar->type = array('name' => 'string'); + $propertyMetadataBar->sinceVersion = '0.2'; + $propertyMetadataBar->untilVersion = '0.3'; + + $input = 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested'; + + $metadata = new ClassMetadata($input); + $metadata->addPropertyMetadata($propertyMetadataFoo); + $metadata->addPropertyMetadata($propertyMetadataBar); + + $metadataFactory->expects($this->any()) + ->method('getMetadataForClass') + ->with($input) + ->will($this->returnValue($metadata)); + + $propertyNamingStrategy = new CamelCaseNamingStrategy(); + + $jmsMetadataParser = new JmsMetadataParser($metadataFactory, $propertyNamingStrategy, $docCommentExtractor); + + // No version specified. + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array(), + 'version' => null, + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); + + // 0.1 + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array(), + 'version' => '0.1', + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); + + // 0.2 & 0.3 + foreach (array('0.2', '0.3') as $version) { + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array(), + 'version' => $version, + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + 'bar' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); + } + + // 0.4 + $output = $jmsMetadataParser->parse( + array( + 'class' => $input, + 'groups' => array(), + 'version' => '0.4', + ) + ); + + $this->assertEquals( + array( + 'foo' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => 'No description.', + 'readonly' => false + ), + ), + $output + ); } public function dataTestParserWithNestedType() diff --git a/composer.json b/composer.json index 7d03918..76b1397 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "dflydev/markdown": "1.0.*" }, "conflict": { + "jms/serializer": "<0.12", "jms/serializer-bundle": "<0.11" }, "require-dev": { From 13efea897526e475e75c6650f100abcd75d1181a Mon Sep 17 00:00:00 2001 From: Pierre-Yves LEBECQ Date: Wed, 24 Apr 2013 22:28:46 +0200 Subject: [PATCH 2/2] Added support for the jms version annotations in formatters --- Extractor/ApiDocExtractor.php | 1 - Formatter/AbstractFormatter.php | 2 + Formatter/MarkdownFormatter.php | 14 + Parser/JmsMetadataParser.php | 16 +- README.md | 46 ++-- Resources/views/Components/version.html.twig | 8 + Resources/views/method.html.twig | 2 + Tests/Extractor/ApiDocExtractorTest.php | 6 +- Tests/Fixtures/Controller/TestController.php | 11 +- Tests/Fixtures/Model/JmsNested.php | 18 ++ Tests/Fixtures/app/config/routing.yml | 4 + Tests/Formatter/MarkdownFormatterTest.php | 107 ++++++++ Tests/Formatter/SimpleFormatterTest.php | 272 ++++++++++++++++++- Tests/Parser/JmsMetadataParserTest.php | 233 +++++++--------- 14 files changed, 565 insertions(+), 175 deletions(-) create mode 100644 Resources/views/Components/version.html.twig diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index 481e071..720a593 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -359,7 +359,6 @@ class ApiDocExtractor $defaults = array( 'class' => '', 'groups' => array(), - 'version' => null, ); // normalize strings diff --git a/Formatter/AbstractFormatter.php b/Formatter/AbstractFormatter.php index 7935c0c..b5d2fc7 100644 --- a/Formatter/AbstractFormatter.php +++ b/Formatter/AbstractFormatter.php @@ -73,6 +73,8 @@ abstract class AbstractFormatter implements FormatterInterface 'dataType' => $info['dataType'], 'readonly' => $info['readonly'], 'required' => $info['required'], + 'sinceVersion' => array_key_exists('sinceVersion', $info) ? $info['sinceVersion'] : null, + 'untilVersion' => array_key_exists('untilVersion', $info) ? $info['untilVersion'] : null, ); if (isset($info['children']) && (!$info['readonly'] || !$ignoreNestedReadOnly)) { diff --git a/Formatter/MarkdownFormatter.php b/Formatter/MarkdownFormatter.php index b4865ba..4bfe286 100644 --- a/Formatter/MarkdownFormatter.php +++ b/Formatter/MarkdownFormatter.php @@ -103,6 +103,20 @@ class MarkdownFormatter extends AbstractFormatter $markdown .= sprintf(" * description: %s\n", $parameter['description']); } + if (null !== $parameter['sinceVersion'] || null !== $parameter['untilVersion']) { + $markdown .= " * versions: "; + if ($parameter['sinceVersion']) { + $markdown .= '>='.$parameter['sinceVersion']; + } + if ($parameter['untilVersion']) { + if ($parameter['sinceVersion']) { + $markdown .= ','; + } + $markdown .= '<='.$parameter['untilVersion']; + } + $markdown .= "\n"; + } + $markdown .= "\n"; } } diff --git a/Parser/JmsMetadataParser.php b/Parser/JmsMetadataParser.php index 0882d0e..8286e20 100644 --- a/Parser/JmsMetadataParser.php +++ b/Parser/JmsMetadataParser.php @@ -12,8 +12,6 @@ namespace Nelmio\ApiDocBundle\Parser; use JMS\Serializer\Exclusion\GroupsExclusionStrategy; -use JMS\Serializer\GraphNavigator; -use JMS\Serializer\NavigatorContext; use JMS\Serializer\SerializationContext; use Metadata\MetadataFactoryInterface; use Nelmio\ApiDocBundle\Util\DocCommentExtractor; @@ -79,7 +77,7 @@ class JmsMetadataParser implements ParserInterface $className = $input['class']; $groups = $input['groups']; - return $this->doParse($className, array(), $groups, $version); + return $this->doParse($className, array(), $groups); } /** @@ -87,7 +85,7 @@ class JmsMetadataParser implements ParserInterface * * @param string $className Class to get all metadata for * @param array $visited Classes we've already visited to prevent infinite recursion. - * @param array $groups Groups to be used in the group exclusion strategy + * @param array $groups Serialization groups to include. * @return array metadata for given class * @throws \InvalidArgumentException */ @@ -119,11 +117,13 @@ class JmsMetadataParser implements ParserInterface } $params[$name] = array( - 'dataType' => $dataType['normalized'], - 'required' => false, + 'dataType' => $dataType['normalized'], + 'required' => false, //TODO: can't think of a good way to specify this one, JMS doesn't have a setting for this - 'description' => $this->getDescription($className, $item), - 'readonly' => $item->readOnly + 'description' => $this->getDescription($className, $item), + 'readonly' => $item->readOnly, + 'sinceVersion' => $item->sinceVersion, + 'untilVersion' => $item->untilVersion, ); // if class already parsed, continue, to avoid infinite recursion diff --git a/README.md b/README.md index 4a76bc1..9ed3a02 100644 --- a/README.md +++ b/README.md @@ -106,27 +106,6 @@ The following properties are available: * `input`: the input type associated to the method, currently this supports Form Types, and classes with JMS Serializer metadata, useful for POST|PUT methods, either as FQCN or as form type (if it is registered in the form factory in the container). - When using a class with JMS Serializer metadata, you can - [use specific groups](http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies#creating-different-views-of-your-objects) - by using this syntax: - - ``` - input={ - "class"="Acme\Bundle\Entity\User", - "groups"={"update", "public"} - } - ``` - - In this case the groups 'update' and 'public' are used. - - Also supported are versions: - - ``` - input={ - "class"="Acme\Bundle\Entity\User", - "version"="2.3" - } - ``` * `output`: the output type associated with the response. Specified and parsed the same way as `input`. @@ -204,6 +183,31 @@ Also bundle will get information from the other annotations: Route functions marked as @deprecated will be set method as deprecation in documentation. +#### JMS Serializer features #### + +The bundle has support for some of the JMS Serializer features and use these extra information in the generated documentation. + +##### Group Exclusion Strategy ##### + +If your classes use [JMS Group Exclusion Strategy](http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies#creating-different-views-of-your-objects), +you can specify which groups to use when generating the documentation by using this syntax : + + ``` + input={ + "class"="Acme\Bundle\Entity\User", + "groups"={"update", "public"} + } + ``` + + In this case the groups 'update' and 'public' are used. + + This feature also works for the `output` property. + +##### Versioning Objects ##### + +If your `output` classes use [versioning capabilities of JMS Serializer](http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies#versioning-objects), +the versioning information will be automatically used when generating the documentation. + ### Documentation on-the-fly ### By calling an URL with the parameter `?_doc=1`, you will get the corresponding documentation if available. diff --git a/Resources/views/Components/version.html.twig b/Resources/views/Components/version.html.twig new file mode 100644 index 0000000..24d5848 --- /dev/null +++ b/Resources/views/Components/version.html.twig @@ -0,0 +1,8 @@ +{% if sinceVersion is empty and untilVersion is empty %} +* +{% else %} + {% if sinceVersion is not empty %}>={{ sinceVersion }}{% endif %} + {% if untilVersion is not empty %} + {% if sinceVersion is not empty %},{% endif %}<={{ untilVersion }} + {% endif %} +{% endif %} diff --git a/Resources/views/method.html.twig b/Resources/views/method.html.twig index 1602b68..81649a5 100644 --- a/Resources/views/method.html.twig +++ b/Resources/views/method.html.twig @@ -134,6 +134,7 @@ Parameter Type + Versions Description @@ -142,6 +143,7 @@ {{ name }} {{ infos.dataType }} + {% include 'NelmioApiDocBundle:Components:version.html.twig' with {'sinceVersion': infos.sinceVersion, 'untilVersion': infos.untilVersion} only %} {{ infos.description }} {% endfor %} diff --git a/Tests/Extractor/ApiDocExtractorTest.php b/Tests/Extractor/ApiDocExtractorTest.php index 8eba7ca..1948c36 100644 --- a/Tests/Extractor/ApiDocExtractorTest.php +++ b/Tests/Extractor/ApiDocExtractorTest.php @@ -15,7 +15,7 @@ use Nelmio\ApiDocBundle\Tests\WebTestCase; class ApiDocExtractorTest extends WebTestCase { - const ROUTES_QUANTITY = 19; + const ROUTES_QUANTITY = 20; public function testAll() { @@ -66,7 +66,7 @@ class ApiDocExtractorTest extends WebTestCase $this->assertFalse(isset($array2['filters'])); $this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getInput()); - $a3 = $data['12']['annotation']; + $a3 = $data['13']['annotation']; $this->assertTrue($a3->getHttps()); } @@ -155,7 +155,7 @@ class ApiDocExtractorTest extends WebTestCase "This method is useful to test if the getDocComment works.", $annotation->getDescription() ); - + $data = $annotation->toArray(); $this->assertEquals( 4, diff --git a/Tests/Fixtures/Controller/TestController.php b/Tests/Fixtures/Controller/TestController.php index bcb3b0a..ea86559 100644 --- a/Tests/Fixtures/Controller/TestController.php +++ b/Tests/Fixtures/Controller/TestController.php @@ -172,7 +172,7 @@ class TestController public function cachedAction() { } - + /** * @ApiDoc() * @deprecated @@ -180,4 +180,13 @@ class TestController public function deprecatedAction() { } + + /** + * @ApiDoc( + * output="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest" + * ) + */ + public function jmsReturnNestedOutputAction() + { + } } diff --git a/Tests/Fixtures/Model/JmsNested.php b/Tests/Fixtures/Model/JmsNested.php index 37162cc..18877fb 100644 --- a/Tests/Fixtures/Model/JmsNested.php +++ b/Tests/Fixtures/Model/JmsNested.php @@ -36,4 +36,22 @@ class JmsNested */ public $parent; + /** + * @Jms\Type("string") + * @Jms\Since("0.2") + */ + public $since; + + /** + * @Jms\Type("string") + * @Jms\Until("0.3") + */ + public $until; + + /** + * @Jms\Type("string") + * @Jms\Since("0.4") + * @Jms\Until("0.5") + */ + public $sinceAndUntil; } diff --git a/Tests/Fixtures/app/config/routing.yml b/Tests/Fixtures/app/config/routing.yml index 65cc687..fcbf561 100644 --- a/Tests/Fixtures/app/config/routing.yml +++ b/Tests/Fixtures/app/config/routing.yml @@ -117,3 +117,7 @@ test_route_17: defaults: { _controller: NelmioApiDocTestBundle:Test:deprecated } requirements: _method: GET + +test_return_nested_output: + pattern: /return-nested-output + defaults: { _controller: NelmioApiDocTestBundle:Test:jmsReturnNestedOutput, _format: json } diff --git a/Tests/Formatter/MarkdownFormatterTest.php b/Tests/Formatter/MarkdownFormatterTest.php index ff62f91..12da9a5 100644 --- a/Tests/Formatter/MarkdownFormatterTest.php +++ b/Tests/Formatter/MarkdownFormatterTest.php @@ -244,6 +244,21 @@ nested[parent][nested_array][]: * type: array of objects (JmsNested) * required: false +nested[since]: + + * type: string + * required: false + +nested[until]: + + * type: string + * required: false + +nested[since_and_until]: + + * type: string + * required: false + nested_array[]: * type: array of objects (JmsNested) @@ -285,6 +300,98 @@ _This method is useful to test if the getDocComment works._ - Description: The param id +### `ANY` /return-nested-output ### + + +#### Response #### + +foo: + + * type: string + +bar: + + * type: DateTime + +number: + + * type: double + +arr: + + * type: array + +nested: + + * type: object (JmsNested) + +nested[foo]: + + * type: DateTime + +nested[bar]: + + * type: string + +nested[baz][]: + + * type: array of integers + * description: Epic description. + +With multiple lines. + +nested[circular]: + + * type: object (JmsNested) + +nested[parent]: + + * type: object (JmsTest) + +nested[parent][foo]: + + * type: string + +nested[parent][bar]: + + * type: DateTime + +nested[parent][number]: + + * type: double + +nested[parent][arr]: + + * type: array + +nested[parent][nested]: + + * type: object (JmsNested) + +nested[parent][nested_array][]: + + * type: array of objects (JmsNested) + +nested[since]: + + * type: string + * versions: >=0.2 + +nested[until]: + + * type: string + * versions: <=0.3 + +nested[since_and_until]: + + * type: string + * versions: >=0.4,<=0.5 + +nested_array[]: + + * type: array of objects (JmsNested) + + ### `ANY` /secure-route ### diff --git a/Tests/Formatter/SimpleFormatterTest.php b/Tests/Formatter/SimpleFormatterTest.php index 3a640a2..603a05e 100644 --- a/Tests/Formatter/SimpleFormatterTest.php +++ b/Tests/Formatter/SimpleFormatterTest.php @@ -252,6 +252,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( @@ -259,6 +261,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'number' => array( @@ -266,6 +270,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'arr' => array( @@ -273,6 +279,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'nested' => array( @@ -280,6 +288,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, 'children' => array( 'foo' => @@ -288,6 +298,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( @@ -295,6 +307,8 @@ class SimpleFormatterTest extends WebTestCase 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'baz' => array( @@ -304,6 +318,8 @@ class SimpleFormatterTest extends WebTestCase With multiple lines.', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'circular' => array( @@ -311,6 +327,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'parent' => array( @@ -318,6 +336,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, 'children' => array( 'foo' => @@ -326,6 +346,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( @@ -333,6 +355,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'number' => array( @@ -340,6 +364,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'arr' => array( @@ -347,6 +373,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'nested' => array( @@ -354,6 +382,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'nested_array' => array( @@ -361,9 +391,38 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), ), ), + 'since' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => '0.2', + 'untilVersion' => null, + ), + 'until' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => '0.3', + ), + 'since_and_until' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => '0.4', + 'untilVersion' => '0.5', + ), ), ), 'nested_array' => @@ -372,6 +431,8 @@ With multiple lines.', 'required' => false, 'description' => '', 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), ), 'https' => false, @@ -438,6 +499,205 @@ And, it supports multilines until the first \'@\' char.', 'deprecated' => false, ), 7 => + array( + 'method' => 'ANY', + 'uri' => '/return-nested-output', + 'https' => false, + 'authentication' => false, + 'deprecated' => false, + 'response' => + array ( + 'foo' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'bar' => + array ( + 'dataType' => 'DateTime', + 'required' => false, + 'description' => '', + 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'number' => + array ( + 'dataType' => 'double', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'arr' => + array ( + 'dataType' => 'array', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'nested' => + array ( + 'dataType' => 'object (JmsNested)', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + 'children' => + array ( + 'foo' => + array ( + 'dataType' => 'DateTime', + 'required' => false, + 'description' => '', + 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'bar' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'baz' => + array ( + 'dataType' => 'array of integers', + 'required' => false, + 'description' => 'Epic description. + +With multiple lines.', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'circular' => + array ( + 'dataType' => 'object (JmsNested)', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'parent' => + array ( + 'dataType' => 'object (JmsTest)', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + 'children' => + array ( + 'foo' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'bar' => + array ( + 'dataType' => 'DateTime', + 'required' => false, + 'description' => '', + 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'number' => + array ( + 'dataType' => 'double', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'arr' => + array ( + 'dataType' => 'array', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'nested' => + array ( + 'dataType' => 'object (JmsNested)', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'nested_array' => + array ( + 'dataType' => 'array of objects (JmsNested)', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + ), + ), + 'since' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => '0.2', + 'untilVersion' => null, + ), + 'until' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => '0.3', + ), + 'since_and_until' => + array ( + 'dataType' => 'string', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => '0.4', + 'untilVersion' => '0.5', + ), + ), + ), + 'nested_array' => + array ( + 'dataType' => 'array of objects (JmsNested)', + 'required' => false, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + ), + ), + 8 => array( 'method' => 'ANY', 'uri' => '/secure-route', @@ -454,7 +714,7 @@ And, it supports multilines until the first \'@\' char.', 'authentication' => false, 'deprecated' => false, ), - 8 => + 9 => array( 'method' => 'ANY', 'uri' => '/yet-another/{id}', @@ -471,7 +731,7 @@ And, it supports multilines until the first \'@\' char.', 'authentication' => false, 'deprecated' => false, ), - 9 => + 10 => array( 'method' => 'GET', 'uri' => '/z-action-with-deprecated-indicator', @@ -479,7 +739,7 @@ And, it supports multilines until the first \'@\' char.', 'authentication' => false, 'deprecated' => true, ), - 10 => + 11 => array( 'method' => 'GET', 'uri' => '/z-action-with-query-param', @@ -496,7 +756,7 @@ And, it supports multilines until the first \'@\' char.', 'authentication' => false, 'deprecated' => false, ), - 11 => + 12 => array( 'method' => 'GET', 'uri' => '/z-action-with-query-param-no-default', @@ -512,7 +772,7 @@ And, it supports multilines until the first \'@\' char.', 'authentication' => false, 'deprecated' => false, ), - 12 => + 13 => array( 'method' => 'GET', 'uri' => '/z-action-with-query-param-strict', @@ -529,7 +789,7 @@ And, it supports multilines until the first \'@\' char.', 'authentication' => false, 'deprecated' => false, ), - 13 => + 14 => array( 'method' => 'POST', 'uri' => '/z-action-with-request-param', diff --git a/Tests/Parser/JmsMetadataParserTest.php b/Tests/Parser/JmsMetadataParserTest.php index 8d4acae..3e41883 100644 --- a/Tests/Parser/JmsMetadataParserTest.php +++ b/Tests/Parser/JmsMetadataParserTest.php @@ -75,29 +75,34 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase array( 'class' => $input, 'groups' => array(), - 'version' => null, ) ); $this->assertEquals( array( 'foo' => array( - 'dataType' => 'DateTime', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'DateTime', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'baz' => array( - 'dataType' => 'array of integers', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'array of integers', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ) ), $output @@ -143,23 +148,26 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase array( 'class' => $input, 'groups' => array(), - 'version' => null, ) ); $this->assertEquals( array( 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), ), $output @@ -170,23 +178,26 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase array( 'class' => $input, 'groups' => array('Default'), - 'version' => null, ) ); $this->assertEquals( array( 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), ), $output @@ -197,23 +208,26 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase array( 'class' => $input, 'groups' => array('Special'), - 'version' => null, ) ); $this->assertEquals( array( 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'baz' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), ), $output @@ -224,29 +238,34 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase array( 'class' => $input, 'groups' => array('Default', 'Special'), - 'version' => null, ) ); $this->assertEquals( array( 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'baz' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ) ), $output @@ -265,14 +284,18 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase $propertyMetadataBar = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'bar'); $propertyMetadataBar->type = array('name' => 'string'); - $propertyMetadataBar->sinceVersion = '0.2'; - $propertyMetadataBar->untilVersion = '0.3'; + $propertyMetadataBar->sinceVersion = '2.0'; + + $propertyMetadataBaz = new PropertyMetadata('Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested', 'baz'); + $propertyMetadataBaz->type = array('name' => 'string'); + $propertyMetadataBaz->untilVersion = '3.0'; $input = 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested'; $metadata = new ClassMetadata($input); $metadata->addPropertyMetadata($propertyMetadataFoo); $metadata->addPropertyMetadata($propertyMetadataBar); + $metadata->addPropertyMetadata($propertyMetadataBaz); $metadataFactory->expects($this->any()) ->method('getMetadataForClass') @@ -283,100 +306,40 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase $jmsMetadataParser = new JmsMetadataParser($metadataFactory, $propertyNamingStrategy, $docCommentExtractor); - // No version specified. + // No group specified. $output = $jmsMetadataParser->parse( array( 'class' => $input, 'groups' => array(), - 'version' => null, ) ); $this->assertEquals( array( 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, ), 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => '2.0', + 'untilVersion' => null, ), - ), - $output - ); - - // 0.1 - $output = $jmsMetadataParser->parse( - array( - 'class' => $input, - 'groups' => array(), - 'version' => '0.1', - ) - ); - - $this->assertEquals( - array( - 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false - ), - ), - $output - ); - - // 0.2 & 0.3 - foreach (array('0.2', '0.3') as $version) { - $output = $jmsMetadataParser->parse( - array( - 'class' => $input, - 'groups' => array(), - 'version' => $version, + 'baz' => array( + 'dataType' => 'string', + 'required' => false, + 'description' => null, + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => '3.0', ) - ); - - $this->assertEquals( - array( - 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false - ), - 'bar' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false - ), - ), - $output - ); - } - - // 0.4 - $output = $jmsMetadataParser->parse( - array( - 'class' => $input, - 'groups' => array(), - 'version' => '0.4', - ) - ); - - $this->assertEquals( - array( - 'foo' => array( - 'dataType' => 'string', - 'required' => false, - 'description' => 'No description.', - 'readonly' => false - ), ), $output );