From 36c657b751f37e123221d85a387faaef2a2618c2 Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 20 Dec 2024 11:27:04 +0100 Subject: [PATCH 01/16] docs: v4.1.0-alpha.1 changelog --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2139802871..81b5e43257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## v4.1.0-alpha.1 + +### Bug fixes + +* [67fbe51c5](https://github.com/api-platform/core/commit/67fbe51c570abe1ece6651ae6a037662e9012881) fix: reintroduce the `show_webby` parameter in Laravel config (#6741) + +### Features + +* [00787f32d](https://github.com/api-platform/core/commit/00787f32da54418de7d869cff218e22d8ae2ae1d) feat(laravel): automatically register policies (#6623) +* [12c42096b](https://github.com/api-platform/core/commit/12c42096bb0006d6ebae60ae5d90e9b356f9a335) feat(metadata): ability to hide an hydra class/operation (#6871) +* [57f15cf4f](https://github.com/api-platform/core/commit/57f15cf4f38278315c5f31d3949416c9455ba0d0) feat(state): strict query parameters (#6399) +* [bd0e92936](https://github.com/api-platform/core/commit/bd0e92936f82d3cd4563cd45ebf1f73fd1db9f01) feat(openapi): HTTP Authentication Support for Swagger UI (#6665) +* [be98f4e01](https://github.com/api-platform/core/commit/be98f4e01a52d8341ef9b65ed2f4e3b46ab31165) feat(graphql): allow to configure max query depth and max query complexity (#6880) +* [c78ed0b78](https://github.com/api-platform/core/commit/c78ed0b78baf5d2e1b7444a9882ba039c70a3887) feat(laravel): boolean filter (#6806) +* [d0a442786](https://github.com/api-platform/core/commit/d0a44278630d201b91cbba0774a09f4eeaac88f7) feat(doctrine): enhance getLinksHandler with method validation and typo suggestions (#6874) +* [f67f6f1ac](https://github.com/api-platform/core/commit/f67f6f1acb6476182c18a3503f2a8bc80ae89a0b) feat(doctrine): doctrine filters like laravel eloquent filters (#6775) + ## v4.0.13 ### Bug fixes From 5e1a6e11e33486f76c4ded7bf7bcb108c65a7de6 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Sat, 21 Dec 2024 09:14:52 +0100 Subject: [PATCH 02/16] fix(laravel): restore accidentally removed BooleanFilter (#6881) --- src/Laravel/ApiPlatformProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Laravel/ApiPlatformProvider.php b/src/Laravel/ApiPlatformProvider.php index d0f064f508..90ce2d6a02 100644 --- a/src/Laravel/ApiPlatformProvider.php +++ b/src/Laravel/ApiPlatformProvider.php @@ -427,6 +427,7 @@ public function register(): void $this->app->bind(OperationMetadataFactoryInterface::class, OperationMetadataFactory::class); $this->app->tag([ + BooleanFilter::class, EqualsFilter::class, PartialSearchFilter::class, DateFilter::class, From b82f9ac76ce89dd3910849c73da42317ee1339ed Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 9 Jan 2025 11:29:41 +0100 Subject: [PATCH 03/16] fix(openapi): not forbidden response on openAPI doc (#6886) --- src/OpenApi/Factory/OpenApiFactory.php | 4 +++ .../Tests/Factory/OpenApiFactoryTest.php | 29 ++++++++++++++++++- .../Tests/Fixtures/Issue6872/Diamond.php | 19 ++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/OpenApi/Tests/Fixtures/Issue6872/Diamond.php diff --git a/src/OpenApi/Factory/OpenApiFactory.php b/src/OpenApi/Factory/OpenApiFactory.php index 84a779ccc9..1a51fbb542 100644 --- a/src/OpenApi/Factory/OpenApiFactory.php +++ b/src/OpenApi/Factory/OpenApiFactory.php @@ -408,6 +408,10 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection } } + if (true === $overrideResponses && !isset($existingResponses[403]) && $operation->getSecurity()) { + $openapiOperation = $openapiOperation->withResponse(403, new Response('Forbidden')); + } + if (true === $overrideResponses && !$operation instanceof CollectionOperationInterface && 'POST' !== $operation->getMethod()) { if (!isset($existingResponses[404])) { $openapiOperation = $openapiOperation->withResponse(404, new Response('Resource not found')); diff --git a/src/OpenApi/Tests/Factory/OpenApiFactoryTest.php b/src/OpenApi/Tests/Factory/OpenApiFactoryTest.php index 1d3511df8e..0acf7dba88 100644 --- a/src/OpenApi/Tests/Factory/OpenApiFactoryTest.php +++ b/src/OpenApi/Tests/Factory/OpenApiFactoryTest.php @@ -59,6 +59,7 @@ use ApiPlatform\OpenApi\Tests\Fixtures\Dummy; use ApiPlatform\OpenApi\Tests\Fixtures\DummyErrorResource; use ApiPlatform\OpenApi\Tests\Fixtures\DummyFilter; +use ApiPlatform\OpenApi\Tests\Fixtures\Issue6872\Diamond; use ApiPlatform\OpenApi\Tests\Fixtures\OutputDto; use ApiPlatform\State\Pagination\PaginationOptions; use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\WithParameter; @@ -85,6 +86,7 @@ public function testInvoke(): void $baseOperation = (new HttpOperation())->withTypes(['http://schema.example.com/Dummy'])->withInputFormats(self::OPERATION_FORMATS['input_formats'])->withOutputFormats(self::OPERATION_FORMATS['output_formats'])->withClass(Dummy::class)->withOutput([ 'class' => OutputDto::class, ])->withPaginationClientItemsPerPage(true)->withShortName('Dummy')->withDescription('This is a dummy'); + $dummyResourceWebhook = (new ApiResource())->withOperations(new Operations([ 'dummy webhook' => (new Get())->withUriTemplate('/dummy/{id}')->withShortName('short')->withOpenapi(new Webhook('first webhook')), 'an other dummy webhook' => (new Post())->withUriTemplate('/dummies')->withShortName('short something')->withOpenapi(new Webhook('happy webhook', new Model\PathItem(post: new Operation( @@ -272,13 +274,23 @@ public function testInvoke(): void ]))->withOperation($baseOperation), ])); + $diamondResource = (new ApiResource()) + ->withOperations(new Operations([ + 'getDiamondCollection' => (new GetCollection(uriTemplate: '/diamonds')) + ->withSecurity("is_granted('ROLE_USER')") + ->withOperation($baseOperation), + 'putDiamond' => (new Put(uriTemplate: '/diamond/{id}')) + ->withOperation($baseOperation), + ])); + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->shouldBeCalled()->willReturn(new ResourceNameCollection([Dummy::class, WithParameter::class])); + $resourceNameCollectionFactoryProphecy->create()->shouldBeCalled()->willReturn(new ResourceNameCollection([Dummy::class, WithParameter::class, Diamond::class])); $resourceCollectionMetadataFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class); $resourceCollectionMetadataFactoryProphecy->create(Dummy::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(Dummy::class, [$dummyResource, $dummyResourceWebhook])); $resourceCollectionMetadataFactoryProphecy->create(DummyErrorResource::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(DummyErrorResource::class, [new ApiResource(operations: [new ErrorOperation(name: 'err', description: 'nice one!')])])); $resourceCollectionMetadataFactoryProphecy->create(WithParameter::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(WithParameter::class, [$parameterResource])); + $resourceCollectionMetadataFactoryProphecy->create(Diamond::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(Diamond::class, [$diamondResource])); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); $propertyNameCollectionFactoryProphecy->create(Dummy::class, Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['id', 'name', 'description', 'dummyDate', 'enum'])); @@ -1171,5 +1183,20 @@ public function testInvoke(): void ], deprecated: false ), $paths->getPath('/erroredDummies')->getGet()); + + $diamondsGetPath = $paths->getPath('/diamonds'); + $diamondGetOperation = $diamondsGetPath->getGet(); + $diamondGetResponses = $diamondGetOperation->getResponses(); + + $this->assertNotNull($diamondGetOperation); + $this->assertArrayHasKey('403', $diamondGetResponses); + $this->assertSame('Forbidden', $diamondGetResponses['403']->getDescription()); + + $diamondsPutPath = $paths->getPath('/diamond/{id}'); + $diamondPutOperation = $diamondsPutPath->getPut(); + $diamondPutResponses = $diamondPutOperation->getResponses(); + + $this->assertNotNull($diamondPutOperation); + $this->assertArrayNotHasKey('403', $diamondPutResponses); } } diff --git a/src/OpenApi/Tests/Fixtures/Issue6872/Diamond.php b/src/OpenApi/Tests/Fixtures/Issue6872/Diamond.php new file mode 100644 index 0000000000..e2cf520f62 --- /dev/null +++ b/src/OpenApi/Tests/Fixtures/Issue6872/Diamond.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\OpenApi\Tests\Fixtures\Issue6872; + +class Diamond +{ + public float $weight; +} From 97cdb6b3f43471789e096c9dc3a0c3c7b6d4e43c Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 9 Jan 2025 11:54:20 +0100 Subject: [PATCH 04/16] fix: remove laravel specific type fixes #6890 --- src/State/ProcessorInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/State/ProcessorInterface.php b/src/State/ProcessorInterface.php index 07bb906798..8bfa0c49b0 100644 --- a/src/State/ProcessorInterface.php +++ b/src/State/ProcessorInterface.php @@ -31,7 +31,7 @@ interface ProcessorInterface * * @param T1 $data * @param array $uriVariables - * @param array&array{request?: Request|\Illuminate\Http\Request, previous_data?: mixed, resource_class?: string|null, original_data?: mixed} $context + * @param array&array{request?: Request, previous_data?: mixed, resource_class?: string|null, original_data?: mixed} $context * * @return T2 */ From deb2ed265dfee7b8a73fd3b542aef3e29eca3412 Mon Sep 17 00:00:00 2001 From: Tobias Oitzinger <42447585+toitzi@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:24:32 +0100 Subject: [PATCH 05/16] fix(laravel): fix use laravel fillable for writable props (#6898) Closes: #6875 --- .../Factory/Property/EloquentPropertyMetadataFactory.php | 2 +- src/Laravel/workbench/app/Models/Book.php | 4 ++-- src/Laravel/workbench/app/Models/Vault.php | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Laravel/Eloquent/Metadata/Factory/Property/EloquentPropertyMetadataFactory.php b/src/Laravel/Eloquent/Metadata/Factory/Property/EloquentPropertyMetadataFactory.php index 6385a83568..d4210674e6 100644 --- a/src/Laravel/Eloquent/Metadata/Factory/Property/EloquentPropertyMetadataFactory.php +++ b/src/Laravel/Eloquent/Metadata/Factory/Property/EloquentPropertyMetadataFactory.php @@ -88,7 +88,7 @@ public function create(string $resourceClass, string $property, array $options = return $propertyMetadata ->withBuiltinTypes([$type]) - ->withWritable($propertyMetadata->isWritable() ?? true) + ->withWritable($propertyMetadata->isWritable() ?? true === $p['fillable']) ->withReadable($propertyMetadata->isReadable() ?? false === $p['hidden']); } diff --git a/src/Laravel/workbench/app/Models/Book.php b/src/Laravel/workbench/app/Models/Book.php index 5bf77ecd21..65f8050743 100644 --- a/src/Laravel/workbench/app/Models/Book.php +++ b/src/Laravel/workbench/app/Models/Book.php @@ -88,8 +88,8 @@ class Book extends Model use HasFactory; use HasUlids; - protected $visible = ['name', 'author', 'isbn', 'publication_date', 'published', 'is_available']; - protected $fillable = ['name', 'is_available']; + protected $visible = ['name', 'author', 'isbn', 'publication_date', 'is_available', 'published']; + protected $fillable = ['name', 'publication_date', 'isbn', 'is_available', 'published']; protected $casts = [ 'is_available' => 'boolean', ]; diff --git a/src/Laravel/workbench/app/Models/Vault.php b/src/Laravel/workbench/app/Models/Vault.php index 2e22a52d6c..7949c84a63 100644 --- a/src/Laravel/workbench/app/Models/Vault.php +++ b/src/Laravel/workbench/app/Models/Vault.php @@ -42,6 +42,10 @@ class Vault extends Model { use HasFactory; + protected $fillable = [ + 'secret', + ]; + public static function provide(): self { $v = new self(); From 2b3c55db2a9ecc52f62c441fa8a5696233a30b87 Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Thu, 9 Jan 2025 12:25:57 +0100 Subject: [PATCH 06/16] fix(symfony): remove unsolvable deprecation (#6899) fixes #6686 --- src/Symfony/EventListener/QueryParameterValidateListener.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/EventListener/QueryParameterValidateListener.php b/src/Symfony/EventListener/QueryParameterValidateListener.php index 6f799b07a1..3771c98d65 100644 --- a/src/Symfony/EventListener/QueryParameterValidateListener.php +++ b/src/Symfony/EventListener/QueryParameterValidateListener.php @@ -44,7 +44,6 @@ public function __construct($queryParameterValidator, ?ResourceMetadataCollectio if ($queryParameterValidator instanceof ProviderInterface) { $this->provider = $queryParameterValidator; } else { - trigger_deprecation('api-platform/core', '3.3', 'Use a "%s" as first argument in "%s" instead of "%s".', ProviderInterface::class, self::class, ParameterValidator::class); $this->queryParameterValidator = $queryParameterValidator; } From 3a1142782409a4d93f690ba631bf3bb8fb79d72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 9 Jan 2025 15:22:44 +0100 Subject: [PATCH 07/16] chore: add missing deprecation notices to ParameterValidator (#6655) Co-authored-by: soyuka --- .../Exception/ValidationException.php | 4 ++++ .../Exception/ValidationExceptionInterface.php | 2 ++ src/ParameterValidator/FilterLocatorTrait.php | 6 ++---- src/ParameterValidator/ParameterValidator.php | 4 ++++ .../Tests/ParameterValidatorTest.php | 2 ++ .../Tests/Validator/ArrayItemsTest.php | 5 ++--- .../Tests/Validator/BoundsTest.php | 14 ++------------ .../Tests/Validator/EnumTest.php | 8 ++------ .../Tests/Validator/LengthTest.php | 14 ++------------ .../Tests/Validator/MultipleOfTest.php | 8 ++------ .../Tests/Validator/PatternTest.php | 14 ++------------ .../Tests/Validator/RequiredTest.php | 8 ++------ src/ParameterValidator/Validator/ArrayItems.php | 7 ++++++- src/ParameterValidator/Validator/Bounds.php | 7 ++++++- src/ParameterValidator/Validator/Enum.php | 7 ++++++- src/ParameterValidator/Validator/Length.php | 7 ++++++- src/ParameterValidator/Validator/MultipleOf.php | 7 ++++++- src/ParameterValidator/Validator/Pattern.php | 7 ++++++- src/ParameterValidator/Validator/Required.php | 7 ++++++- .../Validator/ValidatorInterface.php | 2 +- .../DependencyInjection/ApiPlatformExtension.php | 2 +- .../Bundle/DependencyInjection/Configuration.php | 1 + .../parameter_validator/parameter_validator.xml | 1 + .../config/legacy/parameter_validator/state.xml | 2 ++ tests/Fixtures/app/config/config_common.yml | 2 ++ .../DependencyInjection/ConfigurationTest.php | 1 + 26 files changed, 79 insertions(+), 70 deletions(-) diff --git a/src/ParameterValidator/Exception/ValidationException.php b/src/ParameterValidator/Exception/ValidationException.php index b5559d5103..52c8ca3d51 100644 --- a/src/ParameterValidator/Exception/ValidationException.php +++ b/src/ParameterValidator/Exception/ValidationException.php @@ -18,6 +18,8 @@ /** * Filter validation exception. * + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead + * * @author Julien DENIAU */ final class ValidationException extends \Exception implements ValidationExceptionInterface, ProblemExceptionInterface @@ -28,6 +30,8 @@ final class ValidationException extends \Exception implements ValidationExceptio public function __construct(private readonly array $constraintViolationList, string $message = '', int $code = 0, ?\Exception $previous = null) { parent::__construct($message ?: $this->__toString(), $code, $previous); + + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); } public function getConstraintViolationList(): array diff --git a/src/ParameterValidator/Exception/ValidationExceptionInterface.php b/src/ParameterValidator/Exception/ValidationExceptionInterface.php index 863c5ff685..18e0553acb 100644 --- a/src/ParameterValidator/Exception/ValidationExceptionInterface.php +++ b/src/ParameterValidator/Exception/ValidationExceptionInterface.php @@ -17,6 +17,8 @@ /** * This Exception is thrown when any parameter validation fails. + * + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ interface ValidationExceptionInterface extends ExceptionInterface, \Stringable { diff --git a/src/ParameterValidator/FilterLocatorTrait.php b/src/ParameterValidator/FilterLocatorTrait.php index 5d4fbce277..a3d49501d3 100644 --- a/src/ParameterValidator/FilterLocatorTrait.php +++ b/src/ParameterValidator/FilterLocatorTrait.php @@ -20,11 +20,9 @@ /** * Manipulates filters with a backward compatibility between the new filter locator and the deprecated filter collection. * - * @author Baptiste Meyer - * - * @deprecated - * * @internal + * + * @author Baptiste Meyer */ trait FilterLocatorTrait { diff --git a/src/ParameterValidator/ParameterValidator.php b/src/ParameterValidator/ParameterValidator.php index a915bd0381..1a52140925 100644 --- a/src/ParameterValidator/ParameterValidator.php +++ b/src/ParameterValidator/ParameterValidator.php @@ -26,6 +26,8 @@ /** * Validates parameters depending on filter description. * + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead + * * @author Julien Deniau */ class ParameterValidator @@ -36,6 +38,8 @@ class ParameterValidator public function __construct(ContainerInterface $filterLocator) { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + $this->setFilterLocator($filterLocator); $this->validators = [ diff --git a/src/ParameterValidator/Tests/ParameterValidatorTest.php b/src/ParameterValidator/Tests/ParameterValidatorTest.php index cc2223fb7d..211fabc492 100644 --- a/src/ParameterValidator/Tests/ParameterValidatorTest.php +++ b/src/ParameterValidator/Tests/ParameterValidatorTest.php @@ -23,6 +23,8 @@ use Psr\Container\ContainerInterface; /** + * @group legacy + * * @author Julien Deniau */ class ParameterValidatorTest extends TestCase diff --git a/src/ParameterValidator/Tests/Validator/ArrayItemsTest.php b/src/ParameterValidator/Tests/Validator/ArrayItemsTest.php index 6e922ba339..228228111b 100644 --- a/src/ParameterValidator/Tests/Validator/ArrayItemsTest.php +++ b/src/ParameterValidator/Tests/Validator/ArrayItemsTest.php @@ -17,6 +17,8 @@ use PHPUnit\Framework\TestCase; /** + * @group legacy + * * @author Julien Deniau */ class ArrayItemsTest extends TestCase @@ -41,9 +43,6 @@ public function testEmptyQueryParameter(): void ); } - /** - * @group legacy - */ public function testNonMatchingParameter(): void { $filter = new ArrayItems(); diff --git a/src/ParameterValidator/Tests/Validator/BoundsTest.php b/src/ParameterValidator/Tests/Validator/BoundsTest.php index 2706f8e9e2..dbcc77a655 100644 --- a/src/ParameterValidator/Tests/Validator/BoundsTest.php +++ b/src/ParameterValidator/Tests/Validator/BoundsTest.php @@ -17,6 +17,8 @@ use PHPUnit\Framework\TestCase; /** + * @group legacy + * * @author Julien Deniau */ class BoundsTest extends TestCase @@ -39,9 +41,6 @@ public function testEmptyQueryParameter(): void ); } - /** - * @group legacy - */ public function testNonMatchingMinimum(): void { $request = ['some_filter' => '9']; @@ -124,9 +123,6 @@ public function testNonMatchingMinimumOpenApi(): void ); } - /** - * @group legacy - */ public function testMatchingMinimum(): void { $request = ['some_filter' => '10']; @@ -181,9 +177,6 @@ public function testMatchingMinimumOpenApi(): void ); } - /** - * @group legacy - */ public function testNonMatchingMaximum(): void { $request = ['some_filter' => '11']; @@ -266,9 +259,6 @@ public function testNonMatchingMaximumOpenApi(): void ); } - /** - * @group legacy - */ public function testMatchingMaximum(): void { $request = ['some_filter' => '10']; diff --git a/src/ParameterValidator/Tests/Validator/EnumTest.php b/src/ParameterValidator/Tests/Validator/EnumTest.php index 7f21ca17c0..ac19443246 100644 --- a/src/ParameterValidator/Tests/Validator/EnumTest.php +++ b/src/ParameterValidator/Tests/Validator/EnumTest.php @@ -17,6 +17,8 @@ use PHPUnit\Framework\TestCase; /** + * @group legacy + * * @author Julien Deniau */ class EnumTest extends TestCase @@ -39,9 +41,6 @@ public function testEmptyQueryParameter(): void ); } - /** - * @group legacy - */ public function testNonMatchingParameter(): void { $filter = new Enum(); @@ -74,9 +73,6 @@ public function testNonMatchingParameterOpenApi(): void ); } - /** - * @group legacy - */ public function testMatchingParameter(): void { $filter = new Enum(); diff --git a/src/ParameterValidator/Tests/Validator/LengthTest.php b/src/ParameterValidator/Tests/Validator/LengthTest.php index cb9a244a56..ef6c6ca0e6 100644 --- a/src/ParameterValidator/Tests/Validator/LengthTest.php +++ b/src/ParameterValidator/Tests/Validator/LengthTest.php @@ -17,6 +17,8 @@ use PHPUnit\Framework\TestCase; /** + * @group legacy + * * @author Julien Deniau */ class LengthTest extends TestCase @@ -39,9 +41,6 @@ public function testEmptyQueryParameter(): void ); } - /** - * @group legacy - */ public function testNonMatchingParameter(): void { $filter = new Length(); @@ -86,9 +85,6 @@ public function testNonMatchingParameterOpenApi(): void ); } - /** - * @group legacy - */ public function testNonMatchingParameterWithOnlyOneDefinition(): void { $filter = new Length(); @@ -143,9 +139,6 @@ public function testNonMatchingParameterWithOnlyOneDefinitionOpenApi(): void ); } - /** - * @group legacy - */ public function testMatchingParameter(): void { $filter = new Length(); @@ -194,9 +187,6 @@ public function testMatchingParameterOpenApi(): void ); } - /** - * @group legacy - */ public function testMatchingParameterWithOneDefinition(): void { $filter = new Length(); diff --git a/src/ParameterValidator/Tests/Validator/MultipleOfTest.php b/src/ParameterValidator/Tests/Validator/MultipleOfTest.php index 58227b7672..38c8b0511d 100644 --- a/src/ParameterValidator/Tests/Validator/MultipleOfTest.php +++ b/src/ParameterValidator/Tests/Validator/MultipleOfTest.php @@ -17,6 +17,8 @@ use PHPUnit\Framework\TestCase; /** + * @group legacy + * * @author Julien Deniau */ class MultipleOfTest extends TestCase @@ -40,9 +42,6 @@ public function testEmptyQueryParameter(): void ); } - /** - * @group legacy - */ public function testNonMatchingParameter(): void { $request = ['some_filter' => '8']; @@ -77,9 +76,6 @@ public function testNonMatchingParameterOpenApi(): void ); } - /** - * @group legacy - */ public function testMatchingParameter(): void { $request = ['some_filter' => '8']; diff --git a/src/ParameterValidator/Tests/Validator/PatternTest.php b/src/ParameterValidator/Tests/Validator/PatternTest.php index bfa987a524..b18328d95a 100644 --- a/src/ParameterValidator/Tests/Validator/PatternTest.php +++ b/src/ParameterValidator/Tests/Validator/PatternTest.php @@ -17,6 +17,8 @@ use PHPUnit\Framework\TestCase; /** + * @group legacy + * * @author Julien Deniau */ class PatternTest extends TestCase @@ -30,9 +32,6 @@ public function testNonDefinedFilter(): void ); } - /** - * @group legacy - */ public function testFilterWithEmptyValue(): void { $filter = new Pattern(); @@ -75,9 +74,6 @@ public function testFilterWithEmptyValueOpenApi(): void ); } - /** - * @group legacy - */ public function testFilterWithZeroAsParameter(): void { $filter = new Pattern(); @@ -110,9 +106,6 @@ public function testFilterWithZeroAsParameterOpenApi(): void ); } - /** - * @group legacy - */ public function testFilterWithNonMatchingValue(): void { $filter = new Pattern(); @@ -145,9 +138,6 @@ public function testFilterWithNonMatchingValueOpenApi(): void ); } - /** - * @group legacy - */ public function testFilterWithNonchingValue(): void { $filter = new Pattern(); diff --git a/src/ParameterValidator/Tests/Validator/RequiredTest.php b/src/ParameterValidator/Tests/Validator/RequiredTest.php index ce6419bca0..32d00d03a7 100644 --- a/src/ParameterValidator/Tests/Validator/RequiredTest.php +++ b/src/ParameterValidator/Tests/Validator/RequiredTest.php @@ -19,6 +19,8 @@ /** * Class RequiredTest. * + * @group legacy + * * @author Julien Deniau */ class RequiredTest extends TestCase @@ -58,9 +60,6 @@ public function testRequiredFilterIsPresent(): void ); } - /** - * @group legacy - */ public function testEmptyValueNotAllowed(): void { $request = ['some_filter' => '']; @@ -115,9 +114,6 @@ public function testEmptyValueNotAllowedOpenApi(): void ); } - /** - * @group legacy - */ public function testEmptyValueAllowed(): void { $request = ['some_filter' => '']; diff --git a/src/ParameterValidator/Validator/ArrayItems.php b/src/ParameterValidator/Validator/ArrayItems.php index 28d99ff413..9034222e1c 100644 --- a/src/ParameterValidator/Validator/ArrayItems.php +++ b/src/ParameterValidator/Validator/ArrayItems.php @@ -14,12 +14,17 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class ArrayItems implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/Bounds.php b/src/ParameterValidator/Validator/Bounds.php index a5ca73fda4..1170b82a0b 100644 --- a/src/ParameterValidator/Validator/Bounds.php +++ b/src/ParameterValidator/Validator/Bounds.php @@ -14,12 +14,17 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class Bounds implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/Enum.php b/src/ParameterValidator/Validator/Enum.php index b22b12facc..6d23d0561d 100644 --- a/src/ParameterValidator/Validator/Enum.php +++ b/src/ParameterValidator/Validator/Enum.php @@ -14,12 +14,17 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class Enum implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/Length.php b/src/ParameterValidator/Validator/Length.php index 19e4aef3ae..7636f024ad 100644 --- a/src/ParameterValidator/Validator/Length.php +++ b/src/ParameterValidator/Validator/Length.php @@ -14,12 +14,17 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class Length implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/MultipleOf.php b/src/ParameterValidator/Validator/MultipleOf.php index a363b47158..bbac95613b 100644 --- a/src/ParameterValidator/Validator/MultipleOf.php +++ b/src/ParameterValidator/Validator/MultipleOf.php @@ -14,12 +14,17 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class MultipleOf implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/Pattern.php b/src/ParameterValidator/Validator/Pattern.php index ca29f05b77..3ac468e670 100644 --- a/src/ParameterValidator/Validator/Pattern.php +++ b/src/ParameterValidator/Validator/Pattern.php @@ -14,12 +14,17 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class Pattern implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/Required.php b/src/ParameterValidator/Validator/Required.php index 41b6d2fdba..09d7eba33e 100644 --- a/src/ParameterValidator/Validator/Required.php +++ b/src/ParameterValidator/Validator/Required.php @@ -16,12 +16,17 @@ use ApiPlatform\State\Util\RequestParser; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ final class Required implements ValidatorInterface { use CheckFilterDeprecationsTrait; + public function __construct() + { + trigger_deprecation('api-platform/core', '3.4', 'The class "%s" is deprecated, use "\ApiPlatform\Metadata\Parameter::$constraints" instead.', __CLASS__); + } + /** * {@inheritdoc} */ diff --git a/src/ParameterValidator/Validator/ValidatorInterface.php b/src/ParameterValidator/Validator/ValidatorInterface.php index 846c9ae4b0..5e53ede15a 100644 --- a/src/ParameterValidator/Validator/ValidatorInterface.php +++ b/src/ParameterValidator/Validator/ValidatorInterface.php @@ -14,7 +14,7 @@ namespace ApiPlatform\ParameterValidator\Validator; /** - * @deprecated use Parameter constraint instead + * @deprecated use \ApiPlatform\Metadata\Parameter::$constraints instead */ interface ValidatorInterface { diff --git a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php index f8f233fa69..c3903b2c16 100644 --- a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -881,7 +881,7 @@ private function registerValidatorConfiguration(ContainerBuilder $container, arr $container->setParameter('api_platform.validator.serialize_payload_fields', $config['validator']['serialize_payload_fields']); $container->setParameter('api_platform.validator.query_parameter_validation', $config['validator']['query_parameter_validation']); - if (class_exists(QueryParameterValidator::class)) { + if ($config['validator']['legacy_query_parameter_validation'] && class_exists(QueryParameterValidator::class)) { $loader->load('legacy/parameter_validator/parameter_validator.xml'); $loader->load($config['use_symfony_listeners'] ? 'legacy/parameter_validator/events.xml' : 'legacy/parameter_validator/state.xml'); } diff --git a/src/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/DependencyInjection/Configuration.php index f37c42860d..85f089148a 100644 --- a/src/Symfony/Bundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/DependencyInjection/Configuration.php @@ -99,6 +99,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->variableNode('serialize_payload_fields')->defaultValue([])->info('Set to null to serialize all payload fields when a validation error is thrown, or set the fields you want to include explicitly.')->end() ->booleanNode('query_parameter_validation')->defaultValue(true)->end() ->booleanNode('legacy_validation_exception')->defaultValue(true)->info('Uses the legacy "%s" instead of "%s".', LegacyValidationException::class, ValidationException::class)->end() + ->booleanNode('legacy_query_parameter_validation')->defaultValue(true)->info('Use the legacy query validation system.')->end() ->end() ->end() ->arrayNode('eager_loading') diff --git a/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/parameter_validator.xml b/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/parameter_validator.xml index 89ea18cfab..1dc2842033 100644 --- a/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/parameter_validator.xml +++ b/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/parameter_validator.xml @@ -6,6 +6,7 @@ + The "%service_id%" service is deprecated use "\ApiPlatform\Metadata\Parameter::$constraints" instead. diff --git a/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/state.xml b/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/state.xml index 7fd2a0249f..3f34f93400 100644 --- a/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/state.xml +++ b/src/Symfony/Bundle/Resources/config/legacy/parameter_validator/state.xml @@ -6,10 +6,12 @@ + The "%service_id%" service is deprecated use "\ApiPlatform\Metadata\Parameter::$constraints" instead. + The "%service_id%" service is deprecated. diff --git a/tests/Fixtures/app/config/config_common.yml b/tests/Fixtures/app/config/config_common.yml index 986b838e17..bdc3f8596b 100644 --- a/tests/Fixtures/app/config/config_common.yml +++ b/tests/Fixtures/app/config/config_common.yml @@ -90,6 +90,8 @@ api_platform: - '%kernel.project_dir%/../TestBundle/Model' mercure: include_type: true + validator: + legacy_query_parameter_validation: false services: test.clienL: diff --git a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php index ba44d094e7..bef451ac77 100644 --- a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php +++ b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php @@ -111,6 +111,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm 'serialize_payload_fields' => [], 'query_parameter_validation' => true, 'legacy_validation_exception' => true, + 'legacy_query_parameter_validation' => true, ], 'name_converter' => null, 'enable_swagger' => true, From 9493b9b6ec0264ab5b700c861ad1b97455b4f88d Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Thu, 9 Jan 2025 15:55:39 +0100 Subject: [PATCH 08/16] fix(symfony): revert json schema bc break (#6903) fixes #6753 --- src/Symfony/Bundle/Resources/config/json_schema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/Resources/config/json_schema.xml b/src/Symfony/Bundle/Resources/config/json_schema.xml index d4a740601f..c49ffe710e 100644 --- a/src/Symfony/Bundle/Resources/config/json_schema.xml +++ b/src/Symfony/Bundle/Resources/config/json_schema.xml @@ -16,7 +16,7 @@ - null + From b415fd17eaaa534902191c9231dead8c48cbeeb0 Mon Sep 17 00:00:00 2001 From: soyuka Date: Thu, 9 Jan 2025 16:08:10 +0100 Subject: [PATCH 09/16] Revert "fix(laravel): restore accidentally removed BooleanFilter (#6881)" This reverts commit 5e1a6e11e33486f76c4ded7bf7bcb108c65a7de6. --- src/Laravel/ApiPlatformProvider.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Laravel/ApiPlatformProvider.php b/src/Laravel/ApiPlatformProvider.php index 90ce2d6a02..d0f064f508 100644 --- a/src/Laravel/ApiPlatformProvider.php +++ b/src/Laravel/ApiPlatformProvider.php @@ -427,7 +427,6 @@ public function register(): void $this->app->bind(OperationMetadataFactoryInterface::class, OperationMetadataFactory::class); $this->app->tag([ - BooleanFilter::class, EqualsFilter::class, PartialSearchFilter::class, DateFilter::class, From ccd2a1544324b84e0a0f57d78c7c8f9479933196 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Thu, 9 Jan 2025 16:16:11 +0100 Subject: [PATCH 10/16] chore: lint for php-cs-fixer 3.66.0 compatibility (#6902) --- src/State/ProcessorInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/State/ProcessorInterface.php b/src/State/ProcessorInterface.php index 8bfa0c49b0..5d676e16ae 100644 --- a/src/State/ProcessorInterface.php +++ b/src/State/ProcessorInterface.php @@ -29,8 +29,8 @@ interface ProcessorInterface /** * Handles the state. * - * @param T1 $data - * @param array $uriVariables + * @param T1 $data + * @param array $uriVariables * @param array&array{request?: Request, previous_data?: mixed, resource_class?: string|null, original_data?: mixed} $context * * @return T2 From 05cbd0f3d8048e8bab3c29e64f7a0a9c8b33c8d7 Mon Sep 17 00:00:00 2001 From: ziming Date: Fri, 10 Jan 2025 17:06:43 +0800 Subject: [PATCH 11/16] chore(laravel): phpstan/phpdoc-parser ^2.0, larastan ^3.0 (#6900) Co-authored-by: soyuka --- src/Laravel/Eloquent/Filter/DateFilter.php | 5 ++++- src/Laravel/Eloquent/Filter/OrFilter.php | 2 +- src/Laravel/Eloquent/Filter/OrderFilter.php | 5 ++++- src/Laravel/Eloquent/Filter/RangeFilter.php | 5 ++++- src/Laravel/Eloquent/Paginator.php | 2 +- src/Laravel/Eloquent/PartialPaginator.php | 2 +- src/Laravel/Routing/IriConverter.php | 2 +- src/Laravel/Routing/SkolemIriConverter.php | 2 +- .../Tests/Console/Maker/MakeStateProcessorCommandTest.php | 2 +- .../Tests/Console/Maker/MakeStateProviderCommandTest.php | 2 +- src/Laravel/composer.json | 4 ++-- 11 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Laravel/Eloquent/Filter/DateFilter.php b/src/Laravel/Eloquent/Filter/DateFilter.php index 67665dce87..29903f50d4 100644 --- a/src/Laravel/Eloquent/Filter/DateFilter.php +++ b/src/Laravel/Eloquent/Filter/DateFilter.php @@ -84,7 +84,10 @@ public function getSchema(Parameter $parameter): array return ['type' => 'date']; } - public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null + /** + * @return OpenApiParameter[] + */ + public function getOpenApiParameters(Parameter $parameter): array { $in = $parameter instanceof QueryParameter ? 'query' : 'header'; $key = $parameter->getKey(); diff --git a/src/Laravel/Eloquent/Filter/OrFilter.php b/src/Laravel/Eloquent/Filter/OrFilter.php index 6c9e7f833b..609608cb92 100644 --- a/src/Laravel/Eloquent/Filter/OrFilter.php +++ b/src/Laravel/Eloquent/Filter/OrFilter.php @@ -49,7 +49,7 @@ public function getSchema(Parameter $parameter): array return ['type' => 'array', 'items' => $schema]; } - public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null + public function getOpenApiParameters(Parameter $parameter): OpenApiParameter { return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true); } diff --git a/src/Laravel/Eloquent/Filter/OrderFilter.php b/src/Laravel/Eloquent/Filter/OrderFilter.php index 90315f3d08..233356d48b 100644 --- a/src/Laravel/Eloquent/Filter/OrderFilter.php +++ b/src/Laravel/Eloquent/Filter/OrderFilter.php @@ -54,7 +54,10 @@ public function getSchema(Parameter $parameter): array return ['type' => 'string', 'enum' => ['asc', 'desc']]; } - public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null + /** + * @return OpenApiParameter[]|null + */ + public function getOpenApiParameters(Parameter $parameter): ?array { if (str_contains($parameter->getKey(), ':property')) { $parameters = []; diff --git a/src/Laravel/Eloquent/Filter/RangeFilter.php b/src/Laravel/Eloquent/Filter/RangeFilter.php index 82f7e4457e..bb86f7dc78 100644 --- a/src/Laravel/Eloquent/Filter/RangeFilter.php +++ b/src/Laravel/Eloquent/Filter/RangeFilter.php @@ -52,7 +52,10 @@ public function getSchema(Parameter $parameter): array return ['type' => 'number']; } - public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null + /** + * @return OpenApiParameter[] + */ + public function getOpenApiParameters(Parameter $parameter): array { $in = $parameter instanceof QueryParameter ? 'query' : 'header'; $key = $parameter->getKey(); diff --git a/src/Laravel/Eloquent/Paginator.php b/src/Laravel/Eloquent/Paginator.php index 77784ce6c7..feabdf2eaa 100644 --- a/src/Laravel/Eloquent/Paginator.php +++ b/src/Laravel/Eloquent/Paginator.php @@ -34,7 +34,7 @@ public function __construct( public function count(): int { - return $this->paginator->count(); + return $this->paginator->count(); // @phpstan-ignore-line } public function getLastPage(): float diff --git a/src/Laravel/Eloquent/PartialPaginator.php b/src/Laravel/Eloquent/PartialPaginator.php index e8dd57aae8..e193d9cfc6 100644 --- a/src/Laravel/Eloquent/PartialPaginator.php +++ b/src/Laravel/Eloquent/PartialPaginator.php @@ -33,7 +33,7 @@ public function __construct( public function count(): int { - return $this->paginator->count(); + return $this->paginator->count(); // @phpstan-ignore-line } public function getCurrentPage(): float diff --git a/src/Laravel/Routing/IriConverter.php b/src/Laravel/Routing/IriConverter.php index cc9ab93a49..ad1e6f1b78 100644 --- a/src/Laravel/Routing/IriConverter.php +++ b/src/Laravel/Routing/IriConverter.php @@ -159,7 +159,7 @@ private function generateRoute(object|string $resource, int $referenceType = Url if (\is_object($resource)) { try { $identifiers = $this->identifiersExtractor->getIdentifiersFromItem($resource, $identifiersExtractorOperation, $context); - } catch (InvalidArgumentException|RuntimeException $e) { + } catch (RuntimeException $e) { // We can try using context uri variables if any if (!$identifiers) { throw new InvalidArgumentException(\sprintf('Unable to generate an IRI for the item of type "%s"', $operation->getClass()), $e->getCode(), $e); diff --git a/src/Laravel/Routing/SkolemIriConverter.php b/src/Laravel/Routing/SkolemIriConverter.php index 6aa7f16f6c..fcb6779853 100644 --- a/src/Laravel/Routing/SkolemIriConverter.php +++ b/src/Laravel/Routing/SkolemIriConverter.php @@ -53,7 +53,7 @@ public function getResourceFromIri(string $iri, array $context = [], ?Operation /** * {@inheritdoc} */ - public function getIriFromResource(object|string $resource, int $referenceType = UrlGeneratorInterface::ABS_PATH, ?Operation $operation = null, array $context = []): ?string + public function getIriFromResource(object|string $resource, int $referenceType = UrlGeneratorInterface::ABS_PATH, ?Operation $operation = null, array $context = []): string { $referenceType = $operation ? ($operation->getUrlGenerationStrategy() ?? $referenceType) : $referenceType; if (($isObject = \is_object($resource)) && $this->objectHashMap->contains($resource)) { diff --git a/src/Laravel/Tests/Console/Maker/MakeStateProcessorCommandTest.php b/src/Laravel/Tests/Console/Maker/MakeStateProcessorCommandTest.php index c51b5de1fc..fcb05239fc 100644 --- a/src/Laravel/Tests/Console/Maker/MakeStateProcessorCommandTest.php +++ b/src/Laravel/Tests/Console/Maker/MakeStateProcessorCommandTest.php @@ -30,7 +30,7 @@ class MakeStateProcessorCommandTest extends TestCase /** @var string */ private const CHOSEN_CLASS_NAME = 'Choose a class name for your state processor (e.g. AwesomeStateProcessor)'; - private ?Filesystem $filesystem; + private Filesystem $filesystem; private PathResolver $pathResolver; private AppServiceFileGenerator $appServiceFileGenerator; diff --git a/src/Laravel/Tests/Console/Maker/MakeStateProviderCommandTest.php b/src/Laravel/Tests/Console/Maker/MakeStateProviderCommandTest.php index c259c79fa3..f7d8c8e8e5 100644 --- a/src/Laravel/Tests/Console/Maker/MakeStateProviderCommandTest.php +++ b/src/Laravel/Tests/Console/Maker/MakeStateProviderCommandTest.php @@ -30,7 +30,7 @@ class MakeStateProviderCommandTest extends TestCase /** @var string */ private const STATE_PROVIDER_CLASS_NAME = 'Choose a class name for your state provider (e.g. AwesomeStateProvider)'; - private ?Filesystem $filesystem; + private Filesystem $filesystem; private PathResolver $pathResolver; private AppServiceFileGenerator $appServiceFileGenerator; diff --git a/src/Laravel/composer.json b/src/Laravel/composer.json index 65c1ef6be1..ae78d72179 100644 --- a/src/Laravel/composer.json +++ b/src/Laravel/composer.json @@ -49,12 +49,12 @@ "illuminate/container": "^11.0", "symfony/web-link": "^6.4 || ^7.1", "willdurand/negotiation": "^3.1", - "phpstan/phpdoc-parser": "^1.29", + "phpstan/phpdoc-parser": "^1.29 || ^2.0", "phpdocumentor/reflection-docblock": "^5.1" }, "require-dev": { "doctrine/dbal": "^4.0", - "larastan/larastan": "^2.0", + "larastan/larastan": "^2.0 || ^3.0", "orchestra/testbench": "^9.1", "phpunit/phpunit": "^11.2", "api-platform/graphql": "^4.0", From b12a0d005fda58a162b82a3574e6ee877838a55b Mon Sep 17 00:00:00 2001 From: Tobias Oitzinger <42447585+toitzi@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:30:13 +0100 Subject: [PATCH 12/16] fix(graphql): register types for parameter args (#6895) --- src/GraphQl/Type/FieldsBuilder.php | 10 +++++++- src/Laravel/Tests/GraphQlTest.php | 37 ++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/GraphQl/Type/FieldsBuilder.php b/src/GraphQl/Type/FieldsBuilder.php index 0952929981..6c41959518 100644 --- a/src/GraphQl/Type/FieldsBuilder.php +++ b/src/GraphQl/Type/FieldsBuilder.php @@ -415,7 +415,15 @@ private function getResourceFieldConfiguration(?string $property, ?string $field } $args = $this->getFilterArgs($args, $resourceClass, $rootResource, $resourceOperation, $rootOperation, $property, $depth); - $args = $this->getParameterArgs($rootOperation, $args); + + // Also register parameter args in the types container + // Note: This is a workaround, for more information read the comment on the parameterToObjectType function. + foreach ($this->getParameterArgs($rootOperation) as $key => $arg) { + if ($arg instanceof InputObjectType || (\is_array($arg) && isset($arg['name']))) { + $this->typesContainer->set(\is_array($arg) ? $arg['name'] : $arg->name(), $arg); + } + $args[$key] = $arg; + } } } diff --git a/src/Laravel/Tests/GraphQlTest.php b/src/Laravel/Tests/GraphQlTest.php index 571573cc6c..e296bfb1ff 100644 --- a/src/Laravel/Tests/GraphQlTest.php +++ b/src/Laravel/Tests/GraphQlTest.php @@ -79,20 +79,37 @@ public function testGetBooksWithSimplePagination(): void public function testGetBooksWithPaginationAndOrder(): void { - BookFactory::new()->has(AuthorFactory::new())->count(10)->create(); - $response = $this->postJson('/api/graphql', ['query' => '{ - books(first: 3, order: {name: "desc"}) { - edges { - node { - id, name, publicationDate, author { id, name } - } - } - } -}'], ['accept' => ['application/json']]); + // Create books in reverse alphabetical order to test the 'asc' order + BookFactory::new() + ->count(10) + ->sequence(fn ($sequence) => ['name' => \chr(122 - $sequence->index)]) // ASCII codes starting from 'z' + ->has(AuthorFactory::new()) + ->create(); + + $response = $this->postJson('/api/graphql', [ + 'query' => ' + query getBooks($first: Int!, $order: orderBookcollection_query!) { + books(first: $first, order: $order) { + edges { + node { + id, name, publicationDate, author { id, name } + } + } + } + } + ', + 'variables' => [ + 'first' => 3, + 'order' => ['name' => 'asc'], + ], + ], ['accept' => ['application/json']]); $response->assertStatus(200); $data = $response->json(); $this->assertArrayHasKey('data', $data); $this->assertCount(3, $data['data']['books']['edges']); + $this->assertEquals('q', $data['data']['books']['edges'][0]['node']['name']); + $this->assertEquals('r', $data['data']['books']['edges'][1]['node']['name']); + $this->assertEquals('s', $data['data']['books']['edges'][2]['node']['name']); $this->assertArrayNotHasKey('errors', $data); } From 0cf752bcec692718b2503250e655d05aea670316 Mon Sep 17 00:00:00 2001 From: wuchen90 Date: Fri, 10 Jan 2025 11:33:02 +0100 Subject: [PATCH 13/16] fix(metadata): make the schema attribute to fallback to null for parameters in YamlResourceExtractor (#6896) --- src/Metadata/Extractor/YamlResourceExtractor.php | 2 +- .../Tests/Extractor/Adapter/XmlResourceAdapter.php | 10 ++++++++-- src/Metadata/Tests/Extractor/Adapter/resources.xml | 2 +- src/Metadata/Tests/Extractor/Adapter/resources.yaml | 3 +++ .../Extractor/ResourceMetadataCompatibilityTest.php | 5 ++++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Metadata/Extractor/YamlResourceExtractor.php b/src/Metadata/Extractor/YamlResourceExtractor.php index 8bbb03bed6..3083818658 100644 --- a/src/Metadata/Extractor/YamlResourceExtractor.php +++ b/src/Metadata/Extractor/YamlResourceExtractor.php @@ -471,7 +471,7 @@ private function buildParameters(array $resource): ?array $parameters[$key] = new $cl( key: $key, required: $this->phpize($parameter, 'required', 'bool'), - schema: $parameter['schema'], + schema: $parameter['schema'] ?? null, openApi: ($parameter['openapi'] ?? null) ? new Parameter( name: $parameter['openapi']['name'], in: $parameter['in'] ?? 'query', diff --git a/src/Metadata/Tests/Extractor/Adapter/XmlResourceAdapter.php b/src/Metadata/Tests/Extractor/Adapter/XmlResourceAdapter.php index 4a2acbbb06..0b302606fa 100644 --- a/src/Metadata/Tests/Extractor/Adapter/XmlResourceAdapter.php +++ b/src/Metadata/Tests/Extractor/Adapter/XmlResourceAdapter.php @@ -533,8 +533,14 @@ private function buildParameters(\SimpleXMLElement $resource, ?array $values = n $childNode = $node->addChild('parameter'); $childNode->addAttribute('in', 'query'); $childNode->addAttribute('key', $key); - $childNode->addAttribute('required', $this->parse($value['required'])); - $this->buildValues($childNode->addChild('schema'), $value['schema']); + + if (\array_key_exists('required', $value)) { + $childNode->addAttribute('required', $this->parse($value['required'])); + } + + if (\array_key_exists('schema', $value)) { + $this->buildValues($childNode->addChild('schema'), $value['schema']); + } } } diff --git a/src/Metadata/Tests/Extractor/Adapter/resources.xml b/src/Metadata/Tests/Extractor/Adapter/resources.xml index 45b012242b..65eebd8c97 100644 --- a/src/Metadata/Tests/Extractor/Adapter/resources.xml +++ b/src/Metadata/Tests/Extractor/Adapter/resources.xml @@ -1,3 +1,3 @@ -someirischemaanotheririschemaCommentapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetapplication/merge-patch+json+ldapplication/merge-patch+json+ld_foo\d+bazhttps
60120AuthorizationAccept-LanguageAcceptcomment:read_collectioncomment:writebazbazbazbarcomment.another_custom_filteruserIdLorem ipsum dolor sit ametDolor sit ametbarstringapplication/vnd.ms-excelapplication/merge-patch+jsonapplication/merge-patch+jsonpouet\d+barhttphttps60120AuthorizationAccept-Languagecomment:readcomment:writecomment:custombazbazbazbarcomment.custom_filterfoobarcustombazcustomquxcomment:read_collectioncomment:writebarcomment.another_custom_filteruserIdLorem ipsum dolor sit ametDolor sit ametbar/v1/v1Lorem ipsum dolor sit ametDolor sit amet/v1Lorem ipsum dolor sit ametDolor sit amet/v1Lorem ipsum dolor sit ametDolor sit ametLorem ipsum dolor sit ametDolor sit amet +someirischemaanotheririschemaCommentapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetapplication/merge-patch+json+ldapplication/merge-patch+json+ld_foo\d+bazhttps
60120AuthorizationAccept-LanguageAcceptcomment:read_collectioncomment:writebazbazbazbarcomment.another_custom_filteruserIdLorem ipsum dolor sit ametDolor sit ametbarstringapplication/vnd.ms-excelapplication/merge-patch+jsonapplication/merge-patch+jsonpouet\d+barhttphttps60120AuthorizationAccept-Languagecomment:readcomment:writecomment:custombazbazbazbarcomment.custom_filterfoobarcustombazcustomquxcomment:read_collectioncomment:writebarcomment.another_custom_filteruserIdLorem ipsum dolor sit ametDolor sit ametbar/v1/v1Lorem ipsum dolor sit ametDolor sit amet/v1Lorem ipsum dolor sit ametDolor sit amet/v1Lorem ipsum dolor sit ametDolor sit ametLorem ipsum dolor sit ametDolor sit amet diff --git a/src/Metadata/Tests/Extractor/Adapter/resources.yaml b/src/Metadata/Tests/Extractor/Adapter/resources.yaml index 2c9e21b1c5..08dbaa8082 100644 --- a/src/Metadata/Tests/Extractor/Adapter/resources.yaml +++ b/src/Metadata/Tests/Extractor/Adapter/resources.yaml @@ -139,6 +139,9 @@ resources: - rel: 'http://www.w3.org/ns/json-ld#error' href: 'http://www.w3.org/ns/hydra/error' + parameters: + date: + key: date formats: json: null jsonld: null diff --git a/src/Metadata/Tests/Extractor/ResourceMetadataCompatibilityTest.php b/src/Metadata/Tests/Extractor/ResourceMetadataCompatibilityTest.php index 030f754e90..116ce821ac 100644 --- a/src/Metadata/Tests/Extractor/ResourceMetadataCompatibilityTest.php +++ b/src/Metadata/Tests/Extractor/ResourceMetadataCompatibilityTest.php @@ -442,6 +442,9 @@ final class ResourceMetadataCompatibilityTest extends TestCase 'links' => [ ['rel' => 'http://www.w3.org/ns/json-ld#error', 'href' => 'http://www.w3.org/ns/hydra/error'], ], + 'parameters' => [ + 'date' => ['key' => 'date'], + ], ], ], ], @@ -761,7 +764,7 @@ private function withParameters(array $values): ?array $parameters = []; foreach ($values as $k => $value) { - $parameters[$k] = new QueryParameter(key: $value['key'], required: $value['required'], schema: $value['schema']); + $parameters[$k] = new QueryParameter(key: $value['key'] ?? $k, required: $value['required'] ?? null, schema: $value['schema'] ?? null); } return $parameters; From 42f0ace3a95c386bbf4dfbdcc331f343969fe815 Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 10 Jan 2025 15:18:44 +0100 Subject: [PATCH 14/16] docs: v3.4.11 changelog --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b26dc32fa2..e0af0d4fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v3.4.11 + +### Bug fixes + +* [0cf752bce](https://github.com/api-platform/core/commit/0cf752bcec692718b2503250e655d05aea670316) fix(metadata): make the schema attribute to fallback to null for parameters in YamlResourceExtractor (#6896) +* [2b3c55db2](https://github.com/api-platform/core/commit/2b3c55db2a9ecc52f62c441fa8a5696233a30b87) fix(symfony): remove unsolvable deprecation (#6899) see also (#6655) +* [9493b9b6e](https://github.com/api-platform/core/commit/9493b9b6ec0264ab5b700c861ad1b97455b4f88d) fix(symfony): revert json schema bc break (#6903) +* [b82f9ac76](https://github.com/api-platform/core/commit/b82f9ac76ce89dd3910849c73da42317ee1339ed) fix(openapi): not forbidden response on openAPI doc (#6886) + ## v3.4.10 ### Bug fixes @@ -2689,4 +2698,4 @@ Please read #2825 if you have issues with the behavior of Readable/Writable Link ## 1.0.0 beta 2 * Preserve indexes when normalizing and denormalizing associative arrays -* Allow setting default order for property when registering a `Doctrine\Orm\Filter\OrderFilter` instance \ No newline at end of file +* Allow setting default order for property when registering a `Doctrine\Orm\Filter\OrderFilter` instance From a6b84610364b4782eea85a21286d79e0d4e07152 Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 10 Jan 2025 15:26:40 +0100 Subject: [PATCH 15/16] docs: v4.0.14 changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 827c3eb5bb..4772c7d3a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v4.0.14 + +### Bug fixes + +* [97cdb6b3f](https://github.com/api-platform/core/commit/97cdb6b3f43471789e096c9dc3a0c3c7b6d4e43c) fix(state): remove ProcessorInterface laravel specific type +* [b12a0d005](https://github.com/api-platform/core/commit/b12a0d005fda58a162b82a3574e6ee877838a55b) fix(graphql): register types for parameter args (#6895) + +### Features + ## v4.0.13 ### Bug fixes From 9b073807219eb474e743f82aca64c1b089c6b03d Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 10 Jan 2025 15:33:49 +0100 Subject: [PATCH 16/16] docs: v3.4.14 changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0af0d4fec..74cac432ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## v3.4.11 +## v3.4.14 ### Bug fixes @@ -9,6 +9,9 @@ * [9493b9b6e](https://github.com/api-platform/core/commit/9493b9b6ec0264ab5b700c861ad1b97455b4f88d) fix(symfony): revert json schema bc break (#6903) * [b82f9ac76](https://github.com/api-platform/core/commit/b82f9ac76ce89dd3910849c73da42317ee1339ed) fix(openapi): not forbidden response on openAPI doc (#6886) +I mispublished a v3.4.13 on some repositories to fix them all I bumped 3.4.10 to 3.4.14 +More details at #6888. + ## v3.4.10 ### Bug fixes