welcome back to dyb-tech
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber;
|
||||
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
|
||||
interface RouteArgumentDescriberInterface
|
||||
{
|
||||
public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void;
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
<?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 [];
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber;
|
||||
|
||||
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface;
|
||||
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait;
|
||||
use Nelmio\ApiDocBundle\Model\Model;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapQueryString;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
|
||||
final class SymfonyMapQueryStringDescriber implements RouteArgumentDescriberInterface, ModelRegistryAwareInterface
|
||||
{
|
||||
public const CONTEXT_KEY = 'nelmio_api_doc_bundle.map_query_string.'.self::class;
|
||||
public const CONTEXT_ARGUMENT_METADATA = 'nelmio_api_doc_bundle.argument_metadata.'.self::class;
|
||||
public const CONTEXT_MODEL_REF = 'nelmio_api_doc_bundle.model_ref.'.self::class;
|
||||
|
||||
use ModelRegistryAwareTrait;
|
||||
|
||||
public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void
|
||||
{
|
||||
/** @var MapQueryString $attribute */
|
||||
if (!$attribute = $argumentMetadata->getAttributes(MapQueryString::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$modelRef = $this->modelRegistry->register(new Model(
|
||||
new Type(Type::BUILTIN_TYPE_OBJECT, $argumentMetadata->isNullable(), $argumentMetadata->getType()),
|
||||
groups: $this->getGroups($attribute),
|
||||
serializationContext: $attribute->serializationContext,
|
||||
));
|
||||
|
||||
if (!isset($operation->_context->{self::CONTEXT_KEY})) {
|
||||
$operation->_context->{self::CONTEXT_KEY} = [];
|
||||
}
|
||||
|
||||
$data = [
|
||||
self::CONTEXT_ARGUMENT_METADATA => $argumentMetadata,
|
||||
self::CONTEXT_MODEL_REF => $modelRef,
|
||||
];
|
||||
|
||||
$operation->_context->{self::CONTEXT_KEY}[] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]|null
|
||||
*/
|
||||
private function getGroups(MapQueryString $attribute): ?array
|
||||
{
|
||||
if (null === $attribute->validationGroups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($attribute->validationGroups)) {
|
||||
return [$attribute->validationGroups];
|
||||
}
|
||||
|
||||
if (is_array($attribute->validationGroups)) {
|
||||
return $attribute->validationGroups;
|
||||
}
|
||||
|
||||
if ($attribute->validationGroups instanceof GroupSequence) {
|
||||
return $attribute->validationGroups->groups;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nelmio\ApiDocBundle\RouteDescriber\RouteArgumentDescriber;
|
||||
|
||||
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface;
|
||||
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait;
|
||||
use Nelmio\ApiDocBundle\Model\Model;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
|
||||
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
|
||||
final class SymfonyMapRequestPayloadDescriber implements RouteArgumentDescriberInterface, ModelRegistryAwareInterface
|
||||
{
|
||||
public const CONTEXT_ARGUMENT_METADATA = 'nelmio_api_doc_bundle.argument_metadata.'.self::class;
|
||||
public const CONTEXT_MODEL_REF = 'nelmio_api_doc_bundle.model_ref.'.self::class;
|
||||
|
||||
use ModelRegistryAwareTrait;
|
||||
|
||||
public function describe(ArgumentMetadata $argumentMetadata, OA\Operation $operation): void
|
||||
{
|
||||
/** @var MapRequestPayload $attribute */
|
||||
if (!$attribute = $argumentMetadata->getAttributes(MapRequestPayload::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$modelRef = $this->modelRegistry->register(new Model(
|
||||
new Type(Type::BUILTIN_TYPE_OBJECT, false, $argumentMetadata->getType()),
|
||||
groups: $this->getGroups($attribute),
|
||||
serializationContext: $attribute->serializationContext,
|
||||
));
|
||||
|
||||
$operation->_context->{self::CONTEXT_ARGUMENT_METADATA} = $argumentMetadata;
|
||||
$operation->_context->{self::CONTEXT_MODEL_REF} = $modelRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]|null
|
||||
*/
|
||||
private function getGroups(MapRequestPayload $attribute): ?array
|
||||
{
|
||||
if (null === $attribute->validationGroups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($attribute->validationGroups)) {
|
||||
return [$attribute->validationGroups];
|
||||
}
|
||||
|
||||
if (is_array($attribute->validationGroups)) {
|
||||
return $attribute->validationGroups;
|
||||
}
|
||||
|
||||
if ($attribute->validationGroups instanceof GroupSequence) {
|
||||
return $attribute->validationGroups->groups;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user