From b4194892ad7f17a7cec3a5c944cee880105d4414 Mon Sep 17 00:00:00 2001 From: Christopher Moore Date: Sat, 24 Mar 2018 15:58:17 -0700 Subject: [PATCH] created group directive --- .../Directives/Fields/FieldDirective.php | 47 +++++++++- .../Directives/Nodes/GroupDirective.php | 89 +++++++++++++++++++ src/Schema/Factories/NodeFactory.php | 43 +++++---- src/Schema/SchemaBuilder.php | 4 +- src/Schema/Values/NodeValue.php | 43 +++++++++ src/Support/Contracts/NodeMiddleware.php | 7 ++ .../Http/Controllers/GraphQLController.php | 13 +-- .../Directives/Nodes/GroupDirectiveTest.php | 44 +++++++++ 8 files changed, 258 insertions(+), 32 deletions(-) create mode 100644 src/Schema/Directives/Nodes/GroupDirective.php create mode 100644 tests/Unit/Schema/Directives/Nodes/GroupDirectiveTest.php diff --git a/src/Schema/Directives/Fields/FieldDirective.php b/src/Schema/Directives/Fields/FieldDirective.php index bbb336af7d..9f7cc38781 100644 --- a/src/Schema/Directives/Fields/FieldDirective.php +++ b/src/Schema/Directives/Fields/FieldDirective.php @@ -12,6 +12,20 @@ class FieldDirective implements FieldResolver { use HandlesDirectives; + /** + * Field resolver. + * + * @var string + */ + protected $resolver; + + /** + * Field resolver method. + * + * @var string + */ + protected $method; + /** * Name of the directive. * @@ -32,14 +46,14 @@ public function name() public function handle(FieldValue $value) { $directive = $this->fieldDirective($value->getField(), $this->name()); - $className = $this->getClassName($directive); + $resolver = $this->getResolver($value, $directive); $method = $this->getMethod($directive); $data = $this->argValue(collect($directive->arguments)->first(function ($arg) { return 'args' === data_get($arg, 'name.value'); })); - return $value->setResolver(function ($root, array $args, $context = null, $info = null) use ($className, $method, $data) { - $instance = app($className); + return $value->setResolver(function ($root, array $args, $context = null, $info = null) use ($resolver, $method, $data) { + $instance = app($resolver); return call_user_func_array( [$instance, $method], @@ -48,6 +62,27 @@ public function handle(FieldValue $value) }); } + /** + * Get resolver namespace. + * + * @param FieldValue $value + * @param DirectiveNode $directive + * + * @return string + */ + protected function getResolver(FieldValue $value, DirectiveNode $directive) + { + if ($resolver = $this->directiveArgValue($directive, 'resolve')) { + $className = array_get(explode('@', $resolver), '0'); + + return $value->getNode()->getNamespace($className); + } + + return $value->getNode()->getNamespace( + $this->getClassName($directive) + ); + } + /** * Get class name for resolver. * @@ -78,6 +113,12 @@ protected function getClassName(DirectiveNode $directive) */ protected function getMethod(DirectiveNode $directive) { + if ($resolver = $this->directiveArgValue($directive, 'resolve')) { + if ($method = array_get(explode('@', $resolver), '1')) { + return $method; + } + } + $method = $this->directiveArgValue($directive, 'method'); if (! $method) { diff --git a/src/Schema/Directives/Nodes/GroupDirective.php b/src/Schema/Directives/Nodes/GroupDirective.php new file mode 100644 index 0000000000..d0095bb6b9 --- /dev/null +++ b/src/Schema/Directives/Nodes/GroupDirective.php @@ -0,0 +1,89 @@ +setNamespace($value); + $this->setMiddleware($value); + + return $value; + } + + /** + * Set namespace on node. + * + * @param NodeValue $value [description] + */ + protected function setNamespace(NodeValue $value) + { + $namespace = $this->directiveArgValue( + $this->nodeDirective($value->getNode(), $this->name()), + 'namespace' + ); + + if ($namespace) { + $value->setNamespace($namespace); + } + } + + /** + * Set middleware for field. + * + * @param NodeValue $value + */ + protected function setMiddleware(NodeValue $value) + { + $node = $value->getNodeName(); + + if (! in_array($node, ['Query', 'Mutation'])) { + $message = 'Middleware can only be placed on a Query or Mutation ['.$node.']'; + + throw new DirectiveException($message); + } + + $middleware = $this->directiveArgValue( + $this->nodeDirective($value->getNode(), $this->name()), + 'middleware' + ); + + $container = graphql()->middleware(); + $middleware = is_string($middleware) ? [$middleware] : $middleware; + + if (empty($middleware)) { + return; + } + + foreach ($value->getNodeFields() as $field) { + 'Query' == $node + ? $container->registerQuery($field->name->value, $middleware) + : $container->registerMutation($field->name->value, $middleware); + } + } +} diff --git a/src/Schema/Factories/NodeFactory.php b/src/Schema/Factories/NodeFactory.php index ec17adc23f..828cce9429 100644 --- a/src/Schema/Factories/NodeFactory.php +++ b/src/Schema/Factories/NodeFactory.php @@ -39,25 +39,6 @@ public function handle(NodeValue $value) return $this->applyMiddleware($value)->getType(); } - /** - * Extend type definition. - * - * @param Extension $extension - * @param Type $type - * - * @return Type - */ - public function extend(Extension $extension, Type $type) - { - $typeFields = value($type->config['fields']); - $extendedFields = $this->getFields(new NodeValue($extension->definition)); - $type->config['fields'] = function () use ($typeFields, $extendedFields) { - return array_merge($typeFields, $extendedFields); - }; - - return $type; - } - /** * Check if node has a resolver directive. * @@ -103,6 +84,8 @@ protected function transform(NodeValue $value) return $this->objectType($value); case InputObjectTypeDefinitionNode::class: return $this->inputObjectType($value); + case Extension::class: + return $this->extend($value); default: throw new \Exception("Unknown node [{$value->getNodeName()}]"); } @@ -204,6 +187,28 @@ public function inputObjectType(NodeValue $value) return $value->setType($inputType); } + /** + * Extend type definition. + * + * @param NodeValue $value + * + * @return NodeValue + */ + public function extend(NodeValue $value) + { + $value->setNode( + $value->getNode()->definition + ); + + $type = $value->getType(); + $originalFields = value($type->config['fields']); + $type->config['fields'] = function () use ($originalFields, $value) { + return array_merge($originalFields, $this->getFields($value)); + }; + + return $value; + } + /** * Get fields for node. * diff --git a/src/Schema/SchemaBuilder.php b/src/Schema/SchemaBuilder.php index e619a2418a..76e943e3b9 100644 --- a/src/Schema/SchemaBuilder.php +++ b/src/Schema/SchemaBuilder.php @@ -164,7 +164,9 @@ protected function extendTypes(DocumentNode $document) $name = $extension->definition->name->value; if ($type = collect($this->types)->firstWhere('name', $name)) { - app(NodeFactory::class)->extend($extension, $type); + $value = new NodeValue($extension); + + app(NodeFactory::class)->handle($value->setType($type)); } }); } diff --git a/src/Schema/Values/NodeValue.php b/src/Schema/Values/NodeValue.php index 0df97f76c6..6508912e6f 100644 --- a/src/Schema/Values/NodeValue.php +++ b/src/Schema/Values/NodeValue.php @@ -29,6 +29,13 @@ class NodeValue */ protected $directive; + /** + * Current namespace. + * + * @var string + */ + protected $namespace; + /** * Create new instance of node value. * @@ -49,6 +56,20 @@ public static function init(Node $node) return new static($node); } + /** + * Set current node instance. + * + * @param Node $node + * + * @return self + */ + public function setNode(Node $node) + { + $this->node = $node; + + return $this; + } + /** * Set type definition. * @@ -73,6 +94,16 @@ public function setDirective(DirectiveNode $directive) $this->directive = $directive; } + /** + * Set the current namespace. + * + * @param string $namespace + */ + public function setNamespace($namespace) + { + $this->namespace = $namespace; + } + /** * Get current node. * @@ -103,6 +134,18 @@ public function getType() return $this->type; } + /** + * Get current namespace. + * + * @param string $class + * + * @return string + */ + public function getNamespace($class = null) + { + return $class ? $this->namespace.'\\'.$class : $this->namespace; + } + /** * Get the name of the node. * diff --git a/src/Support/Contracts/NodeMiddleware.php b/src/Support/Contracts/NodeMiddleware.php index 503d425609..8d0e59d757 100644 --- a/src/Support/Contracts/NodeMiddleware.php +++ b/src/Support/Contracts/NodeMiddleware.php @@ -6,6 +6,13 @@ interface NodeMiddleware { + /** + * Name of the directive. + * + * @return string + */ + public function name(); + /** * Handle node value. * diff --git a/src/Support/Http/Controllers/GraphQLController.php b/src/Support/Http/Controllers/GraphQLController.php index 69727d72f7..41c6df731f 100644 --- a/src/Support/Http/Controllers/GraphQLController.php +++ b/src/Support/Http/Controllers/GraphQLController.php @@ -15,14 +15,9 @@ class GraphQLController extends Controller */ public function __construct(Request $request) { - // TODO: Query for middleware - // if ($query = $request->get('query')) { - // $middleware = app('graphql')->schema() - // ->parse($query) - // ->middleware(); - // - // $this->middleware($middleware->toArray()); - // } + $this->middleware(graphql()->middleware()->forRequest( + $request->input('query', '') + )); } /** @@ -30,7 +25,7 @@ public function __construct(Request $request) * * @param Request $request * - * @return Response + * @return \Illuminate\Http\Response */ public function query(Request $request) { diff --git a/tests/Unit/Schema/Directives/Nodes/GroupDirectiveTest.php b/tests/Unit/Schema/Directives/Nodes/GroupDirectiveTest.php new file mode 100644 index 0000000000..3c42d05f56 --- /dev/null +++ b/tests/Unit/Schema/Directives/Nodes/GroupDirectiveTest.php @@ -0,0 +1,44 @@ +execute($schema, '{ me }'); + $this->assertEquals('foo.bar', $result->data['me']); + } + + /** + * @test + * @group failing + */ + public function itCanSetMiddleware() + { + $schema = ' + type Query {} + extend type Query @group(middleware: ["foo", "bar"]) { + me: String @field(resolve: "Tests\\\Utils\\\Resolvers\\\Foo@bar") + } + '; + + $this->execute($schema, '{ me }'); + $middleware = graphql()->middleware()->query('me'); + $this->assertCount(2, $middleware); + $this->assertEquals('foo', $middleware[0]); + $this->assertEquals('bar', $middleware[1]); + } +}