Skip to content

Commit

Permalink
Merge pull request #70 from fogrye/master
Browse files Browse the repository at this point in the history
Support of graphqlite 7 and symfony 7
  • Loading branch information
nguyenk authored Apr 13, 2024
2 parents 433380b + f469df2 commit 2f677f6
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 86 deletions.
11 changes: 5 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -48,7 +47,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "6.0.x-dev"
"dev-master": "7.0.x-dev"
}
},
"minimum-stability": "dev",
Expand Down
2 changes: 1 addition & 1 deletion phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<!-- Directories to be checked -->
<file>src</file>
<!-- <file>tests</file> -->
<file>tests</file>

<!-- Include full Doctrine Coding Standard -->
<rule ref="Doctrine">
Expand Down
33 changes: 21 additions & 12 deletions src/Annotations/Assertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace TheCodingMachine\GraphQLite\Validator\Annotations;

use Attribute;
use BadMethodCallException;
use Symfony\Component\Validator\Constraint;
use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotationInterface;
Expand All @@ -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<string, mixed> $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<string, mixed> $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
Expand Down
10 changes: 10 additions & 0 deletions src/Mappers/Parameters/ParameterValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
13 changes: 7 additions & 6 deletions tests/Annotations/AssertionTest.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Validator\Annotations;

use BadMethodCallException;
use PHPUnit\Framework\TestCase;

class AssertionTest extends TestCase
{

public function testException1()
public function testException1(): void
{
$this->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']);
}
}
5 changes: 3 additions & 2 deletions tests/ConstraintValidationExceptionTest.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Validator;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\ConstraintViolation;

class ConstraintValidationExceptionTest extends TestCase
{

public function testException()
public function testException(): void
{
$exception = new ConstraintViolationException(new ConstraintViolation('foo', 'foo {bar}', ['bar' => 'baz'], null, null, 'invalidValue', null, 'myCode'));
$this->assertSame(400, $exception->getCode());
Expand Down
22 changes: 7 additions & 15 deletions tests/Fixtures/Controllers/UserController.php
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Validator\Fixtures\Controllers;


use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use TheCodingMachine\GraphQLite\Annotations\Mutation;
use TheCodingMachine\GraphQLite\Annotations\Query;
use TheCodingMachine\GraphQLite\Validator\Fixtures\Types\User;
use TheCodingMachine\GraphQLite\Validator\Annotations\Assertion;
use TheCodingMachine\GraphQLite\Validator\Fixtures\Types\User;
use TheCodingMachine\GraphQLite\Validator\ValidationFailedException;

class UserController
{
private $validator;

public function __construct(ValidatorInterface $validator)
public function __construct(private ValidatorInterface $validator)
{
$this->validator = $validator;
}

/**
* @Mutation()
*/
#[Mutation]
public function createUser(string $email, string $password): User
{
$user = new User($email, $password);
Expand All @@ -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 = '[email protected]'): User
{
$user = new User($email, 'foo');
return $user;
return new User($email, 'foo');
}
}
8 changes: 3 additions & 5 deletions tests/Fixtures/InvalidControllers/InvalidController.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Validator\Fixtures\InvalidControllers;


use GraphQL\Type\Definition\ResolveInfo;
use Symfony\Component\Validator\Constraints as Assert;
use TheCodingMachine\GraphQLite\Annotations\Query;
use TheCodingMachine\GraphQLite\Validator\Annotations\Assertion;

class InvalidController
{
/**
* @Query
* @Assertion(for="$resolveInfo", constraint=@Assert\Email())
*/
#[Query]
#[Assertion(for: '$resolveInfo', constraint: new Assert\Email())]
public function invalid(ResolveInfo $resolveInfo): string
{
return 'foo';
Expand Down
24 changes: 9 additions & 15 deletions tests/Fixtures/Types/User.php
Original file line number Diff line number Diff line change
@@ -1,40 +1,34 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Validator\Fixtures\Types;

use Symfony\Component\Validator\Constraints as Assert;
use TheCodingMachine\GraphQLite\Annotations\Field;
use TheCodingMachine\GraphQLite\Annotations\Type;

/**
* @Type()
*/
#[Type]
class User
{
/**
* @Assert\Email(
* message = "The email '{{ value }}' is not a valid email."
* )
*/
private $email;
#[Assert\Email(message: "The email '{{ value }}' is not a valid email.")]
private string $email;

/**
* The NotCompromisedPassword assertion asks the "HaveIBeenPawned" service if your password has already leaked or not.
* @Assert\Length(min=8)
*/
private $password;
#[Assert\Length(min: 8)]
private string $password;

public function __construct(string $email, string $password)
{
$this->email = $email;
$this->password = $password;
}

/**
* @Field()
*/
#[Field]
public function getEmail(): string
{
return $this->email;
}
}
}
27 changes: 12 additions & 15 deletions tests/IntegrationTest.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Validator;


use Doctrine\Common\Annotations\AnnotationReader;
use GraphQL\Error\DebugFlag;
use GraphQL\GraphQL;
use GraphQL\Type\Schema;
Expand All @@ -30,19 +29,19 @@ class IntegrationTest extends TestCase
private function getSchemaFactory(): SchemaFactory
{
$container = new Picotainer([
TranslatorInterface::class => 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));
Expand Down Expand Up @@ -73,7 +72,7 @@ public function testEndToEndThrowException(): void

$result = GraphQL::executeQuery(
$schema,
$queryString
$queryString,
);
$result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']);
$result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']);
Expand Down Expand Up @@ -102,7 +101,7 @@ public function testEndToEndAssert(): void

$result = GraphQL::executeQuery(
$schema,
$queryString
$queryString,
);
$result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']);
$result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']);
Expand All @@ -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: "[email protected]") {
Expand All @@ -125,7 +123,7 @@ public function testEndToEndAssert(): void

$result = GraphQL::executeQuery(
$schema,
$queryString
$queryString,
);
$result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']);
$result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']);
Expand All @@ -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('[email protected]', $data['findByMail']['email']);

}

public function testException(): void
Expand All @@ -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();
}
}
}
Loading

0 comments on commit 2f677f6

Please sign in to comment.