Skip to content

Commit dd4cca5

Browse files
committed
Ensure that a #[GQL\Arg] on method has a matching parameter
1 parent f990e0b commit dd4cca5

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

src/Config/Parser/MetadataParser/MetadataParser.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use ReflectionClassConstant;
2020
use ReflectionException;
2121
use ReflectionMethod;
22+
use ReflectionParameter;
2223
use ReflectionProperty;
2324
use Reflector;
2425
use RuntimeException;
@@ -565,6 +566,8 @@ private static function getTypeFieldConfigurationFromReflector(ReflectionClass $
565566
$accessMetadata = self::getFirstMetadataMatching($metadatas, Metadata\Access::class);
566567
$publicMetadata = self::getFirstMetadataMatching($metadatas, Metadata\IsPublic::class);
567568

569+
$isMethod = $reflector instanceof ReflectionMethod;
570+
568571
if (null === $fieldMetadata) {
569572
if (null !== $accessMetadata || null !== $publicMetadata) {
570573
throw new InvalidArgumentException(sprintf('The metadatas %s and/or %s defined on "%s" are only usable in addition of metadata %s', self::formatMetadata('Access'), self::formatMetadata('Visible'), $reflector->getName(), self::formatMetadata('Field')));
@@ -573,7 +576,7 @@ private static function getTypeFieldConfigurationFromReflector(ReflectionClass $
573576
return [];
574577
}
575578

576-
if ($reflector instanceof ReflectionMethod && !$reflector->isPublic()) {
579+
if ($isMethod && !$reflector->isPublic()) {
577580
throw new InvalidArgumentException(sprintf('The metadata %s can only be applied to public method. The method "%s" is not public.', self::formatMetadata('Field'), $reflector->getName()));
578581
}
579582

@@ -591,7 +594,13 @@ private static function getTypeFieldConfigurationFromReflector(ReflectionClass $
591594
/** @var Metadata\Arg[] $argAnnotations */
592595
$argAnnotations = self::getMetadataMatching($metadatas, Metadata\Arg::class);
593596

597+
$validArgNames = array_map(fn (ReflectionParameter $parameter) => $parameter->getName(), $isMethod ? $reflector->getParameters() : []);
598+
594599
foreach ($argAnnotations as $arg) {
600+
if ($isMethod && !in_array($arg->name, $validArgNames, true)) {
601+
throw new InvalidArgumentException(sprintf('The argument "%s" defined with #[GQL\Arg] attribute/annotation on method "%s" does not match any parameter name in the method.', $arg->name, $reflector->getName()));
602+
}
603+
595604
$args[$arg->name] = ['type' => $arg->type];
596605

597606
if (isset($arg->description)) {
@@ -606,7 +615,7 @@ private static function getTypeFieldConfigurationFromReflector(ReflectionClass $
606615
}
607616
}
608617

609-
if ($reflector instanceof ReflectionMethod) {
618+
if ($isMethod) {
610619
$args = self::guessArgs($reflectionClass, $reflector, $args);
611620
}
612621

tests/Config/Parser/MetadataParserTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,18 @@ public function testInvalidParamGuessing(): void
524524
}
525525
}
526526

527+
public function testInvalidArgumentMatching(): void
528+
{
529+
try {
530+
$file = __DIR__.'/fixtures/annotations/Invalid/InvalidArgumentNaming.php';
531+
$this->parser('parse', new SplFileInfo($file), $this->containerBuilder, $this->parserConfig);
532+
$this->fail('Missing matching argument should have raise an exception');
533+
} catch (Exception $e) {
534+
$this->assertInstanceOf(InvalidArgumentException::class, $e);
535+
$this->assertMatchesRegularExpression('/The argument "missingParameter" defined/', $e->getPrevious()->getMessage());
536+
}
537+
}
538+
527539
public function testInvalidReturnGuessing(): void
528540
{
529541
try {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Overblog\GraphQLBundle\Tests\Config\Parser\fixtures\annotations\Invalid;
6+
7+
use Overblog\GraphQLBundle\Annotation as GQL;
8+
9+
/**
10+
* @GQL\Type
11+
*/
12+
#[GQL\Type]
13+
final class InvalidArgumentNaming
14+
{
15+
/**
16+
* @GQL\Field(name="guessFailed")
17+
*
18+
* @GQL\Arg(name="missingParameter", type="String")
19+
*
20+
* @param mixed $test
21+
*/
22+
#[GQL\Field(name: 'guessFailed')]
23+
#[GQL\Arg(name: 'missingParameter', type: 'String')]
24+
public function guessFail(int $test): int
25+
{
26+
return 12;
27+
}
28+
}

0 commit comments

Comments
 (0)