Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix-2224: fix vendor extension being ignored #2230

Merged
merged 11 commits into from
Mar 6, 2024
12 changes: 12 additions & 0 deletions src/OpenApiPhp/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -421,9 +421,21 @@ private static function mergeFromArray(OA\AbstractAnnotation $annotation, array
}

foreach ($properties as $propertyName => $value) {
if (str_starts_with($propertyName, 'x-')) {
$propertyName = substr($propertyName, 2);

if (Generator::isDefault($annotation->x)) {
$annotation->x = [];
}

$annotation->x = [$propertyName => $value] + ($annotation->x ?: []);
continue;
}

if ('$ref' === $propertyName) {
$propertyName = 'ref';
}

if (array_key_exists($propertyName, $defaults) && !\in_array($propertyName, $done, true)) {
self::mergeProperty($annotation, $propertyName, $value, $defaults[$propertyName], $overwrite);
}
Expand Down
14 changes: 14 additions & 0 deletions tests/Functional/Configs/VendorExtension.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
nelmio_api_doc:
documentation:
info:
title: 'Test API'
description: 'Test API description'
x-vendor:
test: 'Test vendor extension'
x-build: '#SomeCommitHash'
components:
schemas:
Test:
type: string
x-vendor:
test: 'Test vendor extension inside schema'
4 changes: 2 additions & 2 deletions tests/Functional/Controller/TestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@

namespace Nelmio\ApiDocBundle\Tests\Functional\Controller;

use Nelmio\ApiDocBundle\Tests\Functional\TestKernel;
use OpenApi\Annotations as OA;
use OpenApi\Attributes as OAT;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\Annotation\Route;

if (Kernel::MAJOR_VERSION < 7) {
if (TestKernel::isAnnotationsAvailable()) {
/**
* @Route("/test", host="api-test.example.com")
*/
Expand Down
32 changes: 11 additions & 21 deletions tests/Functional/ControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ final class ControllerTest extends WebTestCase
*/
private $configurableContainerFactory;

/**
* @var string[]
*/
private static $usedFixtures = [];

protected function setUp(): void
{
$this->configurableContainerFactory = new ConfigurableContainerFactory();
Expand All @@ -51,11 +46,15 @@ protected function getOpenApiDefinition($area = 'default'): OA\OpenApi
/**
* @dataProvider provideControllers
*/
public function testControllers(string $controllerName, ?string $fixtureName = null, array $extraConfigs = []): void
public function testControllers(?string $controllerName, ?string $fixtureName = null, array $extraConfigs = []): void
{
$fixtureName = $fixtureName ?? $controllerName;
$fixtureName = $fixtureName ?? $controllerName ?? $this->fail('A fixture name must be provided.');

$routingConfiguration = function (RoutingConfigurator $routes) use ($controllerName) {
if (null === $controllerName) {
return;
}

$routes->withPath('/')->import(__DIR__."/Controller/$controllerName.php", 'attribute');
};

Expand All @@ -68,8 +67,6 @@ public function testControllers(string $controllerName, ?string $fixtureName = n
file_put_contents($fixtureDir, $apiDefinition->toJson());
}

static::$usedFixtures[] = $fixtureName.'.json';

self::assertSame(
self::getFixture($fixtureDir),
$this->getOpenApiDefinition()->toJson()
Expand All @@ -87,19 +84,12 @@ public static function provideControllers(): iterable
[__DIR__.'/Configs/CleanUnusedComponentsProcessor.yaml'],
];
}
}

/**
* @depends testControllers
*/
public function testUnusedFixtures(): void
{
$fixtures = glob(__DIR__.'/Fixtures/*.json');
$fixtures = array_map('basename', $fixtures);

$diff = array_diff($fixtures, static::$usedFixtures);

self::assertEmpty($diff, sprintf('The following fixtures are not used: %s', implode(', ', $diff)));
yield 'https://github.com/nelmio/NelmioApiDocBundle/issues/2224' => [
null,
'VendorExtension',
[__DIR__.'/Configs/VendorExtension.yaml'],
];
}

private static function getFixture(string $fixture): string
Expand Down
23 changes: 23 additions & 0 deletions tests/Functional/Fixtures/VendorExtension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"openapi": "3.0.0",
"info": {
"title": "Test API",
"description": "Test API description",
"version": "0.0.0",
"x-build": "#SomeCommitHash",
"x-vendor": {
"test": "Test vendor extension"
}
},
"paths": {},
"components": {
"schemas": {
"Test": {
"type": "string",
"x-vendor": {
"test": "Test vendor extension inside schema"
}
}
}
}
}
1 change: 1 addition & 0 deletions tests/Functional/FunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ protected function setUp(): void
public function testConfiguredDocumentation()
{
$this->assertEquals('My Default App', $this->getOpenApiDefinition()->info->title);
$this->assertEquals(['buildHash' => 'ab1234567890'], $this->getOpenApiDefinition()->info->x);
$this->assertEquals('My Test App', $this->getOpenApiDefinition('test')->info->title);
}

Expand Down
5 changes: 3 additions & 2 deletions tests/Functional/TestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load
'exception_controller' => null,
]);

if (self::isAnnotationsAvailable()) {
if (class_exists(SensioFrameworkExtraBundle::class)) {
$c->loadFromExtension('sensio_framework_extra', [
'router' => [
'annotations' => false,
Expand All @@ -173,7 +173,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load
]],
]);

if (self::isAnnotationsAvailable()) {
if (class_exists(FOSRestBundle::class)) {
$c->loadFromExtension('fos_rest', [
'format_listener' => [
'rules' => [
Expand Down Expand Up @@ -268,6 +268,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load
'documentation' => [
'info' => [
'title' => 'My Default App',
'x-buildHash' => 'ab1234567890',
],
'paths' => [
// Ensures we can define routes in Yaml without defining OperationIds
Expand Down