Skip to content

Commit a4bafbd

Browse files
authored
Merge pull request #9 from moufmouf/default_values
Default values on controller methods are now honored
2 parents 0575c0b + 7ffdeee commit a4bafbd

File tree

5 files changed

+82
-27
lines changed

5 files changed

+82
-27
lines changed

src/ControllerQueryProvider.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use phpDocumentor\Reflection\Types\Array_;
88
use phpDocumentor\Reflection\Types\Boolean;
99
use phpDocumentor\Reflection\Types\Float_;
10-
use phpDocumentor\Reflection\Types\Mixed;
10+
use phpDocumentor\Reflection\Types\Mixed_;
1111
use phpDocumentor\Reflection\Types\Object_;
1212
use phpDocumentor\Reflection\Types\String_;
1313
use Roave\BetterReflection\Reflection\ReflectionClass;
@@ -156,6 +156,7 @@ private function isAuthorized(\ReflectionMethod $reflectionMethod) : bool
156156
* @param ReflectionMethod $refMethod
157157
* @param \ReflectionMethod $standardRefMethod
158158
* @return array
159+
* @throws MissingTypeHintException
159160
*/
160161
private function mapParameters(ReflectionMethod $refMethod, \ReflectionMethod $standardRefMethod)
161162
{
@@ -167,9 +168,24 @@ private function mapParameters(ReflectionMethod $refMethod, \ReflectionMethod $s
167168
$allowsNull = $standardParameter->allowsNull();
168169
$parameter = $refMethod->getParameter($standardParameter->getName());
169170

170-
$phpdocType = $typeResolver->resolve((string) $parameter->getType());
171+
$type = (string) $parameter->getType();
172+
if ($type === '') {
173+
throw MissingTypeHintException::missingTypeHint($parameter);
174+
}
175+
$phpdocType = $typeResolver->resolve($type);
176+
177+
$arr = [
178+
'type' => $this->mapType($phpdocType, $parameter->getDocBlockTypes(), $allowsNull, true),
179+
];
180+
181+
if ($standardParameter->allowsNull()) {
182+
$arr['default'] = null;
183+
}
184+
if ($standardParameter->isDefaultValueAvailable()) {
185+
$arr['default'] = $standardParameter->getDefaultValue();
186+
}
171187

172-
$args[$parameter->getName()] = $this->mapType($phpdocType, $parameter->getDocBlockTypes(), $allowsNull, true);
188+
$args[$parameter->getName()] = $arr;
173189
}
174190

175191
return $args;
@@ -184,7 +200,7 @@ private function mapType(Type $type, array $docBlockTypes, bool $isNullable, boo
184200
{
185201
$graphQlType = null;
186202

187-
if ($type instanceof Array_ || $type instanceof Mixed) {
203+
if ($type instanceof Array_ || $type instanceof Mixed_) {
188204
if (!$isNullable) {
189205
// Let's check a "null" value in the docblock
190206
$isNullable = $this->isNullable($docBlockTypes);

src/MissingTypeHintException.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
namespace TheCodingMachine\GraphQL\Controllers;
3+
4+
use Roave\BetterReflection\Reflection\ReflectionParameter;
5+
6+
class MissingTypeHintException extends GraphQLException
7+
{
8+
public static function missingTypeHint(ReflectionParameter $parameter)
9+
{
10+
return new self(sprintf('Parameter "%s" of method "%s::%s" is missing a type-hint', $parameter->getName(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName()));
11+
}
12+
}

src/QueryField.php

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,36 @@ public function __construct(string $name, TypeInterface $type, array $arguments,
3535
$config = [
3636
'name' => $name,
3737
'type' => $type,
38-
'args' => $arguments
38+
'args' => array_map(function(array $item) { return $item['type']; }, $arguments)
3939
];
4040

4141
$config['resolve'] = function ($source, array $args, ResolveInfo $info) use ($resolve, $arguments) {
4242
$toPassArgs = [];
43-
foreach ($arguments as $name => $type) {
44-
// FIXME: this is not ok for default values! We need to take the default value of the reflected argument.
45-
$val = $args[$name] ?? null;
43+
foreach ($arguments as $name => $arr) {
44+
$type = $arr['type'];
45+
if (isset($args[$name])) {
46+
$val = $args[$name];
4647

47-
$type = $this->stripNonNullType($type);
48-
if ($type instanceof ListType) {
49-
$subtype = $this->stripNonNullType($type->getItemType());
50-
$val = array_map(function ($item) use ($subtype) {
51-
if ($subtype instanceof DateTimeType) {
52-
return new \DateTimeImmutable($item);
53-
} elseif ($subtype->getKind() === TypeMap::KIND_INPUT_OBJECT) {
54-
return $this->hydrator->hydrate($item, $subtype);
55-
};
56-
return $item;
57-
}, $val);
58-
} elseif ($type instanceof DateTimeType) {
59-
$val = new \DateTimeImmutable($val);
60-
} elseif ($type->getKind() === TypeMap::KIND_INPUT_OBJECT) {
61-
$val = $this->hydrator->hydrate($val, $type);
48+
$type = $this->stripNonNullType($type);
49+
if ($type instanceof ListType) {
50+
$subtype = $this->stripNonNullType($type->getItemType());
51+
$val = array_map(function ($item) use ($subtype) {
52+
if ($subtype instanceof DateTimeType) {
53+
return new \DateTimeImmutable($item);
54+
} elseif ($subtype->getKind() === TypeMap::KIND_INPUT_OBJECT) {
55+
return $this->hydrator->hydrate($item, $subtype);
56+
};
57+
return $item;
58+
}, $val);
59+
} elseif ($type instanceof DateTimeType) {
60+
$val = new \DateTimeImmutable($val);
61+
} elseif ($type->getKind() === TypeMap::KIND_INPUT_OBJECT) {
62+
$val = $this->hydrator->hydrate($val, $type);
63+
}
64+
} elseif (isset($arr['default'])) {
65+
$val = $arr['default'];
66+
} else {
67+
throw new GraphQLException("Expected argument '$name' was not provided.");
6268
}
6369

6470
$toPassArgs[] = $val;

tests/ControllerQueryProviderTest.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Youshido\GraphQL\Type\Scalar\IntType;
2020
use Youshido\GraphQL\Type\Scalar\StringType;
2121
use Youshido\GraphQL\Type\TypeInterface;
22+
use TheCodingMachine\GraphQL\Controllers\Annotations\Query;
2223

2324
class ControllerQueryProviderTest extends AbstractQueryProviderTest
2425
{
@@ -35,7 +36,7 @@ public function testQueryProvider()
3536
$usersQuery = $queries[0];
3637
$this->assertSame('test', $usersQuery->getName());
3738

38-
$this->assertCount(7, $usersQuery->getArguments());
39+
$this->assertCount(8, $usersQuery->getArguments());
3940
$this->assertInstanceOf(NonNullType::class, $usersQuery->getArgument('int')->getType());
4041
$this->assertInstanceOf(IntType::class, $usersQuery->getArgument('int')->getType()->getTypeOf());
4142
$this->assertInstanceOf(StringType::class, $usersQuery->getArgument('string')->getType());
@@ -62,7 +63,7 @@ public function testQueryProvider()
6263
], $mockResolveInfo);
6364

6465
$this->assertInstanceOf(TestObject::class, $result);
65-
$this->assertSame('foo424212true4.22017010101010120170101010101', $result->getTest());
66+
$this->assertSame('foo424212true4.22017010101010120170101010101default', $result->getTest());
6667
}
6768

6869
public function testMutations()
@@ -85,4 +86,24 @@ public function testMutations()
8586
$this->assertInstanceOf(TestObject::class, $result);
8687
$this->assertEquals('42', $result->getTest());
8788
}
89+
90+
public function testErrors()
91+
{
92+
$controller = new class {
93+
/**
94+
* @Query
95+
* @return string
96+
*/
97+
public function test($noTypeHint): string
98+
{
99+
return 'foo';
100+
}
101+
};
102+
$reader = new AnnotationReader();
103+
104+
$queryProvider = new ControllerQueryProvider($controller, $reader, $this->getTypeMapper(), $this->getHydrator(), new VoidAuthenticationService(), new VoidAuthorizationService());
105+
106+
$this->expectException(MissingTypeHintException::class);
107+
$queryProvider->getQueries();
108+
}
88109
}

tests/Fixtures/TestController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class TestController
2121
* @param \DateTime|null $dateTime
2222
* @return TestObject
2323
*/
24-
public function test(int $int, ?string $string, array $list, ?bool $boolean, ?float $float, ?\DateTimeImmutable $dateTimeImmutable, ?\DateTimeInterface $dateTime): TestObject
24+
public function test(int $int, ?string $string, array $list, ?bool $boolean, ?float $float, ?\DateTimeImmutable $dateTimeImmutable, ?\DateTimeInterface $dateTime, string $withDefault = 'default'): TestObject
2525
{
2626
$str = '';
2727
foreach ($list as $test) {
@@ -30,7 +30,7 @@ public function test(int $int, ?string $string, array $list, ?bool $boolean, ?fl
3030
}
3131
$str .= $test->getTest();
3232
}
33-
return new TestObject($string.$int.$str.($boolean?'true':'false').$float.$dateTimeImmutable->format('YmdHis').$dateTime->format('YmdHis'));
33+
return new TestObject($string.$int.$str.($boolean?'true':'false').$float.$dateTimeImmutable->format('YmdHis').$dateTime->format('YmdHis').$withDefault);
3434
}
3535

3636
/**

0 commit comments

Comments
 (0)