diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9c319..83192b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,27 @@ CHANGELOG * Add a documentation form extension. Use the ``documentation`` option to define how a form field is documented. * Allow references to config definitions in controllers. +* Using `@Model` implicitely in `@SWG\Schema`, `@SWG\Items` and `@SWG\Property` is deprecated. Use `ref=@Model()` instead. + + Before: + ```php + /** + * This was considered as an array of models. + * + * @SWG\Property(@Model(type=FooClass::class)) + */ + ``` + + After: + ```php + /** + * For an individual object: + * @SWG\Property(ref=@Model(type=FooClass::class)) + * + * For an array: + * @SWG\Property(type="array", @SWG\Items(ref=@Model(type=FooClass::class))) + */ + ``` Config * `nelmio_api_doc.areas` added support to filter by host patterns. diff --git a/Resources/doc/faq.rst b/Resources/doc/faq.rst index ad3c588..b5f5950 100644 --- a/Resources/doc/faq.rst +++ b/Resources/doc/faq.rst @@ -1,56 +1,6 @@ Frequently Asked Questions (FAQ) ================================ -* Q: I use ``@Model`` to document an operation and the bundle understands I want an array of models while I only want one. - - A: You most likely nested ``@Model`` in a ``@Schema`` annotation. The ``@Model`` annotation acts like a ``@Schema`` annotation, so - when nested, the bundle considers that you're documenting an array of models. - - For instance, the following example:: - - /** - * @SWG\Response( -       *   response="200", -       *   description="Success", - * @SWG\Schema(@Model(type=User::class)) - * ) - */ - public function getUserAction() - { - } - - will produce: - - .. code-block:: yaml - - # ... - responses: - 200: - schema: -                   items: { $ref: '#/definitions/User' } - - while you probably expected: - - .. code-block:: yaml - - # ... - responses: - 200: -               schema: { $ref: '#/definitions/User' } - - To obtain the output you expected, remove the ``@Schema`` annotation:: - - /** - * @SWG\Response( - * response="200", - * description="Success", -       *   @Model(type=User::class) - * ) - */ - public function getUserAction() - { - } - * Q: How do I fix 404 or 406 HTTP status on NelmioApiDocBundle assets files (css, js, images)? A: Just execute this command to solve it: diff --git a/Resources/doc/index.rst b/Resources/doc/index.rst index ddc07c0..c7f626c 100644 --- a/Resources/doc/index.rst +++ b/Resources/doc/index.rst @@ -151,7 +151,7 @@ To document your routes, you can use the SwaggerPHP annotations and the * description="Returns the rewards of an user", * @SWG\Schema( * type="array", - * @Model(type=Reward::class, groups={"full"}) + * @SWG\Items(ref=@Model(type=Reward::class, groups={"full"})) * ) * ) * @SWG\Parameter( @@ -175,7 +175,7 @@ Use models ---------- As shown in the example above, the bundle provides the ``@Model`` annotation. -When you use it, the bundle will deduce your model properties. +Use it instead of a definition reference and the bundle will deduce your model properties. .. note:: @@ -201,6 +201,27 @@ This annotation has two options:     * )     */ + .. tip:: + + When used at the root of ``@SWG\Response`` and ``@SWG\Parameter``, ``@Model`` is automatically nested + in a ``@SWG\Schema``. + + To use ``@Model`` directly within a ``@SWG\Schema``, ``@SWG\Items`` or ``@SWG\Property``, you have to use the ``$ref`` field:: + + /** + * @SWG\Response( + * @SWG\Schema(ref=@Model(type=User::class)) + * ) + * + * or + * + * @SWG\Response( + * @SWG\Schema(type="object", + * @SWG\Property(property="foo", ref=@Model(FooClass::class)) + * ) + * ) + */ + Symfony Form types ~~~~~~~~~~~~~~~~~~ diff --git a/SwaggerPhp/ModelRegister.php b/SwaggerPhp/ModelRegister.php index 0988910..71f62f1 100644 --- a/SwaggerPhp/ModelRegister.php +++ b/SwaggerPhp/ModelRegister.php @@ -15,7 +15,6 @@ use Nelmio\ApiDocBundle\Annotation\Model as ModelAnnotation; use Nelmio\ApiDocBundle\Model\Model; use Nelmio\ApiDocBundle\Model\ModelRegistry; use Swagger\Analysis; -use Swagger\Annotations\Definition; use Swagger\Annotations\Items; use Swagger\Annotations\Parameter; use Swagger\Annotations\Response; @@ -40,6 +39,25 @@ final class ModelRegister { $modelsRegistered = []; foreach ($analysis->annotations as $annotation) { + // @Model using the ref field + if ($annotation instanceof Schema && $annotation->ref instanceof ModelAnnotation) { + $model = $annotation->ref; + + $annotation->ref = $this->modelRegistry->register(new Model($this->createType($model->type), $model->groups)); + + foreach ($annotation->_unmerged as $key => $unmerged) { + if ($unmerged === $model) { + unset($annotation->_unmerged[$key]); + + break; + } + } + $analysis->annotations->detach($model); + + continue; + } + + // Implicit usages if ($annotation instanceof Response) { $annotationClass = Schema::class; } elseif ($annotation instanceof Parameter) { @@ -72,12 +90,12 @@ final class ModelRegister continue; } - $ref = $this->modelRegistry->register(new Model($this->createType($model->type), $model->groups)); - $parts = explode('/', $ref); - $modelsRegistered[end($parts)] = true; + if ($annotation instanceof Schema) { + @trigger_error(sprintf('Using `@Model` implicitely in a `@SWG\Schema`, `@SWG\Items` or `@SWG\Property` annotation in %s is deprecated since version 3.2 and won\'t be supported in 4.0. Use `ref=@Model()` instead.', $annotation->_context->getDebugLocation()), E_USER_DEPRECATED); + } $annotation->merge([new $annotationClass([ - 'ref' => $ref, + 'ref' => $this->modelRegistry->register(new Model($this->createType($model->type), $model->groups)), ])]); // It is no longer an unmerged annotation @@ -90,10 +108,6 @@ final class ModelRegister } $analysis->annotations->detach($model); } - - foreach ($modelsRegistered as $model => $v) { - $analysis->annotations->attach(new Definition(['definition' => $model])); - } } private function createType(string $type): Type diff --git a/Tests/Functional/Controller/ApiController.php b/Tests/Functional/Controller/ApiController.php index 2b8a55f..60fa8cc 100644 --- a/Tests/Functional/Controller/ApiController.php +++ b/Tests/Functional/Controller/ApiController.php @@ -33,7 +33,7 @@ class ApiController * @SWG\Response( * response="200", * description="Success", - * @Model(type=Article::class, groups={"light"}) + * @SWG\Schema(ref=@Model(type=Article::class, groups={"light"})) * ) * @Route("/article/{id}", methods={"GET"}) */ @@ -65,7 +65,7 @@ class ApiController * description="This is a parameter", * @SWG\Schema( * type="array", - * @Model(type=User::class) + * @SWG\Items(ref=@Model(type=User::class)) * ) * ) * @SWG\Tag(name="implicit") @@ -85,10 +85,7 @@ class ApiController * name="foo", * in="body", * description="This is a parameter", - * @SWG\Schema( - * type="array", - * @Model(type=UserType::class) - * ) + * @SWG\Schema(ref=@Model(type=UserType::class)) * ) */ public function submitUserTypeAction() @@ -152,7 +149,7 @@ class ApiController * name="form", * in="body", * description="Request content", - * @Model(type=DummyType::class) + * @SWG\Schema(ref=@Model(type=DummyType::class)) * ) * @SWG\Response(response="201", description="") */ @@ -175,7 +172,7 @@ class ApiController * @SWG\Response( * response="201", * description="Used for symfony constraints test", - * @Model(type=SymfonyConstraints::class) + * @SWG\Schema(ref=@Model(type=SymfonyConstraints::class)) * ) */ public function symfonyConstraintsAction() diff --git a/Tests/Swagger/ModelRegisterTest.php b/Tests/Swagger/ModelRegisterTest.php new file mode 100644 index 0000000..42b476d --- /dev/null +++ b/Tests/Swagger/ModelRegisterTest.php @@ -0,0 +1,67 @@ +__invoke(new Analysis([$annotation = $annotationsReader->getPropertyAnnotation( + new \ReflectionProperty(Foo::class, 'bar'), + SWG\Property::class + )])); + + $this->assertEquals(['items' => ['$ref' => '#/definitions/Foo']], json_decode(json_encode($annotation), true)); + } +} + +class Foo +{ + /** + * @SWG\Property(@ModelAnnotation(type=Foo::class)) + */ + private $bar; +} + +class NullModelDescriber implements ModelDescriberInterface +{ + public function describe(Model $model, Schema $schema) + { + } + + public function supports(Model $model): bool + { + return true; + } +} diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index ad5cb43..8cf6854 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -140,7 +140,7 @@ class SwaggerDocblockConvertCommand extends ContainerAwareCommand if (200 === $code && isset($responseMap[$code]['class'])) { $model = $responseMap[$code]['class']; $annotation .= ", - * @Model(type=\"$model\")"; + * @SWG\\Schema(ref=@Model(type=\"$model\"))"; } $annotation .= ' * )'; diff --git a/composer.json b/composer.json index 9f063c3..ed3cbdc 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "3.2.x-dev" } } }