Skip to content

Commit ba00217

Browse files
authored
Merge pull request #6 from moufmouf/datetime_typehint
Adding support for type-hinting against DateTime and DateTimeInterface
2 parents 71684fe + 321ef00 commit ba00217

File tree

6 files changed

+85
-8
lines changed

6 files changed

+85
-8
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class UserController
4444
}
4545
```
4646

47+
Your methods can type-hint against:
48+
49+
- int
50+
- string
51+
- bool
52+
- float
53+
- DateTimeImmutable or DateTimeInterface
54+
- an array
55+
- any object (if you provide an hydrator for the object type)
56+
4757
There is an additional support for authentication and authorization:
4858

4959
```php
@@ -65,7 +75,28 @@ class UserController
6575
}
6676
```
6777

78+
Type-hinting against arrays
79+
---------------------------
80+
81+
You can type-hint against arrays as long as you document the PHP-Doc correctly:
82+
83+
```php
84+
/**
85+
* @Query
86+
* @return User[] <=== we specify that the array is an array of User objects.
87+
*/
88+
public function users(int $limit, int $offset): array
89+
{
90+
// Some code that returns an array of "users".
91+
// This completely replaces the "resolve" method.
92+
}
93+
```
94+
95+
Type-hinting against objects
96+
----------------------------
6897

98+
When you specify an object type-hint, graphql-controllers will delegate the object creation to an hydrator.
99+
You must pass this hydrator in parameter when building the `ControllerQueryProvider`.
69100

70101
Troubleshooting
71102
---------------

src/ControllerQueryProvider.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
use phpDocumentor\Reflection\Type;
77
use phpDocumentor\Reflection\Types\Array_;
8+
use phpDocumentor\Reflection\Types\Boolean;
9+
use phpDocumentor\Reflection\Types\Float_;
810
use phpDocumentor\Reflection\Types\Mixed;
911
use phpDocumentor\Reflection\Types\Object_;
1012
use phpDocumentor\Reflection\Types\String_;
@@ -21,6 +23,9 @@
2123
use Youshido\GraphQL\Field\Field;
2224
use Youshido\GraphQL\Type\ListType\ListType;
2325
use Youshido\GraphQL\Type\NonNullType;
26+
use Youshido\GraphQL\Type\Scalar\BooleanType;
27+
use Youshido\GraphQL\Type\Scalar\DateTimeType;
28+
use Youshido\GraphQL\Type\Scalar\FloatType;
2429
use Youshido\GraphQL\Type\Scalar\IntType;
2530
use Youshido\GraphQL\Type\Scalar\StringType;
2631
use Youshido\GraphQL\Type\TypeInterface;
@@ -219,7 +224,18 @@ private function toGraphQlType(Type $type): TypeInterface
219224
return new IntType();
220225
} elseif ($type instanceof String_) {
221226
return new StringType();
227+
} elseif ($type instanceof Boolean) {
228+
return new BooleanType();
229+
} elseif ($type instanceof Float_) {
230+
return new FloatType();
222231
} elseif ($type instanceof Object_) {
232+
$fqcn = (string) $type->getFqsen();
233+
if ($fqcn === '\\DateTimeImmutable' || $fqcn === '\\DateTimeInterface') {
234+
return new DateTimeType();
235+
} elseif ($fqcn === '\\DateTime') {
236+
throw new GraphQLException('Type-hinting a parameter against DateTime is not allowed. Please use the DateTimeImmutable type instead.');
237+
}
238+
223239
return $this->typeMapper->mapClassToType(ltrim($type->getFqsen(), '\\'));
224240
} elseif ($type instanceof Array_) {
225241
return new ListType(new NonNullType($this->toGraphQlType($type->getValueType())));

src/GraphQLException.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\GraphQL\Controllers;
5+
6+
7+
class GraphQLException extends \RuntimeException
8+
{
9+
}

src/QueryField.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Youshido\GraphQL\Type\ListType\ListType;
1111
use Youshido\GraphQL\Type\NonNullType;
1212
use Youshido\GraphQL\Type\Object\AbstractObjectType;
13+
use Youshido\GraphQL\Type\Scalar\DateTimeType;
1314
use Youshido\GraphQL\Type\TypeInterface;
1415
use Youshido\GraphQL\Type\TypeMap;
1516

@@ -47,11 +48,15 @@ public function __construct(string $name, TypeInterface $type, array $arguments,
4748
if ($type instanceof ListType) {
4849
$subtype = $this->stripNonNullType($type->getItemType());
4950
$val = array_map(function ($item) use ($subtype) {
50-
if ($subtype->getKind() === TypeMap::KIND_OBJECT) {
51+
if ($subtype instanceof DateTimeType) {
52+
return new \DateTimeImmutable($item);
53+
} elseif ($subtype->getKind() === TypeMap::KIND_OBJECT) {
5154
return $this->hydrator->hydrate($item, $subtype);
5255
};
5356
return $item;
5457
}, $val);
58+
} elseif ($type instanceof DateTimeType) {
59+
$val = new \DateTimeImmutable($val);
5560
} elseif ($type->getKind() === TypeMap::KIND_OBJECT) {
5661
$val = $this->hydrator->hydrate($val, $type);
5762
}

tests/ControllerQueryProviderTest.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
use Youshido\GraphQL\Type\ListType\ListType;
1313
use Youshido\GraphQL\Type\NonNullType;
1414
use Youshido\GraphQL\Type\Object\ObjectType;
15+
use Youshido\GraphQL\Type\Scalar\BooleanType;
16+
use Youshido\GraphQL\Type\Scalar\DateTimeType;
17+
use Youshido\GraphQL\Type\Scalar\FloatType;
1518
use Youshido\GraphQL\Type\Scalar\IntType;
1619
use Youshido\GraphQL\Type\Scalar\StringType;
1720
use Youshido\GraphQL\Type\TypeInterface;
@@ -32,25 +35,34 @@ public function testQueryProvider()
3235
$usersQuery = $queries[0];
3336
$this->assertSame('test', $usersQuery->getName());
3437

35-
$this->assertCount(3, $usersQuery->getArguments());
38+
$this->assertCount(7, $usersQuery->getArguments());
3639
$this->assertInstanceOf(NonNullType::class, $usersQuery->getArgument('int')->getType());
3740
$this->assertInstanceOf(IntType::class, $usersQuery->getArgument('int')->getType()->getTypeOf());
3841
$this->assertInstanceOf(StringType::class, $usersQuery->getArgument('string')->getType());
3942
$this->assertInstanceOf(NonNullType::class, $usersQuery->getArgument('list')->getType());
4043
$this->assertInstanceOf(ListType::class, $usersQuery->getArgument('list')->getType()->getTypeOf());
4144
$this->assertInstanceOf(NonNullType::class, $usersQuery->getArgument('list')->getType()->getTypeOf()->getItemType());
4245
$this->assertInstanceOf(ObjectType::class, $usersQuery->getArgument('list')->getType()->getTypeOf()->getItemType()->getTypeOf());
46+
$this->assertInstanceOf(BooleanType::class, $usersQuery->getArgument('boolean')->getType());
47+
$this->assertInstanceOf(FloatType::class, $usersQuery->getArgument('float')->getType());
48+
$this->assertInstanceOf(DateTimeType::class, $usersQuery->getArgument('dateTimeImmutable')->getType());
49+
$this->assertInstanceOf(DateTimeType::class, $usersQuery->getArgument('dateTime')->getType());
4350
$this->assertSame('TestObject', $usersQuery->getArgument('list')->getType()->getTypeOf()->getItemType()->getTypeOf()->getName());
4451

4552
$mockResolveInfo = $this->createMock(ResolveInfo::class);
4653

4754
$result = $usersQuery->resolve('foo', ['int'=>42, 'string'=>'foo', 'list'=>[
48-
['test'=>42],
49-
['test'=>12],
50-
]], $mockResolveInfo);
55+
['test'=>42],
56+
['test'=>12],
57+
],
58+
'boolean'=>true,
59+
'float'=>4.2,
60+
'dateTimeImmutable'=>'2017-01-01 01:01:01',
61+
'dateTime'=>'2017-01-01 01:01:01'
62+
], $mockResolveInfo);
5163

5264
$this->assertInstanceOf(TestObject::class, $result);
53-
$this->assertSame('foo424212', $result->getTest());
65+
$this->assertSame('foo424212true4.22017010101010120170101010101', $result->getTest());
5466
}
5567

5668
public function testMutations()

tests/Fixtures/TestController.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@ class TestController
1515
* @param int $int
1616
* @param null|string $string
1717
* @param TestObject[] $list
18+
* @param bool|null $boolean
19+
* @param float|null $float
20+
* @param \DateTimeImmutable|null $dateTimeImmutable
21+
* @param \DateTime|null $dateTime
1822
* @return TestObject
1923
*/
20-
public function test(int $int, ?string $string, array $list): TestObject
24+
public function test(int $int, ?string $string, array $list, ?bool $boolean, ?float $float, ?\DateTimeImmutable $dateTimeImmutable, ?\DateTimeInterface $dateTime): TestObject
2125
{
2226
$str = '';
2327
foreach ($list as $test) {
@@ -26,7 +30,7 @@ public function test(int $int, ?string $string, array $list): TestObject
2630
}
2731
$str .= $test->getTest();
2832
}
29-
return new TestObject($string.$int.$str);
33+
return new TestObject($string.$int.$str.($boolean?'true':'false').$float.$dateTimeImmutable->format('YmdHis').$dateTime->format('YmdHis'));
3034
}
3135

3236
/**

0 commit comments

Comments
 (0)