mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 07:41:43 +03:00
Add a parser for jsonSerializable classes
This commit is contained in:
parent
a343bb7c45
commit
37c6465700
86
Parser/JsonSerializableParser.php
Normal file
86
Parser/JsonSerializableParser.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by mcfedr on 30/06/15 21:03
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Parser;
|
||||
|
||||
class JsonSerializableParser implements ParserInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(array $item)
|
||||
{
|
||||
if (!is_subclass_of($item['class'], 'JsonSerializable')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ref = new \ReflectionClass($item['class']);
|
||||
if ($ref->hasMethod('__construct')) {
|
||||
foreach ($ref->getMethod('__construct')->getParameters() as $parameter) {
|
||||
if (!$parameter->isOptional()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parse(array $item)
|
||||
{
|
||||
/** @var \JsonSerializable $obj */
|
||||
$obj = new $item['class']();
|
||||
|
||||
$encoded = $obj->jsonSerialize();
|
||||
$top = $this->getItemMetaData($encoded);
|
||||
|
||||
return $top['children'];
|
||||
}
|
||||
|
||||
public function getItemMetaData($item)
|
||||
{
|
||||
$type = gettype($item);
|
||||
|
||||
$meta = array(
|
||||
'dataType' => $type,
|
||||
'required' => true,
|
||||
'description' => '',
|
||||
'readonly' => false
|
||||
);
|
||||
|
||||
if ($type == 'object' && $item instanceof \JsonSerializable) {
|
||||
$meta = $this->getItemMetaData($item->jsonSerialize());
|
||||
$meta['class'] = get_class($item);
|
||||
} elseif (($type == 'object' && $item instanceof \stdClass) || ($type == 'array' && !$this->isSequential($item))) {
|
||||
$meta['dataType'] = 'object';
|
||||
$meta['children'] = array();
|
||||
foreach ($item as $key => $value) {
|
||||
$meta['children'][$key] = $this->getItemMetaData($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for numeric sequential keys, just like the json encoder does
|
||||
* Credit: http://stackoverflow.com/a/25206156/859027
|
||||
*
|
||||
* @param array $arr
|
||||
* @return bool
|
||||
*/
|
||||
private function isSequential(array $arr)
|
||||
{
|
||||
for ($i = count($arr) - 1; $i >= 0; $i--) {
|
||||
if (!isset($arr[$i]) && !array_key_exists($i, $arr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
<parameter key="nelmio_api_doc.parser.collection_parser.class">Nelmio\ApiDocBundle\Parser\CollectionParser</parameter>
|
||||
<parameter key="nelmio_api_doc.parser.form_errors_parser.class">Nelmio\ApiDocBundle\Parser\FormErrorsParser</parameter>
|
||||
<parameter key="nelmio_api_doc.parser.json_serializable_parser.class">Nelmio\ApiDocBundle\Parser\JsonSerializableParser</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
@ -68,6 +69,10 @@
|
||||
<service id="nelmio_api_doc.parser.form_errors_parser" class="%nelmio_api_doc.parser.form_errors_parser.class%">
|
||||
<tag name="nelmio_api_doc.extractor.parser" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.parser.json_serializable_parser" class="%nelmio_api_doc.parser.json_serializable_parser.class%">
|
||||
<tag name="nelmio_api_doc.extractor.parser" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
||||
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by mcfedr on 30/06/15 21:05
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model;
|
||||
|
||||
class JsonSerializableOptionalConstructorTest implements \JsonSerializable
|
||||
{
|
||||
public function __construct($optional = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by mcfedr on 30/06/15 21:05
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model;
|
||||
|
||||
class JsonSerializableRequiredConstructorTest implements \JsonSerializable
|
||||
{
|
||||
public function __construct($required)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
24
Tests/Fixtures/Model/JsonSerializableTest.php
Normal file
24
Tests/Fixtures/Model/JsonSerializableTest.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by mcfedr on 30/06/15 21:05
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model;
|
||||
|
||||
class JsonSerializableTest implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'id' => 123,
|
||||
'name' => 'My name',
|
||||
'child' => array(
|
||||
'value' => array(1, 2, 3)
|
||||
),
|
||||
'another' => new JsonSerializableOptionalConstructorTest()
|
||||
);
|
||||
}
|
||||
}
|
98
Tests/Parser/JsonSerializableParserTest.php
Normal file
98
Tests/Parser/JsonSerializableParserTest.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by mcfedr on 30/06/15 21:06
|
||||
*/
|
||||
|
||||
|
||||
namespace NelmioApiDocBundle\Tests\Parser;
|
||||
|
||||
|
||||
use Nelmio\ApiDocBundle\Parser\JsonSerializableParser;
|
||||
|
||||
class JsonSerializableParserTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var JsonSerializableParser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->parser = new JsonSerializableParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestParser
|
||||
*/
|
||||
public function testParser($property, $expected)
|
||||
{
|
||||
$result = $this->parser->parse(array('class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JsonSerializableTest'));
|
||||
foreach ($expected as $name => $value) {
|
||||
$this->assertArrayHasKey($property, $result);
|
||||
$this->assertArrayHasKey($name, $result[$property]);
|
||||
$this->assertEquals($result[$property][$name], $expected[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestSupports
|
||||
*/
|
||||
public function testSupports($class, $expected)
|
||||
{
|
||||
$this->assertEquals($this->parser->supports(array('class' => $class)), $expected);
|
||||
}
|
||||
|
||||
public function dataTestParser()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'property' => 'id',
|
||||
'expected' => array(
|
||||
'dataType' => 'integer'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'property' => 'name',
|
||||
'expected' => array(
|
||||
'dataType' => 'string'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'property' => 'child',
|
||||
'expected' => array(
|
||||
'dataType' => 'object',
|
||||
'children' => array(
|
||||
'value' => array(
|
||||
'dataType' => 'array',
|
||||
'required' => true,
|
||||
'description' => '',
|
||||
'readonly' => false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestSupports()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JsonSerializableTest',
|
||||
'expected' => true
|
||||
),
|
||||
array(
|
||||
'class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JsonSerializableRequiredConstructorTest',
|
||||
'expected' => false
|
||||
),
|
||||
array(
|
||||
'class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\JsonSerializableOptionalConstructorTest',
|
||||
'expected' => true
|
||||
),
|
||||
array(
|
||||
'class' => 'Nelmio\ApiDocBundle\Tests\Fixtures\Model\Popo',
|
||||
'expected' => false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user