Merge pull request #67 from evillemez/nested_jms

updated JMSMetadataParser to support nested models
This commit is contained in:
William Durand 2012-08-28 12:29:02 -07:00
commit d6c50427aa
6 changed files with 179 additions and 5 deletions

View File

@ -61,26 +61,97 @@ class JmsMetadataParser implements ParserInterface
if (!is_null($item->type)) {
$name = isset($item->serializedName) ? $item->serializedName : $item->name;
//TODO: check for nested type
$dataType = $this->processDataType($item->type);
$params[$name] = array(
'dataType' => $item->type,
'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->name),
'readonly' => $item->readOnly
);
//check for nested classes with JMS metadata
if ($dataType['class'] && null !== $this->factory->getMetadataForClass($dataType['class'])) {
$params[$name]['children'] = $this->parse($dataType['class']);
}
}
}
return $params;
}
/**
* Figure out a normalized data type (for documentation), and get a
* nested class name, if available.
*
* @param string $type
* @return array
*/
protected function processDataType($type)
{
//could be basic type
if ($this->isPrimitive($type)) {
return array(
'normalized' => $type,
'class' => null
);
}
//check for a type inside something that could be treated as an array
if ($nestedType = $this->getNestedTypeInArray($type)) {
if ($this->isPrimitive($nestedType)) {
return array(
'normalized' => sprintf("array of %ss", $nestedType),
'class' => null
);
}
$exp = explode("\\", $nestedType);
return array(
'normalized' => sprintf("array of objects (%s)", end($exp)),
'class' => $nestedType
);
}
//if we got this far, it's a general class name
$exp = explode("\\", $type);
return array(
'normalized' => sprintf("object (%s)", end($exp)),
'class' => $type
);
}
protected function isPrimitive($type)
{
return in_array($type, array('boolean', 'integer', 'string', 'double', 'array', 'DateTime'));
}
/**
* Check the various ways JMS describes values in arrays, and
* get the value type in the array
*
* @param string $type
* @return string|null
*/
protected function getNestedTypeInArray($type)
{
//could be some type of array with <V>, or <K,V>
$regEx = "/\<([A-Za-z0-9\\\]*)(\,?\s?(.*))?\>/";
if (preg_match($regEx, $type, $matches)) {
return (!empty($matches[3])) ? $matches[3] : $matches[1];
}
return null;
}
protected function getDescription($className, $propertyName)
{
$description = "No description.";
//TODO: regex comment to get description - or move doc comment parsing functionality from `ApiDocExtractor` to a new location
//in order to reuse it here
//TODO: abstract docblock parsing utility and implement here
return $description;
}

View File

@ -31,6 +31,8 @@ interface ParserInterface
* - required boolean
* - description string
* - readonly boolean
* - children (optional) array of nested property names mapped to arrays
* in the format described here
*
* @param string $item The string type of input to parse.
* @return array

View File

@ -0,0 +1,27 @@
<?php
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model;
use JMS\SerializerBundle\Annotation as JMS;
class JmsNested
{
/**
* @JMS\Type("DateTime");
* @JMS\ReadOnly
*/
public $foo;
/**
* @JMS\Type("string");
*/
public $bar;
/**
* Epic description.
*
* @JMS\Type("array<integer>")
*/
public $baz;
}

View File

@ -30,4 +30,14 @@ class JmsTest
*/
public $arr;
/**
* @JMS\Type("Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested");
*/
public $nested;
/**
* @JMS\Type("array<Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsNested>");
*/
public $nestedArray;
}

View File

@ -185,6 +185,18 @@ arr:
* required: false
* description: No description.
nested:
* type: object (JmsNested)
* required: false
* description: No description.
nestedArray:
* type: array of objects (JmsNested)
* required: false
* description: No description.
### `GET` /jms-return-test ###

View File

@ -210,7 +210,59 @@ class SimpleFormatterTest extends WebTestCase
'required' => false,
'description' => 'No description.',
'readonly' => false
)
),
'nested' => array(
'dataType' => 'object (JmsNested)',
'required' => false,
'description' => 'No description.',
'readonly' => false,
'children' => array(
'foo' => array(
'dataType' => 'DateTime',
'required' => false,
'description' => 'No description.',
'readonly' => true,
),
'bar' => array(
'dataType' => 'string',
'required' => false,
'description' => 'No description.',
'readonly' => false,
),
'baz' => array(
'dataType' => 'array of integers',
'required' => false,
'description' => 'No description.',
'readonly' => false,
)
)
),
'nestedArray' => array(
'dataType' => 'array of objects (JmsNested)',
'required' => false,
'description' => 'No description.',
'readonly' => false,
'children' => array(
'foo' => array(
'dataType' => 'DateTime',
'required' => false,
'description' => 'No description.',
'readonly' => true,
),
'bar' => array(
'dataType' => 'string',
'required' => false,
'description' => 'No description.',
'readonly' => false,
),
'baz' => array(
'dataType' => 'array of integers',
'required' => false,
'description' => 'No description.',
'readonly' => false,
)
)
),
),
'description' => 'Testing JMS'
),