133 lines
4.2 KiB
PHP
133 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber;
|
|
|
|
use Nelmio\ApiDocBundle\OpenApiPhp\Util;
|
|
use OpenApi\Annotations as OA;
|
|
use OpenApi\Generator;
|
|
use OpenApi\Processors\Concerns\TypesTrait;
|
|
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
|
|
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
|
|
|
final class SymfonyMapQueryParameterDescriber implements RouteArgumentDescriberInterface
|
|
{
|
|
use TypesTrait;
|
|
|
|
public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void
|
|
{
|
|
/** @var MapQueryParameter $attribute */
|
|
if (!$attribute = $argumentMetadata->getAttributes(MapQueryParameter::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) {
|
|
return;
|
|
}
|
|
|
|
$name = $attribute->name ?? $argumentMetadata->getName();
|
|
$name = 'array' === $argumentMetadata->getType()
|
|
? $name.'[]'
|
|
: $name;
|
|
|
|
$operationParameter = Util::getOperationParameter($operation, $name, 'query');
|
|
|
|
Util::modifyAnnotationValue($operationParameter, 'required', !($argumentMetadata->hasDefaultValue() || $argumentMetadata->isNullable()));
|
|
|
|
/** @var OA\Schema $schema */
|
|
$schema = Util::getChild($operationParameter, OA\Schema::class);
|
|
|
|
if ($argumentMetadata->hasDefaultValue()) {
|
|
Util::modifyAnnotationValue($schema, 'default', $argumentMetadata->getDefaultValue());
|
|
}
|
|
|
|
if (Generator::UNDEFINED === $schema->nullable && $argumentMetadata->isNullable()) {
|
|
Util::modifyAnnotationValue($schema, 'nullable', true);
|
|
}
|
|
|
|
$defaultFilter = match ($argumentMetadata->getType()) {
|
|
'array' => null,
|
|
'string' => \FILTER_DEFAULT,
|
|
'int' => \FILTER_VALIDATE_INT,
|
|
'float' => \FILTER_VALIDATE_FLOAT,
|
|
'bool' => \FILTER_VALIDATE_BOOL,
|
|
default => null,
|
|
};
|
|
|
|
$properties = $this->describeValidateFilter($attribute->filter ?? $defaultFilter, $attribute->flags, $attribute->options);
|
|
|
|
if ('array' === $argumentMetadata->getType()) {
|
|
$schema->type = 'array';
|
|
Util::getChild($schema, OA\Items::class, $properties);
|
|
} else {
|
|
foreach ($properties as $key => $value) {
|
|
Util::modifyAnnotationValue($schema, $key, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @see https://www.php.net/manual/en/filter.filters.validate.php
|
|
*/
|
|
private function describeValidateFilter(?int $filter, int $flags, array $options): array
|
|
{
|
|
if (null === $filter) {
|
|
return [];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_BOOLEAN === $filter) {
|
|
return ['type' => 'boolean'];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_DOMAIN === $filter) {
|
|
return ['type' => 'string', 'format' => 'hostname'];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_EMAIL === $filter) {
|
|
return ['type' => 'string', 'format' => 'email'];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_FLOAT === $filter) {
|
|
return ['type' => 'number', 'format' => 'float'];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_INT === $filter) {
|
|
$props = [];
|
|
if ($options['min_range'] ?? false) {
|
|
$props['minimum'] = $options['min_range'];
|
|
}
|
|
|
|
if ($options['max_range'] ?? false) {
|
|
$props['maximum'] = $options['max_range'];
|
|
}
|
|
|
|
return ['type' => 'integer', ...$props];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_IP === $filter) {
|
|
$format = match ($flags) {
|
|
FILTER_FLAG_IPV4 => 'ipv4',
|
|
FILTER_FLAG_IPV6 => 'ipv6',
|
|
default => 'ip',
|
|
};
|
|
|
|
return ['type' => 'string', 'format' => $format];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_MAC === $filter) {
|
|
return ['type' => 'string', 'format' => 'mac'];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_REGEXP === $filter) {
|
|
return ['type' => 'string', 'pattern' => $options['regexp']];
|
|
}
|
|
|
|
if (FILTER_VALIDATE_URL === $filter) {
|
|
return ['type' => 'string', 'format' => 'uri'];
|
|
}
|
|
|
|
if (FILTER_DEFAULT === $filter) {
|
|
return ['type' => 'string'];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
}
|