Skip to content

Commit

Permalink
feat(2056): support opt out of JMS serializer usage (#2342)
Browse files Browse the repository at this point in the history
| Q | A |

|---------------|---------------------------------------------------------------------------------------------------------------------------|
| Bug fix? | no |
| New feature? | yes <!-- please update src/**/CHANGELOG.md files --> |
| Deprecations? | no <!-- please update UPGRADE-*.md and
src/**/CHANGELOG.md files --> |
| Issues | Fix #2056 #2341 <!-- prefix each issue number with "Fix #",
no need to create an issue if none exists, explain below instead --> |

<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the
documentation.

Additionally:
 - Always add tests and ensure they pass.
- For new features, provide some code snippets to help understand usage.
-->
Always registers `JMSModelDescriber` when the bundle is active,
independently of the configured global `models.use_jms` option.
If `models.use_jms` is set, then `JMSModelDescriber` will be added with
a priority of 50, just as before. If `models.use_jms` is not set, it
will be added with -50 so that `ObjectModelDescriber` is used instead.
This should not lead to any behavior change.

Adds support to `options.useJms` in the model by early exiting in either
`JMSModelDescriber` or `ObjectModelDescriber` when it is either
explicitly `false` or `true`. Together with the priorities of the
describer this allows to have either JMS or Symfony serializer as
default and switch per model if necessary.

In #2341 I played
around with this in an app and it worked as expected.

(sorry btw, I'm a fan of rebase + force-push and realized too late that
mentioning the issue in the first commit is a bad idea then because
GitHub spams whenever I push..)

Closes #2056
Closes #2341

---------

Co-authored-by: djordy <[email protected]>
  • Loading branch information
herndlm and DjordyKoert authored Sep 24, 2024
1 parent 5eda246 commit 322c47b
Show file tree
Hide file tree
Showing 7 changed files with 341 additions and 2 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# CHANGELOG

## 4.31.0

* Added support to opt out of JMS serializer usage per endpoint by setting `useJms` in the serializationContext.
```php
#[OA\Response(response: 200, content: new Model(type: UserDto::class, serializationContext: ["useJms" => false]))]
```

## 4.30.0
* Create top level OpenApi Tag from Tags top level annotations/attributes

Expand Down
12 changes: 12 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,18 @@ General PHP objects
nelmio_api_doc:
models: { use_jms: false }
Alternatively, it is also possible to opt out of JMS serializer usage per endpoint by setting `useJms` in the serializationContext:

.. configuration-block::

.. code-block:: php-annotations
/** @OA\Response(response=200, @Model(type=UserDto::class, serializationContext={"useJms"=false})) */
.. code-block:: php-attributes
#[OA\Response(response: 200, content: new Model(type: UserDto::class, serializationContext: ["useJms" => false]))]
When using the JMS serializer combined with `willdurand/Hateoas`_ (and the `BazingaHateoasBundle`_),
HATEOAS metadata are automatically extracted

Expand Down
4 changes: 4 additions & 0 deletions src/ModelDescriber/JMSModelDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ private function computeGroups(Context $context, ?array $type = null): ?array

public function supports(Model $model): bool
{
if (($model->getSerializationContext()['useJms'] ?? null) === false) {
return false;
}

$className = $model->getType()->getClassName();

try {
Expand Down
3 changes: 3 additions & 0 deletions tests/Functional/Configs/JMS.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
nelmio_api_doc:
models:
use_jms: true
41 changes: 41 additions & 0 deletions tests/Functional/Controller/JmsOptOutController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?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\Controller;

use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSUser;
use OpenApi\Attributes as OA;
use Symfony\Component\Routing\Annotation\Route;

#[Route(host: 'api.example.com')]
final class JmsOptOutController
{
#[Route('/api/jms', methods: ['GET'])]
#[OA\Response(
response: 200,
description: 'Success',
content: new Model(type: JMSUser::class)
)]
public function jms()
{
}

#[Route('/api/jms_opt_out', methods: ['GET'])]
#[OA\Response(
response: 200,
description: 'Success',
content: new Model(type: JMSUser::class, serializationContext: ['useJms' => false])
)]
public function jmsOptOut()
{
}
}
21 changes: 19 additions & 2 deletions tests/Functional/ControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

namespace Nelmio\ApiDocBundle\Tests\Functional;

use JMS\SerializerBundle\JMSSerializerBundle;
use OpenApi\Annotations as OA;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;

Expand Down Expand Up @@ -42,9 +44,10 @@ protected function getOpenApiDefinition(string $area = 'default'): OA\OpenApi
* @dataProvider provideUniversalTestCases
*
* @param array{name: string, type: string}|null $controller
* @param Bundle[] $extraBundles
* @param string[] $extraConfigs
*/
public function testControllers(?array $controller, ?string $fixtureName = null, array $extraConfigs = []): void
public function testControllers(?array $controller, ?string $fixtureName = null, array $extraBundles = [], array $extraConfigs = []): void
{
$controllerName = $controller['name'] ?? null;
$controllerType = $controller['type'] ?? null;
Expand All @@ -59,7 +62,7 @@ public function testControllers(?array $controller, ?string $fixtureName = null,
$routes->withPath('/')->import(__DIR__."/Controller/$controllerName.php", $controllerType);
};

$this->configurableContainerFactory->create([], $routingConfiguration, $extraConfigs);
$this->configurableContainerFactory->create($extraBundles, $routingConfiguration, $extraConfigs);

$apiDefinition = $this->getOpenApiDefinition();

Expand Down Expand Up @@ -88,9 +91,20 @@ public static function provideAttributeTestCases(): \Generator
'type' => $type,
],
'PromotedPropertiesDefaults',
[],
[__DIR__.'/Configs/AlternativeNamesPHP81Entities.yaml'],
];

yield 'JMS model opt out' => [
[
'name' => 'JmsOptOutController',
'type' => $type,
],
'JmsOptOutController',
[new JMSSerializerBundle()],
[__DIR__.'/Configs/JMS.yaml'],
];

if (version_compare(Kernel::VERSION, '6.3.0', '>=')) {
yield 'https://github.com/nelmio/NelmioApiDocBundle/issues/2209' => [
[
Expand All @@ -110,6 +124,7 @@ public static function provideAttributeTestCases(): \Generator
'type' => $type,
],
'MapQueryStringCleanupComponents',
[],
[__DIR__.'/Configs/CleanUnusedComponentsProcessor.yaml'],
];

Expand Down Expand Up @@ -165,6 +180,7 @@ public static function provideAnnotationTestCases(): \Generator
'type' => 'annotation',
],
'PromotedPropertiesDefaults',
[],
[__DIR__.'/Configs/AlternativeNamesPHP80Entities.yaml'],
];
}
Expand All @@ -178,6 +194,7 @@ public static function provideUniversalTestCases(): \Generator
yield 'https://github.com/nelmio/NelmioApiDocBundle/issues/2224' => [
null,
'VendorExtension',
[],
[__DIR__.'/Configs/VendorExtension.yaml'],
];
}
Expand Down
Loading

0 comments on commit 322c47b

Please sign in to comment.