Added describer that removes duplicate parameters when using $ref.

This commit is contained in:
cyberemissary 2019-11-05 08:41:32 -05:00
parent 9ab9d6da72
commit 9b9dbe69dd
4 changed files with 149 additions and 0 deletions

View File

@ -0,0 +1,79 @@
<?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\Describer;
use EXSyst\Component\Swagger\Collections\Parameters;
use EXSyst\Component\Swagger\Operation;
use EXSyst\Component\Swagger\Parameter;
use EXSyst\Component\Swagger\Path;
use EXSyst\Component\Swagger\Swagger;
/**
* Merges parameters that have been added as refs through config files with those that get auto generated based on
* routes.
*/
class ParameterRefMergeDescriber implements DescriberInterface
{
/**
* {@inheritdoc}
*/
public function describe(Swagger $api)
{
/** @var Path $path */
foreach ($api->getPaths() as $path) {
/** @var Operation $operation */
foreach ($path->getOperations() as $operation) {
$this->checkOperation($api, $operation);
}
}
}
/**
* This method removes parameters that also have a ref version as they will be duplicated otherwise.
*/
private function checkOperation(Swagger $api, Operation $operation)
{
$parametersToRemove = [];
/** @var Parameter[] $globalParams */
$globalParams = $api->getParameters();
/** @var Parameters|Parameter[] $currentParams */
$currentParams = $operation->getParameters();
foreach ($currentParams as $parameter) {
$ref = $parameter->getRef();
if (null === $ref) {
// we only concern ourselves with '$ref' parameters
continue;
}
$ref = \mb_substr($ref, 13); // trim the '#/parameters/' part of ref
if (!isset($globalParams[$ref])) {
// this really shouldn't happen, if it does there will be other failures elsewhere, so just ignore here
continue;
}
$refParameter = $globalParams[$ref];
// param ids are in form {name}/{in}
$refParameterId = \sprintf('%s/%s', $refParameter->getName(), $refParameter->getIn());
if ($currentParams->has($refParameterId)) {
// if we got here it means a duplicate parameter is directly defined, schedule it for removal
$parametersToRemove[] = $currentParams->get($refParameterId);
}
}
foreach ($parametersToRemove as $parameterToRemove) {
$currentParams->remove($parameterToRemove);
}
}
}

View File

@ -32,6 +32,10 @@
<tag name="nelmio_api_doc.describer" priority="-1000" /> <tag name="nelmio_api_doc.describer" priority="-1000" />
</service> </service>
<service id="nelmio_api_doc.describers.param_ref_merge" class="Nelmio\ApiDocBundle\Describer\ParameterRefMergeDescriber" public="false">
<tag name="nelmio_api_doc.describer" priority="-999" />
</service>
<!-- Routing Describers --> <!-- Routing Describers -->
<service id="nelmio_api_doc.route_describers.route_metadata" class="Nelmio\ApiDocBundle\RouteDescriber\RouteMetadataDescriber" public="false"> <service id="nelmio_api_doc.route_describers.route_metadata" class="Nelmio\ApiDocBundle\RouteDescriber\RouteMetadataDescriber" public="false">
<tag name="nelmio_api_doc.route_describer" priority="-300" /> <tag name="nelmio_api_doc.route_describer" priority="-300" />

View File

@ -12,10 +12,12 @@
namespace Nelmio\ApiDocBundle\Tests\Describer; namespace Nelmio\ApiDocBundle\Tests\Describer;
use EXSyst\Component\Swagger\Swagger; use EXSyst\Component\Swagger\Swagger;
use Nelmio\ApiDocBundle\Describer\DescriberInterface;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
abstract class AbstractDescriberTest extends TestCase abstract class AbstractDescriberTest extends TestCase
{ {
/** @var DescriberInterface */
protected $describer; protected $describer;
protected function getSwaggerDoc(): Swagger protected function getSwaggerDoc(): Swagger

View File

@ -0,0 +1,64 @@
<?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\Describer;
use EXSyst\Component\Swagger\Swagger;
use Nelmio\ApiDocBundle\Describer\ParameterRefMergeDescriber;
class ParameterRefMergeDescriberTest extends AbstractDescriberTest
{
public function testDescribe()
{
// this sample config was taken from a json generated by swagger without ParameterRefMergeDescriber
$apiDef = [
'swagger' => '2.0',
'info' => ['title' => 'Ref Test'],
'paths' => [
'/api/{version}/product' => [
'get' => [
'parameters' => [
[
'$ref' => '#/parameters/versionParam',
],
[
'name' => 'version',
'in' => 'path',
'required' => true,
'type' => 'string',
'pattern' => 'v\\d+',
],
],
],
],
],
'parameters' => [
'versionParam' => [
'name' => 'version',
'in' => 'path',
'required' => true,
'type' => 'string',
],
],
];
$api = new Swagger($apiDef);
$this->describer->describe($api);
$describedData = $api->toArray();
// only one parameter should remain as they were duplicates
$this->assertCount(1, $describedData['paths']['/api/{version}/product']['get']['parameters']);
}
protected function setUp()
{
$this->describer = new ParameterRefMergeDescriber();
}
}