mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-10 03:29:25 +03:00
[JMSModelDescriber] Allow to use free form objects from JMS serialization (#1368)
* [JMSModelDescriber] Allow to use free form objects from JMS serialization * Remove unused variable * Refactor `describeItem()` * Add more tests * early detect of free form objects * Add test for array property without type * Merge `findPropertyType()` and `registerPropertyType()` methods * Update `registerPropertyType()` in order to set "object" as type for arrays with undefined item types * Set "additionalProperties" definition for arrays without defined items * Simplified `registerPropertyType()` * Merged `registerPropertyType()` into `describeItem()` * Fix comment * Fix comment
This commit is contained in:
parent
82caa9a063
commit
df9893428e
@ -118,54 +118,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function describeItem(array $type, Schema $property, array $groups = null)
|
||||||
* @param string $type
|
|
||||||
* @param array|null $groups
|
|
||||||
*
|
|
||||||
* @return array|null
|
|
||||||
*/
|
|
||||||
private function findPropertyType(string $type, array $groups = null)
|
|
||||||
{
|
|
||||||
$typeDef = [];
|
|
||||||
if (in_array($type, ['boolean', 'string', 'array'])) {
|
|
||||||
$typeDef['type'] = $type;
|
|
||||||
} elseif (in_array($type, ['int', 'integer'])) {
|
|
||||||
$typeDef['type'] = 'integer';
|
|
||||||
} elseif (in_array($type, ['double', 'float'])) {
|
|
||||||
$typeDef['type'] = 'number';
|
|
||||||
$typeDef['format'] = $type;
|
|
||||||
} elseif (is_subclass_of($type, \DateTimeInterface::class)) {
|
|
||||||
$typeDef['type'] = 'string';
|
|
||||||
$typeDef['format'] = 'date-time';
|
|
||||||
} else {
|
|
||||||
// we can use property type also for custom handlers, then we don't have here real class name
|
|
||||||
if (!class_exists($type)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$typeDef['$ref'] = $this->modelRegistry->register(
|
|
||||||
new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $type), $groups)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $typeDef;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function registerPropertyType(array $typeDef, $property)
|
|
||||||
{
|
|
||||||
if (isset($typeDef['$ref'])) {
|
|
||||||
$property->setRef($typeDef['$ref']);
|
|
||||||
} else {
|
|
||||||
if (isset($typeDef['type'])) {
|
|
||||||
$property->setType($typeDef['type']);
|
|
||||||
}
|
|
||||||
if (isset($typeDef['format'])) {
|
|
||||||
$property->setFormat($typeDef['format']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function describeItem(array $type, $property, array $groups = null)
|
|
||||||
{
|
{
|
||||||
if (list($nestedType, $isHash) = $this->getNestedTypeInArray($type)) { // @ todo update a bit getNestedTypeInArray and describe ($type = $item->type)
|
if (list($nestedType, $isHash) = $this->getNestedTypeInArray($type)) { // @ todo update a bit getNestedTypeInArray and describe ($type = $item->type)
|
||||||
if ($isHash) {
|
if ($isHash) {
|
||||||
@ -173,6 +126,11 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
// in the case of a virtual property, set it as free object type
|
// in the case of a virtual property, set it as free object type
|
||||||
$property->merge(['additionalProperties' => []]);
|
$property->merge(['additionalProperties' => []]);
|
||||||
|
|
||||||
|
// this is a free form object (as nested array)
|
||||||
|
if ('array' === $nestedType['name'] && !isset($nestedType['params'][0])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->describeItem($nestedType, $property->getAdditionalProperties(), $groups);
|
$this->describeItem($nestedType, $property->getAdditionalProperties(), $groups);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -180,10 +138,28 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
|
|
||||||
$property->setType('array');
|
$property->setType('array');
|
||||||
$this->describeItem($nestedType, $property->getItems(), $groups);
|
$this->describeItem($nestedType, $property->getItems(), $groups);
|
||||||
|
} elseif ('array' === $type['name']) {
|
||||||
|
$property->setType('object');
|
||||||
|
$property->merge(['additionalProperties' => []]);
|
||||||
|
} elseif (in_array($type['name'], ['boolean', 'string'], true)) {
|
||||||
|
$property->setType($type['name']);
|
||||||
|
} elseif (in_array($type['name'], ['int', 'integer'], true)) {
|
||||||
|
$property->setType('integer');
|
||||||
|
} elseif (in_array($type['name'], ['double', 'float'], true)) {
|
||||||
|
$property->setType('number');
|
||||||
|
$property->setFormat($type['name']);
|
||||||
|
} elseif (is_subclass_of($type['name'], \DateTimeInterface::class)) {
|
||||||
|
$property->setType('string');
|
||||||
|
$property->setFormat('date-time');
|
||||||
|
} else {
|
||||||
|
// we can use property type also for custom handlers, then we don't have here real class name
|
||||||
|
if (!class_exists($type['name'])) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($typeDef = $this->findPropertyType($type['name'], $groups)) {
|
$property->setRef($this->modelRegistry->register(
|
||||||
$this->registerPropertyType($typeDef, $property);
|
new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $type['name']), $groups)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,36 @@ class JMSUser
|
|||||||
*/
|
*/
|
||||||
private $latLonHistory;
|
private $latLonHistory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("array<string, array>")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $freeFormObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("array")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $freeFormObjectWithoutType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("array<string, array<string, DateTime>>")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $deepObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("array<string, array<DateTime>>")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $deepObjectWithItems;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("array<array<array<string, array>>>")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $deepFreeFormObjectCollection;
|
||||||
|
|
||||||
public function setRoles($roles)
|
public function setRoles($roles)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,44 @@ class JMSFunctionalTest extends WebTestCase
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'free_form_object_without_type' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'additionalProperties' => true,
|
||||||
|
],
|
||||||
|
'free_form_object' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'additionalProperties' => true,
|
||||||
|
],
|
||||||
|
'deep_object' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'additionalProperties' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'additionalProperties' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'format' => 'date-time',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'deep_object_with_items' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'additionalProperties' => [
|
||||||
|
'type' => 'array',
|
||||||
|
'items' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'format' => 'date-time',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'deep_free_form_object_collection' => [
|
||||||
|
'type' => 'array',
|
||||||
|
'items' => [
|
||||||
|
'type' => 'array',
|
||||||
|
'items' => [
|
||||||
|
'type' => 'object',
|
||||||
|
'additionalProperties' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
], $this->getModel('JMSUser')->toArray());
|
], $this->getModel('JMSUser')->toArray());
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"symfony/framework-bundle": "^3.4|^4.0",
|
"symfony/framework-bundle": "^3.4|^4.0",
|
||||||
"symfony/options-resolver": "^3.4.4|^4.0",
|
"symfony/options-resolver": "^3.4.4|^4.0",
|
||||||
"symfony/property-info": "^3.4|^4.0",
|
"symfony/property-info": "^3.4|^4.0",
|
||||||
"exsyst/swagger": "~0.3|~0.4",
|
"exsyst/swagger": "^0.4.1",
|
||||||
"zircote/swagger-php": "^2.0.9",
|
"zircote/swagger-php": "^2.0.9",
|
||||||
"phpdocumentor/reflection-docblock": "^3.1|^4.0"
|
"phpdocumentor/reflection-docblock": "^3.1|^4.0"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user