diff --git a/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index 6ce8083..c3c33c5 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -33,6 +33,12 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn private $factory; private $namingStrategy; private $doctrineReader; + private $previousGroups = []; + + /** + * @var array + */ + private $propertyTypeUseGroupsCache = []; public function __construct( MetadataFactoryInterface $factory, @@ -70,8 +76,14 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn $name = $this->namingStrategy->translateName($item); $groups = $model->getGroups(); + + $previousGroups = null; if (isset($groups[$name]) && is_array($groups[$name])) { + $previousGroups = $groups; $groups = $model->getGroups()[$name]; + } elseif (!isset($groups[$name]) && !empty($this->previousGroups[spl_object_hash($model)])) { + // $groups = $this->previousGroups[spl_object_hash($model)]; use this for jms/serializer 2.0 + $groups = false === $this->propertyTypeUsesGroups($item->type) ? null : [GroupsExclusionStrategy::DEFAULT_GROUP]; } elseif (is_array($groups)) { $groups = array_filter($groups, 'is_scalar'); } @@ -97,7 +109,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn continue; } - $this->describeItem($item->type, $property, $groups); + $this->describeItem($item->type, $property, $groups, $previousGroups); } } @@ -118,9 +130,11 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn return false; } - private function describeItem(array $type, Schema $property, array $groups = null) + private function describeItem(array $type, $property, array $groups = null, array $previousGroups = null) { - if (list($nestedType, $isHash) = $this->getNestedTypeInArray($type)) { // @ todo update a bit getNestedTypeInArray and describe ($type = $item->type) + $nestedTypeInfo = $this->getNestedTypeInArray($type); + if (null !== $nestedTypeInfo) { + list($nestedType, $isHash) = $nestedTypeInfo; if ($isHash) { $property->setType('object'); // in the case of a virtual property, set it as free object type @@ -131,7 +145,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn return; } - $this->describeItem($nestedType, $property->getAdditionalProperties(), $groups); + $this->describeItem($nestedType, $property->getAdditionalProperties(), $groups, $previousGroups); return; } @@ -160,6 +174,10 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn $property->setRef($this->modelRegistry->register( new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $type['name']), $groups) )); + + if ($previousGroups) { + $this->previousGroups[spl_object_hash($model)] = $previousGroups; + } } } @@ -179,4 +197,35 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn return null; } + + /** + * @param array $type + * + * @return bool|null + */ + private function propertyTypeUsesGroups(array $type) + { + if (!array_key_exists($type['name'], $this->propertyTypeUseGroupsCache)) { + return $this->propertyTypeUseGroupsCache[$type['name']]; + } + + try { + $metadata = $this->factory->getMetadataForClass($type['name']); + + foreach ($metadata->propertyMetadata as $item) { + if (null !== $item->groups && $item->groups != [GroupsExclusionStrategy::DEFAULT_GROUP]) { + $this->propertyTypeUseGroupsCache[$type['name']] = true; + + return true; + } + } + $this->propertyTypeUseGroupsCache[$type['name']] = false; + + return false; + } catch (\ReflectionException $e) { + $this->propertyTypeUseGroupsCache[$type['name']] = null; + + return null; + } + } } diff --git a/Tests/Functional/Controller/JMSController.php b/Tests/Functional/Controller/JMSController.php index 0e361c6..fea410a 100644 --- a/Tests/Functional/Controller/JMSController.php +++ b/Tests/Functional/Controller/JMSController.php @@ -15,6 +15,9 @@ use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSComplex; use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSDualComplex; use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSUser; +use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChat; +use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSChatUser; +use Nelmio\ApiDocBundle\Tests\Functional\Entity\NestedGroup\JMSPicture; use Nelmio\ApiDocBundle\Tests\Functional\Entity\VirtualProperty; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Swagger\Annotations as SWG; @@ -71,4 +74,40 @@ class JMSController public function complexDualAction() { } + + /** + * @Route("/api/jms_chat", methods={"GET"}) + * @SWG\Response( + * response=200, + * description="Success", + * @Model(type=JMSChat::class, groups={"Default", "members" : {"mini"}}) + * ) + */ + public function chatAction() + { + } + + /** + * @Route("/api/jms_picture", methods={"GET"}) + * @SWG\Response( + * response=200, + * description="Success", + * @Model(type=JMSPicture::class, groups={"mini"}) + * ) + */ + public function pictureAction() + { + } + + /** + * @Route("/api/jms_mini_user", methods={"GET"}) + * @SWG\Response( + * response=200, + * description="Success", + * @Model(type=JMSChatUser::class, groups={"mini"}) + * ) + */ + public function minUserAction() + { + } } diff --git a/Tests/Functional/Entity/NestedGroup/JMSChat.php b/Tests/Functional/Entity/NestedGroup/JMSChat.php new file mode 100644 index 0000000..5373464 --- /dev/null +++ b/Tests/Functional/Entity/NestedGroup/JMSChat.php @@ -0,0 +1,34 @@ +") + * @Serializer\Expose + */ + private $members; +} diff --git a/Tests/Functional/Entity/NestedGroup/JMSChatUser.php b/Tests/Functional/Entity/NestedGroup/JMSChatUser.php new file mode 100644 index 0000000..71ea114 --- /dev/null +++ b/Tests/Functional/Entity/NestedGroup/JMSChatUser.php @@ -0,0 +1,41 @@ +") + * @Serializer\Expose + */ + private $allPictures; +} diff --git a/Tests/Functional/Entity/NestedGroup/JMSPicture.php b/Tests/Functional/Entity/NestedGroup/JMSPicture.php new file mode 100644 index 0000000..37650bb --- /dev/null +++ b/Tests/Functional/Entity/NestedGroup/JMSPicture.php @@ -0,0 +1,35 @@ +assertEquals([ + 'type' => 'object', + 'properties' => [ + 'only_direct_picture_mini' => [ + 'type' => 'integer', + ], + ], + ], $this->getModel('JMSPicture')->toArray()); + } + + public function testModeChatDocumentation() + { + $this->assertEquals([ + 'type' => 'object', + 'properties' => [ + 'id' => [ + 'type' => 'integer', + ], + 'members' => [ + 'items' => [ + '$ref' => '#/definitions/JMSChatUser', + ], + 'type' => 'array', + ], + ], + ], $this->getModel('JMSChat')->toArray()); + + $this->assertEquals([ + 'type' => 'object', + 'properties' => [ + 'picture' => [ + '$ref' => '#/definitions/JMSPicture', + ], + ], + ], $this->getModel('JMSChatUser')->toArray()); + } + public function testModelDocumentation() { $this->assertEquals([