GraphQLBundle icon indicating copy to clipboard operation
GraphQLBundle copied to clipboard

[RFC] resolver implementation

Open bartv2 opened this issue 5 years ago • 2 comments

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) . ")";
    }
}

bartv2 avatar Aug 23 '20 12:08 bartv2

@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?

bartv2 avatar Sep 05 '20 10:09 bartv2

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.

mcg-web avatar Sep 05 '20 11:09 mcg-web