NelmioApiDocBundle/Parser/JmsMetadataParser.php

162 lines
4.5 KiB
PHP
Raw Normal View History

<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Parser;
use Metadata\MetadataFactoryInterface;
/**
* Uses the JMS metadata factory to extract input/output model information
*/
class JmsMetadataParser implements ParserInterface
{
2012-08-07 21:57:36 -04:00
/**
* Constructor, requires JMS Metadata factory
*/
public function __construct(MetadataFactoryInterface $factory)
{
$this->factory = $factory;
}
2012-08-07 21:57:36 -04:00
/**
* {@inheritdoc}
*/
public function supports($input)
{
try {
if ($meta = $this->factory->getMetadataForClass($input)) {
return true;
}
} catch (\ReflectionException $e) {
}
return false;
}
2012-08-07 21:57:36 -04:00
/**
* {@inheritdoc}
*/
public function parse($input)
{
$meta = $this->factory->getMetadataForClass($input);
2012-08-08 10:21:56 -04:00
if (null === $meta) {
throw new \InvalidArgumentException(sprintf("No metadata found for class %s", $input));
}
2012-08-07 21:57:36 -04:00
$params = array();
2012-08-07 21:57:36 -04:00
//iterate over property metadata
foreach ($meta->propertyMetadata as $item) {
2012-08-07 21:57:36 -04:00
if (!is_null($item->type)) {
$name = isset($item->serializedName) ? $item->serializedName : $item->name;
2012-08-07 21:57:36 -04:00
$params[$name] = array(
'dataType' => $this->getNormalizedType($item->type),
'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
);
2012-08-24 11:12:36 -04:00
//check for nested classes w/ JMS metadata
if ($nestedInputClass = $this->getNestedClass($item->type)) {
$params[$name]['children'] = $this->parse($nestedInputClass);
}
}
}
2012-08-07 21:57:36 -04:00
return $params;
}
2012-08-24 11:12:36 -04:00
/**
* There are various ways via JMS to declare arrays of objects, but that's an internal
* implementation detail.
*
2012-08-24 11:12:36 -04:00
* @param string $type
* @return string
*/
protected function getNormalizedType($type)
{
if (in_array($type, array('boolean', 'integer', 'string', 'double', 'array', 'DateTime'))) {
return $type;
}
2012-08-24 11:12:36 -04:00
if (false !== strpos($type, "array") || false !== strpos($type, "ArrayCollection")) {
if ($nested = $this->getNestedClassInArray($type)) {
$exp = explode("\\", $nested);
2012-08-24 11:12:36 -04:00
return sprintf("array of objects (%s)", end($exp));
} else {
return "array";
}
}
2012-08-24 11:12:36 -04:00
$exp = explode("\\", $type);
2012-08-24 11:12:36 -04:00
return sprintf("object (%s)", end($exp));
}
2012-08-24 11:12:36 -04:00
/**
* Check the various ways JMS describes custom classes in arrays, and
* get the name of the class in the array, if available.
*
2012-08-24 11:12:36 -04:00
* @param string $type
* @return string|false
*/
protected function getNestedClassInArray($type)
{
//could be some type of array with <V>, or <K,V>
$regEx = "/\<([A-Za-z0-9\\\]*)(\,?\s?(.*))?\>/";
if (preg_match($regEx, $type, $matches)) {
$matched = (!empty($matches[3])) ? $matches[3] : $matches[1];
2012-08-24 11:12:36 -04:00
return in_array($matched, array('boolean', 'integer', 'string', 'double', 'array', 'DateTime')) ? false : $matched;
}
2012-08-24 11:12:36 -04:00
return false;
}
2012-08-24 11:12:36 -04:00
/**
* Scan the JMS Serializer types for reference to a class.
*
* http://jmsyst.com/bundles/JMSSerializerBundle/master/reference/annotations#type
*
2012-08-24 11:12:36 -04:00
* @param string $type
* @return string|false
*/
protected function getNestedClass($type)
{
if (in_array($type, array('boolean', 'integer', 'string', 'double', 'array', 'DateTime'))) {
return false;
}
2012-08-24 11:12:36 -04:00
//could be a nested object of some sort
if ($nested = $this->getNestedClassInArray($type)) {
return $nested;
}
2012-08-24 11:12:36 -04:00
//or could just be a class name (potentially)
return (null === $this->factory->getMetadataForClass($type)) ? false : $type;
}
2012-08-07 21:57:36 -04:00
protected function getDescription($className, $propertyName)
{
$description = "No description.";
//TODO: abstract docblock parsing utility and implement here
return $description;
}
}