diff --git a/composer.json b/composer.json index ea1bce3..0dd224e 100644 --- a/composer.json +++ b/composer.json @@ -18,17 +18,16 @@ ], "require" : { "php" : ">=8.1", - "thecodingmachine/graphqlite" : "^6.0 || ^7.0", - "symfony/validator": "^6" , - "doctrine/annotations": "^1.13 || ^2.0.1" + "thecodingmachine/graphqlite" : "^7.0", + "symfony/validator": "^7" }, "require-dev": { "phpunit/phpunit": "^9.6.5 || ^10.0.0", "mouf/picotainer": "^1.1", "phpstan/phpstan": "^1.8", "php-coveralls/php-coveralls": "^2.1.0", - "symfony/translation": "^6", - "doctrine/coding-standard": "^11.1 || ^12.0" + "symfony/translation": "^7", + "doctrine/coding-standard": "^11.1|^12.0" }, "scripts": { "phpstan": "phpstan analyse src/ -c phpstan.neon --level=7 --no-progress", @@ -48,7 +47,7 @@ }, "extra": { "branch-alias": { - "dev-master": "6.0.x-dev" + "dev-master": "7.0.x-dev" } }, "minimum-stability": "dev", 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);