From 48f95788204bee73908bd57941ceb98cf5e12677 Mon Sep 17 00:00:00 2001 From: Yurii Kuvshynov <141632421+fogrye@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:23:42 +0100 Subject: [PATCH 1/4] fix: replace doctrine annotations with attributes --- phpcs.xml.dist | 2 +- src/Annotations/Assertion.php | 33 ++++++++++++------- src/Mappers/Parameters/ParameterValidator.php | 10 ++++++ tests/Annotations/AssertionTest.php | 13 ++++---- tests/ConstraintValidationExceptionTest.php | 5 +-- tests/Fixtures/Controllers/UserController.php | 22 ++++--------- .../InvalidControllers/InvalidController.php | 8 ++--- tests/Fixtures/Types/User.php | 24 +++++--------- tests/IntegrationTest.php | 27 +++++++-------- tests/ValidationFailedExceptionTest.php | 15 ++++----- 10 files changed, 79 insertions(+), 80 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 7f81a06..4c9e021 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -11,7 +11,7 @@ src - + tests diff --git a/src/Annotations/Assertion.php b/src/Annotations/Assertion.php index c0810da..51bc4ea 100644 --- a/src/Annotations/Assertion.php +++ b/src/Annotations/Assertion.php @@ -4,6 +4,7 @@ namespace TheCodingMachine\GraphQLite\Validator\Annotations; +use Attribute; use BadMethodCallException; use Symfony\Component\Validator\Constraint; use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotationInterface; @@ -21,26 +22,34 @@ * @Attribute("constraint", type = "Symfony\Component\Validator\Constraint[]|Symfony\Component\Validator\Constraint") * }) */ +#[Attribute(Attribute::TARGET_METHOD)] class Assertion implements ParameterAnnotationInterface { - /** @var string */ - private $for; + private string $for; /** @var Constraint[] */ - private $constraint; + private array $constraint; - /** @param array $values */ - public function __construct(array $values) - { - if (! isset($values['for'])) { - throw new BadMethodCallException('The @Assert annotation must be passed a target. For instance: "@Assert(for="$email", constraint=@Email)"'); + /** + * @param array $values + * @param Constraint[]|Constraint|null $constraint + */ + public function __construct( + array $values = [], + string|null $for = null, + array|Constraint|null $constraint = null, + ) { + $for = $for ?? $values['for'] ?? null; + $constraint = $constraint ?? $values['constraint'] ?? null; + if ($for === null) { + throw new BadMethodCallException('The Assert attribute must be passed a target. For instance: "#[Assert(for: "$email", constraint: new Email())"'); } - if (! isset($values['constraint'])) { - throw new BadMethodCallException('The @Assert annotation must be passed one or many constraints. For instance: "@Assert(for="$email", constraint=@Email)"'); + if ($constraint === null) { + throw new BadMethodCallException('The Assert attribute must be passed one or many constraints. For instance: "#[Assert(for: "$email", constraint: new Email())"'); } - $this->for = ltrim($values['for'], '$'); - $this->constraint = is_array($values['constraint']) ? $values['constraint'] : [$values['constraint']]; + $this->for = ltrim($for, '$'); + $this->constraint = is_array($constraint) ? $constraint : [$constraint]; } public function getTarget(): string diff --git a/src/Mappers/Parameters/ParameterValidator.php b/src/Mappers/Parameters/ParameterValidator.php index d328808..df60e7c 100644 --- a/src/Mappers/Parameters/ParameterValidator.php +++ b/src/Mappers/Parameters/ParameterValidator.php @@ -77,4 +77,14 @@ public function getDefaultValue(): mixed { return $this->parameter->getDefaultValue(); } + + public function getName(): string + { + return $this->parameter->getName(); + } + + public function getDescription(): string + { + return $this->parameter->getDescription(); + } } diff --git a/tests/Annotations/AssertionTest.php b/tests/Annotations/AssertionTest.php index 58a17a6..72d1e6a 100644 --- a/tests/Annotations/AssertionTest.php +++ b/tests/Annotations/AssertionTest.php @@ -1,5 +1,7 @@ expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @Assert annotation must be passed a target. For instance: "@Assert(for="$email", constraint=@Email)"'); + $this->expectExceptionMessage('The Assert attribute must be passed a target. For instance: "#[Assert(for: "$email", constraint: new Email())"'); new Assertion([]); } - public function testException2() + public function testException2(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @Assert annotation must be passed one or many constraints. For instance: "@Assert(for="$email", constraint=@Email)"'); - new Assertion(['for'=>'foo']); + $this->expectExceptionMessage('The Assert attribute must be passed one or many constraints. For instance: "#[Assert(for: "$email", constraint: new Email())"'); + new Assertion(['for' => 'foo']); } } diff --git a/tests/ConstraintValidationExceptionTest.php b/tests/ConstraintValidationExceptionTest.php index 00af664..3cf249e 100644 --- a/tests/ConstraintValidationExceptionTest.php +++ b/tests/ConstraintValidationExceptionTest.php @@ -1,5 +1,7 @@ 'baz'], null, null, 'invalidValue', null, 'myCode')); $this->assertSame(400, $exception->getCode()); diff --git a/tests/Fixtures/Controllers/UserController.php b/tests/Fixtures/Controllers/UserController.php index efe1140..8041f61 100644 --- a/tests/Fixtures/Controllers/UserController.php +++ b/tests/Fixtures/Controllers/UserController.php @@ -1,29 +1,24 @@ validator = $validator; } - /** - * @Mutation() - */ + #[Mutation] public function createUser(string $email, string $password): User { $user = new User($email, $password); @@ -38,13 +33,10 @@ public function createUser(string $email, string $password): User return $user; } - /** - * @Query - * @Assertion(for="email", constraint=@Assert\Email()) - */ + #[Query] + #[Assertion(for: '$email', constraint: new Assert\Email())] public function findByMail(string $email = 'a@a.com'): User { - $user = new User($email, 'foo'); - return $user; + return new User($email, 'foo'); } } diff --git a/tests/Fixtures/InvalidControllers/InvalidController.php b/tests/Fixtures/InvalidControllers/InvalidController.php index 4906655..428072d 100644 --- a/tests/Fixtures/InvalidControllers/InvalidController.php +++ b/tests/Fixtures/InvalidControllers/InvalidController.php @@ -1,9 +1,9 @@ password = $password; } - /** - * @Field() - */ + #[Field] public function getEmail(): string { return $this->email; } -} \ No newline at end of file +} diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index d92c04c..a9048ad 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -1,10 +1,9 @@ function(ContainerInterface $container) { + TranslatorInterface::class => static function (ContainerInterface $container) { return new Translator('fr_FR'); }, - ValidatorInterface::class => function(ContainerInterface $container) { + ValidatorInterface::class => static function (ContainerInterface $container) { $build = new ValidatorBuilder(); - $build->enableAnnotationMapping(); - $build->setDoctrineAnnotationReader(new AnnotationReader()); + $build->enableAttributeMapping(); $build->setTranslator($container->get(TranslatorInterface::class)); + return $build->getValidator(); }, - UserController::class => function(ContainerInterface $container) { + UserController::class => static function (ContainerInterface $container) { return new UserController($container->get(ValidatorInterface::class)); - } + }, ]); $schemaFactory = new SchemaFactory(new Psr16Cache(new ArrayAdapter()), new BasicAutoWiringContainer($container)); @@ -73,7 +72,7 @@ public function testEndToEndThrowException(): void $result = GraphQL::executeQuery( $schema, - $queryString + $queryString, ); $result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']); $result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']); @@ -102,7 +101,7 @@ public function testEndToEndAssert(): void $result = GraphQL::executeQuery( $schema, - $queryString + $queryString, ); $result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']); $result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']); @@ -114,7 +113,6 @@ public function testEndToEndAssert(): void $this->assertSame('email', $errors[0]['extensions']['field']); $this->assertSame('Validate', $errors[0]['extensions']['category']); - $queryString = ' { findByMail(email: "valid@valid.com") { @@ -125,7 +123,7 @@ public function testEndToEndAssert(): void $result = GraphQL::executeQuery( $schema, - $queryString + $queryString, ); $result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']); $result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']); @@ -144,14 +142,13 @@ public function testEndToEndAssert(): void $result = GraphQL::executeQuery( $schema, - $queryString + $queryString, ); $result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']); $result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']); $data = $result->toArray(DebugFlag::RETHROW_UNSAFE_EXCEPTIONS)['data']; $this->assertSame('a@a.com', $data['findByMail']['email']); - } public function testException(): void @@ -164,4 +161,4 @@ public function testException(): void $this->expectExceptionMessage('In method TheCodingMachine\GraphQLite\Validator\Fixtures\InvalidControllers\InvalidController::invalid(), the @Assert annotation is targeting parameter "$resolveInfo". You cannot target this parameter because it is not part of the GraphQL Input type. You can only assert parameters coming from the end user.'); $schema->validate(); } -} \ No newline at end of file +} diff --git a/tests/ValidationFailedExceptionTest.php b/tests/ValidationFailedExceptionTest.php index ff4882d..f993845 100644 --- a/tests/ValidationFailedExceptionTest.php +++ b/tests/ValidationFailedExceptionTest.php @@ -1,5 +1,7 @@ 'baz'], null, null, 'invalidValue') - ]); + $constraintViolationList = new ConstraintViolationList([new ConstraintViolation('foo', 'foo {bar}', ['bar' => 'baz'], null, null, 'invalidValue')]); $validationFailedException = new ValidationFailedException($constraintViolationList); @@ -24,15 +23,13 @@ public function testGetExceptions() $this->assertSame('foo', $exceptions[0]->getMessage()); } - public function testThrowException() + public function testThrowException(): void { $constraintViolationList = new ConstraintViolationList([]); ValidationFailedException::throwException($constraintViolationList); - $constraintViolationList = new ConstraintViolationList([ - new ConstraintViolation('foo', 'foo {bar}', ['bar' => 'baz'], null, null, 'invalidValue') - ]); + $constraintViolationList = new ConstraintViolationList([new ConstraintViolation('foo', 'foo {bar}', ['bar' => 'baz'], null, null, 'invalidValue')]); $this->expectException(ValidationFailedException::class); ValidationFailedException::throwException($constraintViolationList); From f50476be99c5e7bc02d2662da905df5929ade058 Mon Sep 17 00:00:00 2001 From: Yurii Kuvshynov <141632421+fogrye@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:24:06 +0100 Subject: [PATCH 2/4] chore: bump dependencies for symfony and graphqlite --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 59aa6ef..d68ed62 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,8 @@ ], "require" : { "php" : ">=8.1", - "thecodingmachine/graphqlite" : "^6.0", - "symfony/validator": "^6" , + "thecodingmachine/graphqlite" : "^6.0|^7.0", + "symfony/validator": "^6|^7", "doctrine/annotations": "^1.13 || ^2.0.1" }, "require-dev": { @@ -27,8 +27,8 @@ "mouf/picotainer": "^1.1", "phpstan/phpstan": "^1.8", "php-coveralls/php-coveralls": "^2.1.0", - "symfony/translation": "^6", - "doctrine/coding-standard": "^11.1" + "symfony/translation": "^6|^7", + "doctrine/coding-standard": "^11.1|^12.0" }, "scripts": { "phpstan": "phpstan analyse src/ -c phpstan.neon --level=7 --no-progress", From 3d48c7e86dc3c7b77df65e91b1fb630e0777c136 Mon Sep 17 00:00:00 2001 From: Yurii Kuvshynov <141632421+fogrye@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:19:08 +0100 Subject: [PATCH 3/4] chore: remove doctrine annotation BC: annotation support dropped, use attributes --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d68ed62..9d2f2fa 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,7 @@ "require" : { "php" : ">=8.1", "thecodingmachine/graphqlite" : "^6.0|^7.0", - "symfony/validator": "^6|^7", - "doctrine/annotations": "^1.13 || ^2.0.1" + "symfony/validator": "^6|^7" }, "require-dev": { "phpunit/phpunit": "^9.6.5", From eb0e0310435dcc01cce3f8351b99adbd15120e3a Mon Sep 17 00:00:00 2001 From: Yurii Kuvshynov <141632421+fogrye@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:14:17 +0200 Subject: [PATCH 4/4] chore: prepare for v7 --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 9d2f2fa..8e03244 100644 --- a/composer.json +++ b/composer.json @@ -18,15 +18,15 @@ ], "require" : { "php" : ">=8.1", - "thecodingmachine/graphqlite" : "^6.0|^7.0", - "symfony/validator": "^6|^7" + "thecodingmachine/graphqlite" : "^7.0", + "symfony/validator": "^7" }, "require-dev": { "phpunit/phpunit": "^9.6.5", "mouf/picotainer": "^1.1", "phpstan/phpstan": "^1.8", "php-coveralls/php-coveralls": "^2.1.0", - "symfony/translation": "^6|^7", + "symfony/translation": "^7", "doctrine/coding-standard": "^11.1|^12.0" }, "scripts": { @@ -47,7 +47,7 @@ }, "extra": { "branch-alias": { - "dev-master": "6.0.x-dev" + "dev-master": "7.0.x-dev" } }, "minimum-stability": "dev",