mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Merge pull request #1261 from nelmio/model
Support @Model through `ref`
This commit is contained in:
commit
61cda0161c
21
CHANGELOG.md
21
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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
67
Tests/Swagger/ModelRegisterTest.php
Normal file
67
Tests/Swagger/ModelRegisterTest.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?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\Swagger;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use EXSyst\Component\Swagger\Schema;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model as ModelAnnotation;
|
||||
use Nelmio\ApiDocBundle\Model\Model;
|
||||
use Nelmio\ApiDocBundle\Model\ModelRegistry;
|
||||
use Nelmio\ApiDocBundle\ModelDescriber\ModelDescriberInterface;
|
||||
use Nelmio\ApiDocBundle\SwaggerPhp\ModelRegister;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Swagger\Analysis;
|
||||
use Swagger\Annotations as SWG;
|
||||
|
||||
class ModelRegisterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Using `@Model` implicitely in a `@SWG\Schema`, `@SWG\Items` or `@SWG\Property` annotation in %s. Use `ref=@Model()` instead.
|
||||
*/
|
||||
public function testDeprecatedImplicitUseOfModel()
|
||||
{
|
||||
$api = new Swagger();
|
||||
$registry = new ModelRegistry([new NullModelDescriber()], $api);
|
||||
$modelRegister = new ModelRegister($registry);
|
||||
|
||||
$annotationsReader = new AnnotationReader();
|
||||
|
||||
$modelRegister->__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;
|
||||
}
|
||||
}
|
@ -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 .= '
|
||||
* )';
|
||||
|
@ -56,7 +56,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1.x-dev"
|
||||
"dev-master": "3.2.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user