mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-10 03:29:25 +03:00
Merge pull request #1433 from goetas/serializer-v2
Allow jms/serializer v2.0 and willdurand/Hateoas v3.0
This commit is contained in:
commit
78568a3150
@ -23,6 +23,8 @@ matrix:
|
|||||||
include:
|
include:
|
||||||
- php: 7.0
|
- php: 7.0
|
||||||
env: COMPOSER_FLAGS="--prefer-lowest"
|
env: COMPOSER_FLAGS="--prefer-lowest"
|
||||||
|
- php: 7.2
|
||||||
|
env: COMPOSER_FLAGS="--prefer-lowest"
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- phpenv config-rm xdebug.ini
|
- phpenv config-rm xdebug.ini
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Nelmio\ApiDocBundle\DependencyInjection;
|
namespace Nelmio\ApiDocBundle\DependencyInjection;
|
||||||
|
|
||||||
use FOS\RestBundle\Controller\Annotations\ParamInterface;
|
use FOS\RestBundle\Controller\Annotations\ParamInterface;
|
||||||
|
use JMS\Serializer\Visitor\SerializationVisitorInterface;
|
||||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||||
use Nelmio\ApiDocBundle\Describer\ExternalDocDescriber;
|
use Nelmio\ApiDocBundle\Describer\ExternalDocDescriber;
|
||||||
use Nelmio\ApiDocBundle\Describer\RouteDescriber;
|
use Nelmio\ApiDocBundle\Describer\RouteDescriber;
|
||||||
@ -141,11 +142,13 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
|||||||
|
|
||||||
// JMS metadata support
|
// JMS metadata support
|
||||||
if ($config['models']['use_jms']) {
|
if ($config['models']['use_jms']) {
|
||||||
|
$jmsNamingStrategy = interface_exists(SerializationVisitorInterface::class) ? null : new Reference('jms_serializer.naming_strategy');
|
||||||
|
|
||||||
$container->register('nelmio_api_doc.model_describers.jms', JMSModelDescriber::class)
|
$container->register('nelmio_api_doc.model_describers.jms', JMSModelDescriber::class)
|
||||||
->setPublic(false)
|
->setPublic(false)
|
||||||
->setArguments([
|
->setArguments([
|
||||||
new Reference('jms_serializer.metadata_factory'),
|
new Reference('jms_serializer.metadata_factory'),
|
||||||
new Reference('jms_serializer.naming_strategy'),
|
$jmsNamingStrategy,
|
||||||
new Reference('annotation_reader'),
|
new Reference('annotation_reader'),
|
||||||
])
|
])
|
||||||
->addTag('nelmio_api_doc.model_describer', ['priority' => 50]);
|
->addTag('nelmio_api_doc.model_describer', ['priority' => 50]);
|
||||||
|
@ -13,6 +13,7 @@ namespace Nelmio\ApiDocBundle\ModelDescriber;
|
|||||||
|
|
||||||
use Doctrine\Common\Annotations\Reader;
|
use Doctrine\Common\Annotations\Reader;
|
||||||
use EXSyst\Component\Swagger\Schema;
|
use EXSyst\Component\Swagger\Schema;
|
||||||
|
use JMS\Serializer\Annotation\VirtualProperty;
|
||||||
use JMS\Serializer\Exclusion\GroupsExclusionStrategy;
|
use JMS\Serializer\Exclusion\GroupsExclusionStrategy;
|
||||||
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
|
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
|
||||||
use JMS\Serializer\SerializationContext;
|
use JMS\Serializer\SerializationContext;
|
||||||
@ -42,7 +43,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
MetadataFactoryInterface $factory,
|
MetadataFactoryInterface $factory,
|
||||||
PropertyNamingStrategyInterface $namingStrategy,
|
PropertyNamingStrategyInterface $namingStrategy = null,
|
||||||
Reader $reader
|
Reader $reader
|
||||||
) {
|
) {
|
||||||
$this->factory = $factory;
|
$this->factory = $factory;
|
||||||
@ -67,6 +68,8 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
$annotationsReader = new AnnotationsReader($this->doctrineReader, $this->modelRegistry);
|
$annotationsReader = new AnnotationsReader($this->doctrineReader, $this->modelRegistry);
|
||||||
$annotationsReader->updateDefinition(new \ReflectionClass($className), $schema);
|
$annotationsReader->updateDefinition(new \ReflectionClass($className), $schema);
|
||||||
|
|
||||||
|
$isJmsV1 = null !== $this->namingStrategy;
|
||||||
|
|
||||||
$properties = $schema->getProperties();
|
$properties = $schema->getProperties();
|
||||||
foreach ($metadata->propertyMetadata as $item) {
|
foreach ($metadata->propertyMetadata as $item) {
|
||||||
// filter groups
|
// filter groups
|
||||||
@ -81,9 +84,12 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
$previousGroups = $groups;
|
$previousGroups = $groups;
|
||||||
$groups = $groups[$item->name];
|
$groups = $groups[$item->name];
|
||||||
} elseif (!isset($groups[$item->name]) && !empty($this->previousGroups[$model->getHash()])) {
|
} elseif (!isset($groups[$item->name]) && !empty($this->previousGroups[$model->getHash()])) {
|
||||||
// $groups = $this->previousGroups[spl_object_hash($model)]; use this for jms/serializer 2.0
|
$groups = false === $this->propertyTypeUsesGroups($item->type)
|
||||||
$groups = false === $this->propertyTypeUsesGroups($item->type) ? null : [GroupsExclusionStrategy::DEFAULT_GROUP];
|
? null
|
||||||
} elseif (is_array($groups)) {
|
: ($isJmsV1 ? [GroupsExclusionStrategy::DEFAULT_GROUP] : $this->previousGroups[$model->getHash()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($groups)) {
|
||||||
$groups = array_filter($groups, 'is_scalar');
|
$groups = array_filter($groups, 'is_scalar');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +97,20 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
$groups = null;
|
$groups = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$name = $this->namingStrategy->translateName($item);
|
$name = true === $isJmsV1 ? $this->namingStrategy->translateName($item) : $item->serializedName;
|
||||||
// read property options from Swagger Property annotation if it exists
|
// read property options from Swagger Property annotation if it exists
|
||||||
if (null !== $item->reflection) {
|
try {
|
||||||
$property = $properties->get($annotationsReader->getPropertyName($item->reflection, $name));
|
if (true === $isJmsV1 && property_exists($item, 'reflection') && null !== $item->reflection) {
|
||||||
$annotationsReader->updateProperty($item->reflection, $property, $groups);
|
$reflection = $item->reflection;
|
||||||
} else {
|
} elseif ($item instanceof VirtualProperty) {
|
||||||
|
$reflection = new \ReflectionProperty($item->class, $item->name);
|
||||||
|
} else {
|
||||||
|
$reflection = new \ReflectionProperty($item->class, $item->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$property = $properties->get($annotationsReader->getPropertyName($reflection, $name));
|
||||||
|
$annotationsReader->updateProperty($reflection, $property, $groups);
|
||||||
|
} catch (\ReflectionException $e) {
|
||||||
$property = $properties->get($name);
|
$property = $properties->get($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +165,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
$property->setType('array');
|
$property->setType('array');
|
||||||
$this->describeItem($nestedType, $property->getItems(), $groups);
|
$this->describeItem($nestedType, $property->getItems(), $groups, $previousGroups);
|
||||||
} elseif ('array' === $type['name']) {
|
} elseif ('array' === $type['name']) {
|
||||||
$property->setType('object');
|
$property->setType('object');
|
||||||
$property->merge(['additionalProperties' => []]);
|
$property->merge(['additionalProperties' => []]);
|
||||||
|
@ -17,6 +17,7 @@ use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSDualComplex;
|
|||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSNamingStrategyConstraints;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSNamingStrategyConstraints;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSUser;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSUser;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChat;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChat;
|
||||||
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatRoomUser;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatUser;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatUser;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSPicture;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSPicture;
|
||||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\VirtualProperty;
|
use Nelmio\ApiDocBundle\Tests\Functional\Entity\VirtualProperty;
|
||||||
@ -123,4 +124,16 @@ class JMSController
|
|||||||
public function minUserAction()
|
public function minUserAction()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api/jms_mini_user_nested", methods={"GET"})
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Success",
|
||||||
|
* @Model(type=JMSChatRoomUser::class, groups={"mini", "friend": {"living":{"Default"}}})
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function minUserNestedAction()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ use Hateoas\Configuration\Annotation as Hateoas;
|
|||||||
*
|
*
|
||||||
* @Hateoas\Relation(name="example", attributes={"str_att":"bar", "float_att":5.6, "bool_att": false}, href="http://www.example.com")
|
* @Hateoas\Relation(name="example", attributes={"str_att":"bar", "float_att":5.6, "bool_att": false}, href="http://www.example.com")
|
||||||
* @Hateoas\Relation(name="route", href=@Hateoas\Route("foo"))
|
* @Hateoas\Relation(name="route", href=@Hateoas\Route("foo"))
|
||||||
* @Hateoas\Relation(name="route", attributes={"foo":"bar"}, embedded=@Hateoas\Embedded("expr(foo)"))
|
* @Hateoas\Relation(name="route", attributes={"foo":"bar"}, embedded=@Hateoas\Embedded("expr(service('xx'))"))
|
||||||
*/
|
*/
|
||||||
class BazingaUser
|
class BazingaUser
|
||||||
{
|
{
|
||||||
|
42
Tests/Functional/Entity/NestedGroup/JMSChatFriend.php
Normal file
42
Tests/Functional/Entity/NestedGroup/JMSChatFriend.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the NelmioApiDocBundle package.
|
||||||
|
*
|
||||||
|
* (c) Nelmio
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup;
|
||||||
|
|
||||||
|
use JMS\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User.
|
||||||
|
*
|
||||||
|
* @Serializer\ExclusionPolicy("all")
|
||||||
|
*/
|
||||||
|
class JMSChatFriend
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatRoom")
|
||||||
|
* @Serializer\Expose
|
||||||
|
* @Serializer\Groups({"mini"})
|
||||||
|
*/
|
||||||
|
private $room;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatLivingRoom")
|
||||||
|
* @Serializer\Expose
|
||||||
|
* @Serializer\Groups({"Default"})
|
||||||
|
*/
|
||||||
|
private $living;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatRoom")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $dining;
|
||||||
|
}
|
28
Tests/Functional/Entity/NestedGroup/JMSChatLivingRoom.php
Normal file
28
Tests/Functional/Entity/NestedGroup/JMSChatLivingRoom.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the NelmioApiDocBundle package.
|
||||||
|
*
|
||||||
|
* (c) Nelmio
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup;
|
||||||
|
|
||||||
|
use JMS\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User.
|
||||||
|
*
|
||||||
|
* @Serializer\ExclusionPolicy("all")
|
||||||
|
*/
|
||||||
|
class JMSChatLivingRoom
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("integer")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
}
|
42
Tests/Functional/Entity/NestedGroup/JMSChatRoom.php
Normal file
42
Tests/Functional/Entity/NestedGroup/JMSChatRoom.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the NelmioApiDocBundle package.
|
||||||
|
*
|
||||||
|
* (c) Nelmio
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup;
|
||||||
|
|
||||||
|
use JMS\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User.
|
||||||
|
*
|
||||||
|
* @Serializer\ExclusionPolicy("all")
|
||||||
|
*/
|
||||||
|
class JMSChatRoom
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("integer")
|
||||||
|
* @Serializer\Expose
|
||||||
|
* @Serializer\Groups({"Default"})
|
||||||
|
*/
|
||||||
|
private $id1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("integer")
|
||||||
|
* @Serializer\Expose
|
||||||
|
* @Serializer\Groups({"mini"})
|
||||||
|
*/
|
||||||
|
private $id2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("integer")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $id3;
|
||||||
|
}
|
35
Tests/Functional/Entity/NestedGroup/JMSChatRoomUser.php
Normal file
35
Tests/Functional/Entity/NestedGroup/JMSChatRoomUser.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the NelmioApiDocBundle package.
|
||||||
|
*
|
||||||
|
* (c) Nelmio
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup;
|
||||||
|
|
||||||
|
use JMS\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User.
|
||||||
|
*
|
||||||
|
* @Serializer\ExclusionPolicy("all")
|
||||||
|
*/
|
||||||
|
class JMSChatRoomUser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("integer")
|
||||||
|
* @Serializer\Expose
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Serializer\Type("Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatFriend")
|
||||||
|
* @Serializer\Expose
|
||||||
|
* @Serializer\Groups({"mini"})
|
||||||
|
*/
|
||||||
|
private $friend;
|
||||||
|
}
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace Nelmio\ApiDocBundle\Tests\Functional;
|
namespace Nelmio\ApiDocBundle\Tests\Functional;
|
||||||
|
|
||||||
|
use JMS\Serializer\Visitor\SerializationVisitorInterface;
|
||||||
|
|
||||||
class JMSFunctionalTest extends WebTestCase
|
class JMSFunctionalTest extends WebTestCase
|
||||||
{
|
{
|
||||||
public function testModelPictureDocumentation()
|
public function testModelPictureDocumentation()
|
||||||
@ -46,7 +48,7 @@ class JMSFunctionalTest extends WebTestCase
|
|||||||
'type' => 'object',
|
'type' => 'object',
|
||||||
'properties' => [
|
'properties' => [
|
||||||
'picture' => [
|
'picture' => [
|
||||||
'$ref' => '#/definitions/JMSPicture',
|
'$ref' => '#/definitions/JMSPicture2',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
], $this->getModel('JMSChatUser')->toArray());
|
], $this->getModel('JMSChatUser')->toArray());
|
||||||
@ -192,6 +194,59 @@ class JMSFunctionalTest extends WebTestCase
|
|||||||
], $this->getModel('JMSDualComplex')->toArray());
|
], $this->getModel('JMSDualComplex')->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNestedGroupsV1()
|
||||||
|
{
|
||||||
|
if (interface_exists(SerializationVisitorInterface::class)){
|
||||||
|
$this->markTestSkipped('This applies only for jms/serializer v1.x');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'living' => ['$ref' => '#/definitions/JMSChatLivingRoom'],
|
||||||
|
'dining' => ['$ref' => '#/definitions/JMSChatRoom'],
|
||||||
|
],
|
||||||
|
], $this->getModel('JMSChatFriend')->toArray());
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'id1' => ['type' => 'integer'],
|
||||||
|
'id2' => ['type' => 'integer'],
|
||||||
|
'id3' => ['type' => 'integer'],
|
||||||
|
],
|
||||||
|
], $this->getModel('JMSChatRoom')->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNestedGroupsV2()
|
||||||
|
{
|
||||||
|
if (!interface_exists(SerializationVisitorInterface::class)){
|
||||||
|
$this->markTestSkipped('This applies only for jms/serializer v2.x');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'living' => ['$ref' => '#/definitions/JMSChatLivingRoom'],
|
||||||
|
'dining' => ['$ref' => '#/definitions/JMSChatRoom'],
|
||||||
|
],
|
||||||
|
], $this->getModel('JMSChatFriend')->toArray());
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'id2' => ['type' => 'integer'],
|
||||||
|
],
|
||||||
|
], $this->getModel('JMSChatRoom')->toArray());
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'id' => ['type' => 'integer'],
|
||||||
|
],
|
||||||
|
], $this->getModel('JMSChatLivingRoom')->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
public function testModelComplexDocumentation()
|
public function testModelComplexDocumentation()
|
||||||
{
|
{
|
||||||
$this->assertEquals([
|
$this->assertEquals([
|
||||||
|
@ -43,8 +43,8 @@
|
|||||||
|
|
||||||
"api-platform/core": "^2.1.0",
|
"api-platform/core": "^2.1.0",
|
||||||
"friendsofsymfony/rest-bundle": "^2.0",
|
"friendsofsymfony/rest-bundle": "^2.0",
|
||||||
"willdurand/hateoas-bundle": "^1.0",
|
"willdurand/hateoas-bundle": "^1.0|^2.0",
|
||||||
"jms/serializer-bundle": "^2.0"
|
"jms/serializer-bundle": "^2.0|^3.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"api-platform/core": "For using an API oriented framework.",
|
"api-platform/core": "For using an API oriented framework.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user