Skip to content

Commit 750ec00

Browse files
committed
✨ Support for using attribute as a target to parameter. Deprecate using as a target to the method. Add warning about next major release changes
Refs: thecodingmachine/graphqlite#708 (comment)
1 parent 2f677f6 commit 750ec00

File tree

5 files changed

+94
-20
lines changed

5 files changed

+94
-20
lines changed

src/Annotations/Assertion.php

+15-7
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,21 @@
1515
/**
1616
* Use this annotation to validate a parameter for a query or mutation.
1717
*
18+
* Note 1: using this attribute as a target to the method (not parameter) is deprecated and will be removed in 8.0.
19+
* Note 2: support for `doctrine/annotations` will be removed in 8.0.
20+
* Note 3: this class won't implement `ParameterAnnotationInterface` in 8.0.
21+
*
1822
* @Annotation
1923
* @Target({"METHOD"})
2024
* @Attributes({
2125
* @Attribute("for", type = "string"),
2226
* @Attribute("constraint", type = "Symfony\Component\Validator\Constraint[]|Symfony\Component\Validator\Constraint")
2327
* })
2428
*/
25-
#[Attribute(Attribute::TARGET_METHOD)]
29+
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)]
2630
class Assertion implements ParameterAnnotationInterface
2731
{
28-
private string $for;
32+
private ?string $for = null;
2933
/** @var Constraint[] */
3034
private array $constraint;
3135

@@ -40,20 +44,24 @@ public function __construct(
4044
) {
4145
$for = $for ?? $values['for'] ?? null;
4246
$constraint = $constraint ?? $values['constraint'] ?? null;
43-
if ($for === null) {
44-
throw new BadMethodCallException('The Assert attribute must be passed a target. For instance: "#[Assert(for: "$email", constraint: new Email())"');
45-
}
4647

4748
if ($constraint === null) {
48-
throw new BadMethodCallException('The Assert attribute must be passed one or many constraints. For instance: "#[Assert(for: "$email", constraint: new Email())"');
49+
throw new BadMethodCallException('The Assertion attribute must be passed one or many constraints. For instance: "#[Assertion(constraint: new Email())"');
4950
}
5051

51-
$this->for = ltrim($for, '$');
5252
$this->constraint = is_array($constraint) ? $constraint : [$constraint];
53+
54+
if (null !== $for) {
55+
$this->for = ltrim($for, '$');
56+
}
5357
}
5458

5559
public function getTarget(): string
5660
{
61+
if ($this->for === null) {
62+
throw new BadMethodCallException('The Assertion attribute must be passed a target. For instance: "#[Assertion(for: "$email", constraint: new Email())"');
63+
}
64+
5765
return $this->for;
5866
}
5967

tests/Annotations/AssertionTest.php

+1-8
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,10 @@
99

1010
class AssertionTest extends TestCase
1111
{
12-
public function testException1(): void
13-
{
14-
$this->expectException(BadMethodCallException::class);
15-
$this->expectExceptionMessage('The Assert attribute must be passed a target. For instance: "#[Assert(for: "$email", constraint: new Email())"');
16-
new Assertion([]);
17-
}
18-
1912
public function testException2(): void
2013
{
2114
$this->expectException(BadMethodCallException::class);
22-
$this->expectExceptionMessage('The Assert attribute must be passed one or many constraints. For instance: "#[Assert(for: "$email", constraint: new Email())"');
15+
$this->expectExceptionMessage('The Assertion attribute must be passed one or many constraints. For instance: "#[Assertion(constraint: new Email())"');
2316
new Assertion(['for' => 'foo']);
2417
}
2518
}

tests/Fixtures/Controllers/UserController.php

+10-1
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,17 @@ public function createUser(string $email, string $password): User
3535

3636
#[Query]
3737
#[Assertion(for: '$email', constraint: new Assert\Email())]
38-
public function findByMail(string $email = '[email protected]'): User
38+
public function findByMailTargetMethod(string $email = '[email protected]'): User
3939
{
40+
// deprecated way of using the Assertion annotation - as a target of the method
41+
return new User($email, 'foo');
42+
}
43+
44+
#[Query]
45+
public function findByMail(
46+
#[Assertion(constraint: new Assert\Email())]
47+
string $email = '[email protected]',
48+
): User {
4049
return new User($email, 'foo');
4150
}
4251
}

tests/Fixtures/InvalidControllers/InvalidController.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
class InvalidController
1313
{
1414
#[Query]
15-
#[Assertion(for: '$resolveInfo', constraint: new Assert\Email())]
16-
public function invalid(ResolveInfo $resolveInfo): string
17-
{
15+
public function invalid(
16+
#[Assertion(for: '$resolveInfo', constraint: new Assert\Email())]
17+
ResolveInfo $resolveInfo,
18+
): string {
1819
return 'foo';
1920
}
2021
}

tests/IntegrationTest.php

+64-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ public function testEndToEndAssert(): void
108108

109109
$errors = $result->toArray(DebugFlag::RETHROW_UNSAFE_EXCEPTIONS)['errors'];
110110

111-
// TODO: find why message is not in French...
112111
$this->assertSame('This value is not a valid email address.', $errors[0]['message']);
113112
$this->assertSame('email', $errors[0]['extensions']['field']);
114113
$this->assertSame('Validate', $errors[0]['extensions']['category']);
@@ -151,6 +150,70 @@ public function testEndToEndAssert(): void
151150
$this->assertSame('[email protected]', $data['findByMail']['email']);
152151
}
153152

153+
public function testEndToEndAssertForDeprecatedWay(): void
154+
{
155+
$schema = $this->getSchema();
156+
$schema->assertValid();
157+
158+
$queryString = '
159+
{
160+
findByMailTargetMethod(email: "notvalid") {
161+
email
162+
}
163+
}
164+
';
165+
166+
$result = GraphQL::executeQuery(
167+
$schema,
168+
$queryString,
169+
);
170+
$result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']);
171+
$result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']);
172+
173+
$errors = $result->toArray(DebugFlag::RETHROW_UNSAFE_EXCEPTIONS)['errors'];
174+
175+
$this->assertSame('This value is not a valid email address.', $errors[0]['message']);
176+
$this->assertSame('email', $errors[0]['extensions']['field']);
177+
$this->assertSame('Validate', $errors[0]['extensions']['category']);
178+
179+
$queryString = '
180+
{
181+
findByMailTargetMethod(email: "[email protected]") {
182+
email
183+
}
184+
}
185+
';
186+
187+
$result = GraphQL::executeQuery(
188+
$schema,
189+
$queryString,
190+
);
191+
$result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']);
192+
$result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']);
193+
194+
$data = $result->toArray(DebugFlag::RETHROW_UNSAFE_EXCEPTIONS)['data'];
195+
$this->assertSame('[email protected]', $data['findByMailTargetMethod']['email']);
196+
197+
// Test default parameter
198+
$queryString = '
199+
{
200+
findByMailTargetMethod {
201+
email
202+
}
203+
}
204+
';
205+
206+
$result = GraphQL::executeQuery(
207+
$schema,
208+
$queryString,
209+
);
210+
$result->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']);
211+
$result->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']);
212+
213+
$data = $result->toArray(DebugFlag::RETHROW_UNSAFE_EXCEPTIONS)['data'];
214+
$this->assertSame('[email protected]', $data['findByMailTargetMethod']['email']);
215+
}
216+
154217
public function testException(): void
155218
{
156219
$schemaFactory = $this->getSchemaFactory();

0 commit comments

Comments
 (0)