jerowork /
graphql-attribute-schema
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Jerowork\GraphqlAttributeSchema\NodeParser; |
||
| 6 | |||
| 7 | use Generator; |
||
| 8 | use Jerowork\GraphqlAttributeSchema\Attribute\Mutation; |
||
| 9 | use Jerowork\GraphqlAttributeSchema\Node\MutationNode; |
||
| 10 | use Jerowork\GraphqlAttributeSchema\Node\TypeReference\ConnectionTypeReference; |
||
| 11 | use Jerowork\GraphqlAttributeSchema\NodeParser\Child\MethodArgumentsNodeParser; |
||
| 12 | use Jerowork\GraphqlAttributeSchema\Type\Connection\Connection; |
||
| 13 | use Override; |
||
| 14 | use ReflectionClass; |
||
| 15 | use ReflectionMethod; |
||
| 16 | use ReflectionNamedType; |
||
| 17 | use Stringable; |
||
| 18 | |||
| 19 | /** |
||
| 20 | * @internal |
||
| 21 | */ |
||
| 22 | final readonly class MutationNodeParser implements NodeParser |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 23 | { |
||
| 24 | use RetrieveNameForFieldTrait; |
||
| 25 | use GetAttributeTrait; |
||
| 26 | |||
| 27 | private const array ALLOWED_SCALAR_TYPES_FOR_DEFERRED_TYPE_LOADER = ['string', 'int', 'array']; |
||
| 28 | |||
| 29 | 8 | public function __construct( |
|
| 30 | private TypeReferenceDecider $typeReferenceDecider, |
||
| 31 | private MethodArgumentsNodeParser $methodArgumentsNodeParser, |
||
| 32 | 8 | ) {} |
|
| 33 | |||
| 34 | 6 | #[Override] |
|
| 35 | public function parse(string $attribute, ReflectionClass $class, ?ReflectionMethod $method): Generator |
||
| 36 | { |
||
| 37 | 6 | if ($attribute !== Mutation::class) { |
|
| 38 | 3 | return; |
|
| 39 | } |
||
| 40 | |||
| 41 | 5 | if ($method === null) { |
|
| 42 | throw new ParseException('Logic: Missing ReflectionMethod'); |
||
| 43 | } |
||
| 44 | |||
| 45 | 5 | $attribute = $this->getAttribute($method, Mutation::class); |
|
| 46 | 5 | $returnType = $method->getReturnType(); |
|
| 47 | |||
| 48 | 5 | $reference = $this->typeReferenceDecider->getTypeReference($returnType, $attribute); |
|
| 49 | |||
| 50 | 5 | if ($reference === null) { |
|
| 51 | 1 | throw ParseException::invalidReturnType($class->getName(), $method->getName()); |
|
| 52 | } |
||
| 53 | |||
| 54 | // When reference is ConnectionType, the mutation needs to have Connection as return type |
||
| 55 | 4 | if ($reference instanceof ConnectionTypeReference) { |
|
| 56 | 1 | if (!$returnType instanceof ReflectionNamedType || $returnType->getName() !== Connection::class) { |
|
| 57 | 1 | throw ParseException::invalidConnectionReturnType($class->getName(), $method->getName()); |
|
| 58 | } |
||
| 59 | } |
||
| 60 | |||
| 61 | // When it has a deferred type loader, the return type needs to be an integer, string or Stringable |
||
| 62 | 3 | if ($attribute->deferredTypeLoader !== null) { |
|
| 63 | if ($returnType === null) { |
||
| 64 | throw ParseException::missingDeferredTypeLoaderReturnType($class->getName(), $method->getName()); |
||
| 65 | } |
||
| 66 | |||
| 67 | if ($returnType instanceof ReflectionNamedType |
||
| 68 | && $returnType->isBuiltin() |
||
| 69 | && !in_array($returnType->getName(), self::ALLOWED_SCALAR_TYPES_FOR_DEFERRED_TYPE_LOADER, true) |
||
| 70 | ) { |
||
| 71 | throw ParseException::invalidDeferredTypeLoaderReturnType($class->getName(), $method->getName()); |
||
| 72 | } |
||
| 73 | |||
| 74 | if (!$returnType instanceof Stringable) { |
||
| 75 | throw ParseException::invalidDeferredTypeLoaderReturnType($class->getName(), $method->getName()); |
||
| 76 | } |
||
| 77 | } |
||
| 78 | |||
| 79 | 3 | yield new MutationNode( |
|
| 80 | 3 | $class->getName(), |
|
| 81 | 3 | $this->retrieveNameForField($method, $attribute), |
|
| 82 | 3 | $attribute->description, |
|
| 83 | 3 | array_values([...$this->methodArgumentsNodeParser->parse($method)]), |
|
| 84 | 3 | $reference, |
|
| 85 | 3 | $method->getName(), |
|
| 86 | 3 | $attribute->deprecationReason, |
|
| 87 | 3 | $attribute->deferredTypeLoader, |
|
| 88 | 3 | ); |
|
| 89 | } |
||
| 90 | } |
||
| 91 |