GraphQLBundle
GraphQLBundle copied to clipboard
[RFC] resolver implementation
| Q | A |
|---|---|
| Bug report? | no |
| Feature request? | no |
| BC Break report? | no |
| RFC? | yes |
| Version/Branch | 1.0-dev |
I was looking how to use an attached query provider and get the parent value into the method. Not sure if that is even possible at the moment, but i found #538, #542 and #708 and i really liked the resolver idea.
I created the expression-function below to try this out. It's still missing a lot of functionality and this should probably be done at a level higher. But it works for simple functions, and is a start for a discussion. I think the 3rd parameter can be extracted from the ResolveInfo object.
With a method like
public function posts(?string $after, ?int $first, ?string $before, ?int $last): Connection
and a resolver like
@=actionResolver('App\\GraphQL\\Query\\PostsProviders', 'posts', {after: "String", first: "Int", before: "String", last: "Int"})
generates code like
return $globalVariables->get('container')->get('App\\GraphQL\\Query\\PostsProviders')->posts($args["after"], $args["first"], $args["before"], $args["last"]);
Or you could do this: With a method like below and a relay-connection args builder
public function posts(User $parentValue, Argument $args): Connection
and a resolver like
@=actionResolver('App\\GraphQL\\Query\\PostsProviders', 'posts', {})
generates code like
return $globalVariables->get('container')->get('App\\GraphQL\\Query\\PostsProviders')->posts($value, $args);
namespace App\GraphQL\ExpressionLanguage;
use Overblog\GraphQLBundle\ExpressionLanguage\ExpressionFunction;
use Overblog\GraphQLBundle\Definition\ArgumentInterface;
class ActionResolver extends ExpressionFunction
{
public function __construct()
{
parent::__construct(
'actionResolver',
function (string $classString, string $methodString, string $argsString = '[]') {
$className = stripslashes(trim($classString, '"'));
$method = trim($methodString, '"');
$args = eval('return '.$argsString.';');
$reflectionClass = new \ReflectionClass($className);
$reflectionMethod = $reflectionClass->getMethod($method);
$arguments = [];
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
$argument = $this->getCallArgument($parameter, $args);
if ($argument === null && !$parameter->isOptional()) {
throw new \Exception('bla');
}
$arguments[] = $argument;
}
return ($this->generateServiceCall($className, $method, $arguments));
},
fn ($_, callable $target, array $args) => dump($target, $args)
);
}
private function getCallArgument(\ReflectionParameter $parameter, array $args): ?string
{
if (isset($args[$parameter->getName()])) {
return '$args["'.$parameter->getName().'"]';
}
if (is_a($parameter->getType()->getName(), ArgumentInterface::class, true)) {
return '$args';
}
if ($parameter->getName() === 'parentValue') {
return '$value';
}
return null;
}
private function generateServiceCall(string $class, string $method, array $args)
{
$serviceId = addslashes($class);
return "$this->globalVars->get('container')->get('$serviceId')"
. "->$method(" . implode(', ', $args) . ")";
}
}
@mcg-web @Vincz @akomm @mavimo @murtukov I know you are all busy, but is this something to make a real implementation proposal for or isn't this worth pursuing?
Yes @bartv2 sorry for late reply, since #708 rewrite almost completely the way resolvers definitions. It will better to wait until this totally push, to see how we can implement other part depending on this. I'll try to push this before next weekend.