|
55 | 55 | use ApiPlatform\OpenApi\Options; |
56 | 56 | use ApiPlatform\OpenApi\Serializer\NormalizeOperationNameTrait; |
57 | 57 | use ApiPlatform\State\Pagination\PaginationOptions; |
| 58 | +use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\FilterWithStateOptions; |
58 | 59 | use Psr\Container\ContainerInterface; |
59 | 60 | use Symfony\Component\PropertyInfo\Type; |
60 | 61 | use Symfony\Component\Routing\RouteCollection; |
@@ -161,6 +162,9 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection |
161 | 162 | } |
162 | 163 |
|
163 | 164 | foreach ($resource->getOperations() as $operationName => $operation) { |
| 165 | + if (FilterWithStateOptions::class !== $operation->getClass()) { |
| 166 | + continue; |
| 167 | + } |
164 | 168 | $resourceShortName = $operation->getShortName(); |
165 | 169 | // No path to return |
166 | 170 | if (null === $operation->getUriTemplate() && null === $operation->getRouteName()) { |
@@ -331,12 +335,26 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection |
331 | 335 | } |
332 | 336 | } |
333 | 337 |
|
| 338 | + $entityClass = $this->getFilterClass($operation); |
334 | 339 | $openapiParameters = $openapiOperation->getParameters(); |
335 | 340 | foreach ($operation->getParameters() ?? [] as $key => $p) { |
336 | 341 | if (false === $p->getOpenApi()) { |
337 | 342 | continue; |
338 | 343 | } |
339 | 344 |
|
| 345 | + if (($f = $p->getFilter()) && \is_string($f) && $this->filterLocator->has($f)) { |
| 346 | + $filter = $this->filterLocator->get($f); |
| 347 | + foreach ($filter->getDescription($entityClass) as $name => $description) { |
| 348 | + if ($prop = $p->getProperty()) { |
| 349 | + $name = str_replace($prop, $key, $name); |
| 350 | + } |
| 351 | + |
| 352 | + $openapiParameters[] = $this->getFilterParameter($name, $description, $operation->getShortName(), $f); |
| 353 | + } |
| 354 | + |
| 355 | + continue; |
| 356 | + } |
| 357 | + |
340 | 358 | $in = $p instanceof HeaderParameterInterface ? 'header' : 'query'; |
341 | 359 | $parameter = new Parameter($key, $in, $p->getDescription() ?? "$resourceShortName $key", $p->getRequired() ?? false, false, false, $p->getSchema() ?? ['type' => 'string']); |
342 | 360 |
|
@@ -654,92 +672,102 @@ private function getLinks(ResourceMetadataCollection $resourceMetadataCollection |
654 | 672 | private function getFiltersParameters(CollectionOperationInterface|HttpOperation $operation): array |
655 | 673 | { |
656 | 674 | $parameters = []; |
657 | | - |
658 | 675 | $resourceFilters = $operation->getFilters(); |
| 676 | + $entityClass = $this->getFilterClass($operation); |
| 677 | + |
659 | 678 | foreach ($resourceFilters ?? [] as $filterId) { |
660 | 679 | if (!$this->filterLocator->has($filterId)) { |
661 | 680 | continue; |
662 | 681 | } |
663 | 682 |
|
664 | 683 | $filter = $this->filterLocator->get($filterId); |
665 | | - $entityClass = $operation->getClass(); |
666 | | - if ($options = $operation->getStateOptions()) { |
667 | | - if ($options instanceof DoctrineOptions && $options->getEntityClass()) { |
668 | | - $entityClass = $options->getEntityClass(); |
669 | | - } |
670 | | - |
671 | | - if ($options instanceof DoctrineODMOptions && $options->getDocumentClass()) { |
672 | | - $entityClass = $options->getDocumentClass(); |
673 | | - } |
| 684 | + foreach ($filter->getDescription($entityClass) as $name => $description) { |
| 685 | + $parameters[] = $this->getFilterParameter($name, $description, $operation->getShortName(), $filterId); |
674 | 686 | } |
| 687 | + } |
675 | 688 |
|
676 | | - foreach ($filter->getDescription($entityClass) as $name => $data) { |
677 | | - if (isset($data['swagger'])) { |
678 | | - trigger_deprecation('api-platform/core', '4.0', \sprintf('Using the "swagger" field of the %s::getDescription() (%s) is deprecated.', $filter::class, $operation->getShortName())); |
679 | | - } |
| 689 | + return $parameters; |
| 690 | + } |
680 | 691 |
|
681 | | - if (!isset($data['openapi']) || $data['openapi'] instanceof Parameter) { |
682 | | - $schema = $data['schema'] ?? []; |
| 692 | + private function getFilterClass(HttpOperation $operation): string |
| 693 | + { |
| 694 | + $entityClass = $operation->getClass(); |
| 695 | + if ($options = $operation->getStateOptions()) { |
| 696 | + if ($options instanceof DoctrineOptions && $options->getEntityClass()) { |
| 697 | + return $options->getEntityClass(); |
| 698 | + } |
683 | 699 |
|
684 | | - if (isset($data['type']) && \in_array($data['type'] ?? null, Type::$builtinTypes, true) && !isset($schema['type'])) { |
685 | | - $schema += $this->jsonSchemaTypeFactory ? $this->jsonSchemaTypeFactory->getType(new Type($data['type'], false, null, $data['is_collection'] ?? false)) : $this->getType(new Type($data['type'], false, null, $data['is_collection'] ?? false)); |
686 | | - } |
| 700 | + if ($options instanceof DoctrineODMOptions && $options->getDocumentClass()) { |
| 701 | + return $options->getDocumentClass(); |
| 702 | + } |
| 703 | + } |
687 | 704 |
|
688 | | - if (!isset($schema['type'])) { |
689 | | - $schema['type'] = 'string'; |
690 | | - } |
| 705 | + return $entityClass; |
| 706 | + } |
691 | 707 |
|
692 | | - $style = 'array' === ($schema['type'] ?? null) && \in_array( |
693 | | - $data['type'], |
694 | | - [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_OBJECT], |
695 | | - true |
696 | | - ) ? 'deepObject' : 'form'; |
| 708 | + private function getFilterParameter(string $name, array $description, string $shortName, string $filter): Parameter |
| 709 | + { |
| 710 | + if (isset($description['swagger'])) { |
| 711 | + trigger_deprecation('api-platform/core', '4.0', \sprintf('Using the "swagger" field of the %s::getDescription() (%s) is deprecated.', $filter, $shortName)); |
| 712 | + } |
697 | 713 |
|
698 | | - $parameter = isset($data['openapi']) && $data['openapi'] instanceof Parameter ? $data['openapi'] : new Parameter(in: 'query', name: $name, style: $style, explode: $data['is_collection'] ?? false); |
| 714 | + if (!isset($description['openapi']) || $description['openapi'] instanceof Parameter) { |
| 715 | + $schema = $description['schema'] ?? []; |
699 | 716 |
|
700 | | - if ('' === $parameter->getDescription() && ($description = $data['description'] ?? '')) { |
701 | | - $parameter = $parameter->withDescription($description); |
702 | | - } |
| 717 | + if (isset($description['type']) && \in_array($description['type'] ?? null, Type::$builtinTypes, true) && !isset($schema['type'])) { |
| 718 | + $schema += $this->jsonSchemaTypeFactory ? $this->jsonSchemaTypeFactory->getType(new Type($description['type'], false, null, $description['is_collection'] ?? false)) : $this->getType(new Type($description['type'], false, null, $description['is_collection'] ?? false)); |
| 719 | + } |
703 | 720 |
|
704 | | - if (false === $parameter->getRequired() && false !== ($required = $data['required'] ?? false)) { |
705 | | - $parameter = $parameter->withRequired($required); |
706 | | - } |
| 721 | + if (!isset($schema['type'])) { |
| 722 | + $schema['type'] = 'string'; |
| 723 | + } |
707 | 724 |
|
708 | | - $parameters[] = $parameter->withSchema($schema); |
709 | | - continue; |
710 | | - } |
| 725 | + $style = 'array' === ($schema['type'] ?? null) && \in_array( |
| 726 | + $description['type'], |
| 727 | + [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_OBJECT], |
| 728 | + true |
| 729 | + ) ? 'deepObject' : 'form'; |
711 | 730 |
|
712 | | - trigger_deprecation('api-platform/core', '4.0', \sprintf('Not using "%s" on the "openapi" field of the %s::getDescription() (%s) is deprecated.', Parameter::class, $filter::class, $operation->getShortName())); |
713 | | - if ($this->jsonSchemaTypeFactory) { |
714 | | - $schema = $data['schema'] ?? (\in_array($data['type'], Type::$builtinTypes, true) ? $this->jsonSchemaTypeFactory->getType(new Type($data['type'], false, null, $data['is_collection'] ?? false), 'openapi') : ['type' => 'string']); |
715 | | - } else { |
716 | | - $schema = $data['schema'] ?? (\in_array($data['type'], Type::$builtinTypes, true) ? $this->getType(new Type($data['type'], false, null, $data['is_collection'] ?? false)) : ['type' => 'string']); |
717 | | - } |
| 731 | + $parameter = isset($description['openapi']) && $description['openapi'] instanceof Parameter ? $description['openapi'] : new Parameter(in: 'query', name: $name, style: $style, explode: $description['is_collection'] ?? false); |
718 | 732 |
|
719 | | - $parameters[] = new Parameter( |
720 | | - $name, |
721 | | - 'query', |
722 | | - $data['description'] ?? '', |
723 | | - $data['required'] ?? false, |
724 | | - $data['openapi']['deprecated'] ?? false, |
725 | | - $data['openapi']['allowEmptyValue'] ?? true, |
726 | | - $schema, |
727 | | - 'array' === $schema['type'] && \in_array( |
728 | | - $data['type'], |
729 | | - [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_OBJECT], |
730 | | - true |
731 | | - ) ? 'deepObject' : 'form', |
732 | | - $data['openapi']['explode'] ?? ('array' === $schema['type']), |
733 | | - $data['openapi']['allowReserved'] ?? false, |
734 | | - $data['openapi']['example'] ?? null, |
735 | | - isset( |
736 | | - $data['openapi']['examples'] |
737 | | - ) ? new \ArrayObject($data['openapi']['examples']) : null |
738 | | - ); |
| 733 | + if ('' === $parameter->getDescription() && ($description = $description['description'] ?? '')) { |
| 734 | + $parameter = $parameter->withDescription($description); |
| 735 | + } |
| 736 | + |
| 737 | + if (false === $parameter->getRequired() && false !== ($required = $description['required'] ?? false)) { |
| 738 | + $parameter = $parameter->withRequired($required); |
739 | 739 | } |
| 740 | + |
| 741 | + return $parameter->withSchema($schema); |
740 | 742 | } |
741 | 743 |
|
742 | | - return $parameters; |
| 744 | + trigger_deprecation('api-platform/core', '4.0', \sprintf('Not using "%s" on the "openapi" field of the %s::getDescription() (%s) is deprecated.', Parameter::class, $filter, $shortName)); |
| 745 | + if ($this->jsonSchemaTypeFactory) { |
| 746 | + $schema = $description['schema'] ?? (\in_array($description['type'], Type::$builtinTypes, true) ? $this->jsonSchemaTypeFactory->getType(new Type($description['type'], false, null, $description['is_collection'] ?? false), 'openapi') : ['type' => 'string']); |
| 747 | + } else { |
| 748 | + $schema = $description['schema'] ?? (\in_array($description['type'], Type::$builtinTypes, true) ? $this->getType(new Type($description['type'], false, null, $description['is_collection'] ?? false)) : ['type' => 'string']); |
| 749 | + } |
| 750 | + |
| 751 | + return new Parameter( |
| 752 | + $name, |
| 753 | + 'query', |
| 754 | + $description['description'] ?? '', |
| 755 | + $description['required'] ?? false, |
| 756 | + $description['openapi']['deprecated'] ?? false, |
| 757 | + $description['openapi']['allowEmptyValue'] ?? true, |
| 758 | + $schema, |
| 759 | + 'array' === $schema['type'] && \in_array( |
| 760 | + $description['type'], |
| 761 | + [Type::BUILTIN_TYPE_ARRAY, Type::BUILTIN_TYPE_OBJECT], |
| 762 | + true |
| 763 | + ) ? 'deepObject' : 'form', |
| 764 | + $description['openapi']['explode'] ?? ('array' === $schema['type']), |
| 765 | + $description['openapi']['allowReserved'] ?? false, |
| 766 | + $description['openapi']['example'] ?? null, |
| 767 | + isset( |
| 768 | + $description['openapi']['examples'] |
| 769 | + ) ? new \ArrayObject($description['openapi']['examples']) : null |
| 770 | + ); |
743 | 771 | } |
744 | 772 |
|
745 | 773 | private function getPaginationParameters(CollectionOperationInterface|HttpOperation $operation): array |
|
0 commit comments