Skip to content

Commit 04818f2

Browse files
authored
Merge pull request overblog#735 from bartv2/patch-2
Fix Input Field annotations handling
2 parents fe69991 + bc36e3e commit 04818f2

File tree

6 files changed

+92
-11
lines changed

6 files changed

+92
-11
lines changed

docs/annotations/index.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,27 @@ In the previous example, the generated `resolve` config of the `something` field
116116

117117
## Type & Args auto-guessing
118118

119+
### @Field type auto-guessing when defined on a property with a type hint
120+
121+
The type of the `@Field` annotation can be auto-guessed if it's defined on a property with a type hint.
122+
If the property has a usable type hint this is used and no futher guessing is done.
123+
124+
For example:
125+
126+
```php
127+
/**
128+
* @GQL\Type
129+
*/
130+
class MyType {
131+
/**
132+
* @GQL\Field
133+
*/
134+
protected string $property;
135+
}
136+
```
137+
138+
In this example, the type `String!` will be auto-guessed from the type hint of the property.
139+
119140
### @Field type auto-guessing from Doctrine ORM Annotations
120141

121142
Based on other Doctrine annotations on your fields, the corresponding GraphQL type can sometimes be guessed automatically.

src/Config/Parser/AnnotationParser.php

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ private static function getTypeFieldConfigurationFromReflector(GraphClass $graph
585585
}
586586
} else {
587587
try {
588-
$fieldConfiguration['type'] = self::guessType($graphClass, $annotations);
588+
$fieldConfiguration['type'] = self::guessType($graphClass, $reflector, self::VALID_OUTPUT_TYPES);
589589
} catch (Exception $e) {
590590
throw new InvalidArgumentException(sprintf('The attribute "type" on "@%s" defined on "%s" is required and cannot be auto-guessed : %s.', $fieldAnnotationName, $reflector->getName(), $e->getMessage()));
591591
}
@@ -622,16 +622,29 @@ private static function getGraphQLInputFieldsFromAnnotations(GraphClass $graphCl
622622
foreach ($reflectors as $reflector) {
623623
$annotations = $graphClass->getAnnotations($reflector);
624624

625-
/** @var GQL\Field $fieldAnnotation */
625+
/** @var GQL\Field|null $fieldAnnotation */
626626
$fieldAnnotation = self::getFirstAnnotationMatching($annotations, GQL\Field::class);
627627

628+
// No field annotation found
629+
if (null === $fieldAnnotation) {
630+
continue;
631+
}
632+
628633
// Ignore field with resolver when the type is an Input
629634
if (isset($fieldAnnotation->resolve)) {
630635
return [];
631636
}
632637

633638
$fieldName = $reflector->getName();
634-
$fieldType = $fieldAnnotation->type;
639+
if (isset($fieldAnnotation->type)) {
640+
$fieldType = $fieldAnnotation->type;
641+
} else {
642+
try {
643+
$fieldType = self::guessType($graphClass, $reflector, self::VALID_INPUT_TYPES);
644+
} catch (Exception $e) {
645+
throw new InvalidArgumentException(sprintf('The attribute "type" on GraphQL annotation "@%s" is missing on property "%s" and cannot be auto-guessed as there is no type hint or Doctrine annotation.', GQL\Field::class, $reflector->getName()));
646+
}
647+
}
635648
$fieldConfiguration = [];
636649
if ($fieldType) {
637650
// Resolve a PHP class from a GraphQL type
@@ -839,8 +852,17 @@ private static function suffixName(string $name, string $suffix): string
839852
*
840853
* @throws RuntimeException
841854
*/
842-
private static function guessType(GraphClass $graphClass, array $annotations): string
855+
private static function guessType(GraphClass $graphClass, ReflectionProperty $reflector, array $filterGraphQLTypes = []): string
843856
{
857+
if ($reflector->hasType()) {
858+
try {
859+
// @phpstan-ignore-next-line
860+
return self::resolveGraphQLTypeFromReflectionType($reflector->getType(), $filterGraphQLTypes);
861+
} catch (Exception $e) {
862+
}
863+
}
864+
865+
$annotations = $graphClass->getAnnotations($reflector);
844866
$columnAnnotation = self::getFirstAnnotationMatching($annotations, Column::class);
845867
if (null !== $columnAnnotation) {
846868
$type = self::resolveTypeFromDoctrineType($columnAnnotation->type);

tests/Config/Parser/AnnotationParserTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ public function testInput(): void
188188
'fields' => [
189189
'name' => ['type' => 'String!'],
190190
'population' => ['type' => 'Int!'],
191+
'description' => ['type' => 'String!'],
192+
'diameter' => ['type' => 'Int'],
193+
'variable' => ['type' => 'Int!'],
194+
'tags' => ['type' => '[String]!'],
191195
],
192196
]);
193197
}

tests/Config/Parser/fixtures/annotations/Input/Planet.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Overblog\GraphQLBundle\Tests\Config\Parser\fixtures\annotations\Input;
66

7+
use Doctrine\ORM\Mapping as ORM;
78
use Overblog\GraphQLBundle\Annotation as GQL;
89

910
/**
@@ -21,4 +22,31 @@ class Planet
2122
* @GQL\Field(type="Int!")
2223
*/
2324
protected string $population;
25+
26+
/**
27+
* @GQL\Field
28+
*/
29+
protected string $description;
30+
31+
/**
32+
* @GQL\Field
33+
* @ORM\Column(type="integer", nullable=true)
34+
*/
35+
// @phpstan-ignore-next-line
36+
protected $diameter;
37+
38+
/**
39+
* @GQL\Field
40+
* @ORM\Column(type="boolean")
41+
*/
42+
protected int $variable;
43+
44+
// @phpstan-ignore-next-line
45+
protected $dummy;
46+
47+
/**
48+
* @GQL\Field
49+
* @ORM\Column(type="text[]")
50+
*/
51+
protected array $tags;
2452
}

tests/Config/Parser/fixtures/annotations/Type/Droid.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
class Droid extends Character
1414
{
1515
/**
16-
* @GQL\Field(type="Int!")
16+
* @GQL\Field
1717
*/
1818
protected int $memory;
1919
}

tests/Config/Parser/fixtures/annotations/Type/Lightsaber.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,44 @@ class Lightsaber
2323
* @ORM\Column(type="integer", nullable=true)
2424
* @GQL\Field
2525
*/
26-
protected int $size;
26+
// @phpstan-ignore-next-line
27+
protected $size;
2728

2829
/**
2930
* @ORM\OneToMany(targetEntity="Hero")
3031
* @GQL\Field
3132
*/
32-
protected Hero $holders;
33+
// @phpstan-ignore-next-line
34+
protected $holders;
3335

3436
/**
3537
* @ORM\ManyToOne(targetEntity="Hero")
3638
* @GQL\Field
3739
*/
38-
protected Hero $creator;
40+
// @phpstan-ignore-next-line
41+
protected $creator;
3942

4043
/**
4144
* @ORM\OneToOne(targetEntity="Crystal")
4245
* @GQL\Field
4346
*/
44-
protected Crystal $crystal;
47+
// @phpstan-ignore-next-line
48+
protected $crystal;
4549

4650
/**
4751
* @ORM\ManyToMany(targetEntity="Battle")
4852
* @GQL\Field
4953
*/
50-
protected Battle $battles;
54+
// @phpstan-ignore-next-line
55+
protected $battles;
5156

5257
/**
5358
* @GQL\Field
5459
* @ORM\OneToOne(targetEntity="Hero")
5560
* @ORM\JoinColumn(nullable=true)
5661
*/
57-
protected Hero $currentHolder;
62+
// @phpstan-ignore-next-line
63+
protected $currentHolder;
5864

5965
/**
6066
* @GQL\Field

0 commit comments

Comments
 (0)