-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(graphql): New directive
@type
(#157)
- Loading branch information
Showing
23 changed files
with
617 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# `@type` | ||
|
||
Converts scalar into GraphQL Type. Similar to Lighthouse's `@scalar` directive, but uses Laravel Container to resolve instance and also supports PHP enums. | ||
|
||
[include:exec]: <../../../../dev/artisan dev:directive @type> | ||
[//]: # (start: 90e03adede767b669ea39c2e4de42431b0ee3405074a4297b01666628f98ca45) | ||
[//]: # (warning: Generated automatically. Do not edit.) | ||
|
||
```graphql | ||
""" | ||
Converts scalar into GraphQL Type. Similar to Lighthouse's `@scalar` | ||
directive, but uses Laravel Container to resolve instance and also | ||
supports PHP enums. | ||
""" | ||
directive @type( | ||
""" | ||
Reference to a PHP Class/Enum (FQN). | ||
If not PHP Enum, the Laravel Container with the following additional | ||
arguments will be used to resolver the instance: | ||
* `string $name` - the type name. | ||
* `GraphQL\Language\AST\ScalarTypeDefinitionNode $node` - the AST node. | ||
* `array&ScalarConfig $config` - the scalar configuration (if `GraphQL\Type\Definition\ScalarType`). | ||
Resolved instance must be an `GraphQL\Type\Definition\Type&GraphQL\Type\Definition\NamedType` and have a name equal | ||
to `$name` argument. | ||
""" | ||
class: String! | ||
) | ||
on | ||
| SCALAR | ||
``` | ||
|
||
[//]: # (end: 90e03adede767b669ea39c2e4de42431b0ee3405074a4297b01666628f98ca45) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 3 additions & 6 deletions
9
...ls/Definitions/LaraAspAsEnumDirective.php → .../Directives/Definitions/TypeDirective.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\GraphQL\Directives; | ||
|
||
use GraphQL\Language\AST\ScalarTypeDefinitionNode; | ||
use GraphQL\Type\Definition\EnumType; | ||
use GraphQL\Type\Definition\NamedType; | ||
use GraphQL\Type\Definition\PhpEnumType; | ||
use GraphQL\Type\Definition\ScalarType; | ||
use GraphQL\Type\Definition\Type as GraphQLType; | ||
use LastDragon_ru\LaraASP\Core\Application\ContainerResolver; | ||
use LastDragon_ru\LaraASP\Core\Utils\Cast; | ||
use Nuwave\Lighthouse\Exceptions\DefinitionException; | ||
use Nuwave\Lighthouse\Schema\DirectiveLocator; | ||
use Nuwave\Lighthouse\Schema\Directives\BaseDirective; | ||
use Nuwave\Lighthouse\Schema\Values\TypeValue; | ||
use Nuwave\Lighthouse\Support\Contracts\TypeResolver; | ||
use Override; | ||
use UnitEnum; | ||
|
||
use function is_a; | ||
|
||
/** | ||
* @phpstan-import-type ScalarConfig from ScalarType | ||
*/ | ||
class Type extends BaseDirective implements TypeResolver { | ||
final protected const ArgClass = 'class'; | ||
|
||
public function __construct( | ||
protected readonly ContainerResolver $container, | ||
) { | ||
// empty | ||
} | ||
|
||
#[Override] | ||
public static function definition(): string { | ||
$name = DirectiveLocator::directiveName(static::class); | ||
$argClass = self::ArgClass; | ||
$nodeClass = ScalarTypeDefinitionNode::class; | ||
$typeClass = GraphQLType::class.'&'.NamedType::class; | ||
$scalarClass = ScalarType::class; | ||
|
||
return <<<GRAPHQL | ||
""" | ||
Converts scalar into GraphQL Type. Similar to Lighthouse's `@scalar` | ||
directive, but uses Laravel Container to resolve instance and also | ||
supports PHP enums. | ||
""" | ||
directive @{$name}( | ||
""" | ||
Reference to a PHP Class/Enum (FQN). | ||
If not PHP Enum, the Laravel Container with the following additional | ||
arguments will be used to resolver the instance: | ||
* `string \$name` - the type name. | ||
* `{$nodeClass} \$node` - the AST node. | ||
* `array&ScalarConfig \$config` - the scalar configuration (if `{$scalarClass}`). | ||
Resolved instance must be an `{$typeClass}` and have a name equal | ||
to `\$name` argument. | ||
""" | ||
{$argClass}: String! | ||
) on SCALAR | ||
GRAPHQL; | ||
} | ||
|
||
/** | ||
* @return GraphQLType&NamedType | ||
*/ | ||
#[Override] | ||
public function resolveNode(TypeValue $value): GraphQLType { | ||
// Type? | ||
$class = Cast::toString($this->directiveArgValue(self::ArgClass)); | ||
$node = Cast::to(ScalarTypeDefinitionNode::class, $value->getTypeDefinition()); | ||
$name = $value->getTypeDefinitionName(); | ||
$type = match (true) { | ||
is_a($class, GraphQLType::class, true) && is_a($class, NamedType::class, true) | ||
=> $this->createType($name, $class, $node), | ||
is_a($class, UnitEnum::class, true) | ||
=> $this->createEnum($name, $class, $node), | ||
default | ||
=> null, | ||
}; | ||
|
||
if (!($type instanceof GraphQLType) || !($type instanceof NamedType)) { | ||
throw new DefinitionException( | ||
"The `{$class}` is not a GraphQL type (`scalar {$name}`).", | ||
); | ||
} elseif ($type->name() !== $name) { | ||
throw new DefinitionException( | ||
"The type name must be `{$name}`, `{$type->name()}` given (`scalar {$name}`).", | ||
); | ||
} else { | ||
// ok | ||
} | ||
|
||
// Return | ||
return $type; | ||
} | ||
|
||
/** | ||
* @param class-string<UnitEnum> $class | ||
*/ | ||
private function createEnum(string $name, string $class, ScalarTypeDefinitionNode $node): EnumType { | ||
return new PhpEnumType($class, $name); | ||
} | ||
|
||
/** | ||
* @param class-string<GraphQLType&NamedType> $class | ||
*/ | ||
private function createType(string $name, string $class, ScalarTypeDefinitionNode $node): object { | ||
$args = [ | ||
'name' => $name, | ||
'node' => $node, | ||
]; | ||
|
||
if (is_a($class, ScalarType::class, true)) { | ||
$args['config'] = $this->createTypeScalarConfig($name, $class, $node); | ||
} | ||
|
||
return $this->container->getInstance()->make($class, $args); | ||
} | ||
|
||
/** | ||
* @return ScalarConfig | ||
*/ | ||
private function createTypeScalarConfig(string $name, string $class, ScalarTypeDefinitionNode $node): array { | ||
return [ | ||
'name' => $name, | ||
'astNode' => $node, | ||
'description' => $node->description?->value, | ||
]; | ||
} | ||
} |
Oops, something went wrong.