Modify query builder just before resolve by lighthouse.
First, I've added my directive:
<?php
namespace App\GraphQL\Directives;
use Closure;
use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldMiddleware;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
use App\GraphQL\Grid\Types;
class MyDirective extends BaseDirective implements FieldMiddleware {
public static function definition(): Directive
{
return new Types\Directive();
}
public function handleField(FieldValue $fieldValue, Closure $next)
{
$resolver = $fieldValue->getResolver();
return $next(
$fieldValue->setResolver(function (
$root,
array $args,
GraphQLContext $context,
ResolveInfo $resolveInfo
) use ($resolver) {
info("Middleware");
return $resolver($root, $args, $context, $resolveInfo);
})
);
}
}And defined my query:
extend type Query {
myQuery( arg1: String! @fieldDirective1, arg2: String! @fieldDirective2 ): [MyType] @paginate @myDirective
}I had two arguments with field directives and @paginate directive.
To each directive, I've added info a function with the class name. In case of a trace is added at the beginning and just before the end (when a query is resolved).
First, run:
MyDirective
Paginate Begin
FieldDirective1
FieldDirective2
Paginate EndPaginate directive Resolve field arguments in the middle. I need to add my middleware after FieldDirective2 and before Paginate End.
A little change in the code of MyDirective
$result = $resolver($root, $args, $context, $resolveInfo);
info("middleware");
return $result;Result as expected:
Paginate Begin
FieldDirective1
FieldDirective2
Paginate End
MyDirectivePaginate directive runs field directives. I'm not able to catch the moment with FieldMiddleware. I need to be here:
// PaginateDirective.php
$query = $resolveInfo->argumentSet->enhanceBuilder($query, $this->directiveArgValue("scopes", []));Add bogus argument
I've changed my directive resolver to inject additional arguments into arguments stored in $resolveInfo
class MyDirective extends BaseDirective implements
FieldManipulator,
DefinedDirective,
FieldMiddleware,
\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective
{
public function handleField(FieldValue $fieldValue, Closure $next)
{
$resolver = $fieldValue->getResolver();
return $next(
$fieldValue->setResolver(function (
$root,
array $args,
GraphQLContext $context,
ResolveInfo $resolveInfo
) use ($resolver) {
$argument = new \Nuwave\Lighthouse\Execution\Arguments\Argument();
$argument->value = true;
$argument->type = \GraphQL\Type\Definition\Type::boolean();
$argument->directives->push($this);
$resolveInfo->argumentSet->arguments["my_directive_arg"] = $argument;
info("MyDirective Begin");
$result = $resolver($root, $args, $context, $resolveInfo);
info("MyDirective End");
return $result;
})
);
}
public function handleBuilder($builder, $filters)
{
info("MyDirective Bulder");
return $builder;
}
}And result:
MyDirective Begin
Pagination Begin
FieldDirective1
FieldDirective2
MyDirective Bulder
Paginate End
MyDirective EndThis gives me the ability to modify eloquent queries just before execute knowing all conditions made by argument directives.