Support @Model through ref

This commit is contained in:
Guilhem Niot 2018-03-17 14:36:57 +01:00
parent 3698daa547
commit 9bf00b5196
6 changed files with 73 additions and 70 deletions

View File

@ -6,6 +6,27 @@ CHANGELOG
* Add a documentation form extension. Use the ``documentation`` option to define how a form field is documented. * Add a documentation form extension. Use the ``documentation`` option to define how a form field is documented.
* Allow references to config definitions in controllers. * 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 Config
* `nelmio_api_doc.areas` added support to filter by host patterns. * `nelmio_api_doc.areas` added support to filter by host patterns.

View File

@ -1,56 +1,6 @@
Frequently Asked Questions (FAQ) 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)? * 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: A: Just execute this command to solve it:

View File

@ -140,7 +140,7 @@ To document your routes, you can use the SwaggerPHP annotations and the
* description="Returns the rewards of an user", * description="Returns the rewards of an user",
* @SWG\Schema( * @SWG\Schema(
* type="array", * type="array",
* @Model(type=Reward::class, groups={"full"}) * @SWG\Items(ref=@Model(type=Reward::class, groups={"full"}))
* ) * )
* ) * )
* @SWG\Parameter( * @SWG\Parameter(
@ -163,7 +163,7 @@ Use models
---------- ----------
As shown in the example above, the bundle provides the ``@Model`` annotation. 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:: .. note::
@ -189,6 +189,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 Symfony Form types
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~

View File

@ -15,7 +15,6 @@ use Nelmio\ApiDocBundle\Annotation\Model as ModelAnnotation;
use Nelmio\ApiDocBundle\Model\Model; use Nelmio\ApiDocBundle\Model\Model;
use Nelmio\ApiDocBundle\Model\ModelRegistry; use Nelmio\ApiDocBundle\Model\ModelRegistry;
use Swagger\Analysis; use Swagger\Analysis;
use Swagger\Annotations\Definition;
use Swagger\Annotations\Items; use Swagger\Annotations\Items;
use Swagger\Annotations\Parameter; use Swagger\Annotations\Parameter;
use Swagger\Annotations\Response; use Swagger\Annotations\Response;
@ -40,6 +39,25 @@ final class ModelRegister
{ {
$modelsRegistered = []; $modelsRegistered = [];
foreach ($analysis->annotations as $annotation) { 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) { if ($annotation instanceof Response) {
$annotationClass = Schema::class; $annotationClass = Schema::class;
} elseif ($annotation instanceof Parameter) { } elseif ($annotation instanceof Parameter) {
@ -72,12 +90,12 @@ final class ModelRegister
continue; continue;
} }
$ref = $this->modelRegistry->register(new Model($this->createType($model->type), $model->groups)); if ($annotation instanceof Schema) {
$parts = explode('/', $ref); @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);
$modelsRegistered[end($parts)] = true; }
$annotation->merge([new $annotationClass([ $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 // It is no longer an unmerged annotation
@ -90,10 +108,6 @@ final class ModelRegister
} }
$analysis->annotations->detach($model); $analysis->annotations->detach($model);
} }
foreach ($modelsRegistered as $model => $v) {
$analysis->annotations->attach(new Definition(['definition' => $model]));
}
} }
private function createType(string $type): Type private function createType(string $type): Type

View File

@ -33,7 +33,7 @@ class ApiController
* @SWG\Response( * @SWG\Response(
* response="200", * response="200",
* description="Success", * description="Success",
* @Model(type=Article::class, groups={"light"}) * @SWG\Schema(ref=@Model(type=Article::class, groups={"light"}))
* ) * )
* @Route("/article/{id}", methods={"GET"}) * @Route("/article/{id}", methods={"GET"})
*/ */
@ -65,7 +65,7 @@ class ApiController
* description="This is a parameter", * description="This is a parameter",
* @SWG\Schema( * @SWG\Schema(
* type="array", * type="array",
* @Model(type=User::class) * @SWG\Items(ref=@Model(type=User::class))
* ) * )
* ) * )
* @SWG\Tag(name="implicit") * @SWG\Tag(name="implicit")
@ -85,10 +85,7 @@ class ApiController
* name="foo", * name="foo",
* in="body", * in="body",
* description="This is a parameter", * description="This is a parameter",
* @SWG\Schema( * @SWG\Schema(ref=@Model(type=UserType::class))
* type="array",
* @Model(type=UserType::class)
* )
* ) * )
*/ */
public function submitUserTypeAction() public function submitUserTypeAction()
@ -152,7 +149,7 @@ class ApiController
* name="form", * name="form",
* in="body", * in="body",
* description="Request content", * description="Request content",
* @Model(type=DummyType::class) * @SWG\Schema(ref=@Model(type=DummyType::class))
* ) * )
* @SWG\Response(response="201", description="") * @SWG\Response(response="201", description="")
*/ */
@ -175,7 +172,7 @@ class ApiController
* @SWG\Response( * @SWG\Response(
* response="201", * response="201",
* description="Used for symfony constraints test", * description="Used for symfony constraints test",
* @Model(type=SymfonyConstraints::class) * @SWG\Schema(ref=@Model(type=SymfonyConstraints::class))
* ) * )
*/ */
public function symfonyConstraintsAction() public function symfonyConstraintsAction()

View File

@ -140,7 +140,7 @@ class SwaggerDocblockConvertCommand extends ContainerAwareCommand
if (200 === $code && isset($responseMap[$code]['class'])) { if (200 === $code && isset($responseMap[$code]['class'])) {
$model = $responseMap[$code]['class']; $model = $responseMap[$code]['class'];
$annotation .= ", $annotation .= ",
* @Model(type=\"$model\")"; * @SWG\\Schema(ref=@Model(type=\"$model\"))";
} }
$annotation .= ' $annotation .= '
* )'; * )';