Skip to content

Commit

Permalink
Fixed infinite recursion on JMS Types that reference themselves or th…
Browse files Browse the repository at this point in the history
…eir parents.
  • Loading branch information
Boy Baukema committed Dec 20, 2012
1 parent c946fbc commit fe76b6d
Show file tree
Hide file tree
Showing 4 changed files with 283 additions and 135 deletions.
28 changes: 19 additions & 9 deletions Parser/JmsMetadataParser.php
Expand Up @@ -32,8 +32,6 @@ class JmsMetadataParser implements ParserInterface
*/
private $commentExtractor;

private $parsedClasses = array();

/**
* Constructor, requires JMS Metadata factory
*/
Expand Down Expand Up @@ -63,10 +61,23 @@ public function supports($input)
*/
public function parse($input)
{
$meta = $this->factory->getMetadataForClass($input);
return $this->doParse($input);
}

/**
* Recursively parse all metadata for a class
*
* @param string $className Class to get all metadata for
* @param array $visited Classes we've already visited to prevent infinite recursion.
* @return array metadata for given class
* @throws \InvalidArgumentException
*/
protected function doParse($className, $visited = array())
{
$meta = $this->factory->getMetadataForClass($className);

if (null === $meta) {
throw new \InvalidArgumentException(sprintf("No metadata found for class %s", $input));
throw new \InvalidArgumentException(sprintf("No metadata found for class %s", $className));
}

$params = array();
Expand All @@ -82,23 +93,22 @@ public function parse($input)
$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($input, $item),
'description' => $this->getDescription($className, $item),
'readonly' => $item->readOnly
);

// if class already parsed, continue, to avoid infinite recursion
if (in_array($dataType['class'], $this->parsedClasses)) {
if (in_array($dataType['class'], $visited)) {
continue;
}

//check for nested classes with JMS metadata
if ($dataType['class'] && null !== $this->factory->getMetadataForClass($dataType['class'])) {
$this->parsedClasses[] = $dataType['class'];
$params[$name]['children'] = $this->parse($dataType['class']);
$visited[] = $dataType['class'];
$params[$name]['children'] = $this->doParse($dataType['class'], $visited);
}
}
}
$this->parsedClasses = array();

return $params;
}
Expand Down
10 changes: 10 additions & 0 deletions Tests/Fixtures/Model/JmsNested.php
Expand Up @@ -26,4 +26,14 @@ class JmsNested
*/
public $baz;

/**
* @JMS\Type("Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested");
*/
public $circular;

/**
* @JMS\Type("Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest");
*/
public $parent;

}
46 changes: 37 additions & 9 deletions Tests/Formatter/MarkdownFormatterTest.php
Expand Up @@ -199,25 +199,53 @@ public function testFormat()
With multiple lines.
nestedArray[]:
nested[circular]:
* type: array of objects (JmsNested)
* type: object (JmsNested)
* required: false
* description: No description.
nested[parent]:
* type: object (JmsTest)
* required: false
* description: No description.
nestedArray[][bar]:
nested[parent][foo]:
* type: string
* required: false
* description: No description.
nestedArray[][baz][]:
nested[parent][number]:
* type: array of integers
* type: double
* required: false
* description: Epic description.
* description: No description.
With multiple lines.
nested[parent][arr]:
* type: array
* required: false
* description: No description.
nested[parent][nested]:
* type: object (JmsNested)
* required: false
* description: No description.
nested[parent][nestedArray][]:
* type: array of objects (JmsNested)
* required: false
* description: No description.
nestedArray[]:
* type: array of objects (JmsNested)
* required: false
* description: No description.
### `GET` /jms-return-test ###
Expand Down Expand Up @@ -264,7 +292,7 @@ public function testFormat()
**id**
- Requirement: \d+
- Requirement: \\d+
### `GET` /z-action-with-query-param ###
Expand All @@ -274,7 +302,7 @@ public function testFormat()
page:
* Requirement: \d+
* Requirement: \\d+
* Description: Page of the overview.
Expand Down

0 comments on commit fe76b6d

Please sign in to comment.