复杂 Laravel、Graphql 和 Lighthouse 实现

Complex Laravel, Graphql and Lighhouse implementation

我的问题涉及如何构建复杂的自定义解析器,以及为什么它们不能与内置解析器很好地配合使用。我找不到任何关于复杂解析器的好例子,我的真实案例比这个例子还要复杂。

我有以下架构

type Query {
    users: [User!]! @field(resolver: "App\Library\UserController@fetchAll")
    posts: [Post!]! @field(resolver: "App\Library\PostController@fetchAll")
    post(id: Int! @eq): Post @find
}

type User {
    id: ID!
    name: String
    posts: [Post!]!  @field(resolver: "App\Library\PostController@fetchAll")
}

type Post {
    id: ID!
    content: String!
    comments: [Comment] @field(resolver: "App\Library\CommentController@fetchAll")
}

type Comment {
    id: ID!
    reply: String!
commentRating: [CommentRating] @field(resolver: “App\Library\CommentRatingController@fetchSum")
}

type CommentRating {
    id: ID!
    rating: String
}

例如我有这个查询

{
  users {
    id,
    name
    posts {
      title
      comments {
        id,
        reply
        
      }
    }
  }
}

我需要自定义解析器,因为业务逻辑,但不是所有的。上面的工作(我故意为所有这些使用自定义解析器,我会稍微解释一下)但前提是我构建了我的 eloquent 正确调用第一个解析器中的查询。像这样

// Function in custom resolver. All other custom resolver which are accessed can just pass the $rootValue on, or operate on it.
public function fetchAll($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
// We have some more sophisticated logic to dynamically build the array parameter on the line below, because the query may not always request comments, which means 'posts.comments' wont be needed. As this is the entrypoint, $rootValue is empty
    $t = User::with['posts', 'posts.comments', 'posts.comments.ratings'])->get();

    // Business logic modules called here
        return $t;
}

如果我从自定义解析器开始,但查询中的某些内容使用内置解析器,例如,如果更改

type User {
    id: ID!
    name: String
    posts: [Post!]!  @field(resolver: "App\Library\PostController@fetchAll")
}

type User {
    id: ID!
    name: String
    posts: [Post!]!  @all
}

然后它仍然 运行 是正确的,但引入了 N+1 问题。所以我可以在我的 mysql 日志中看到多个查询突然 运行 ,如果我只有自定义或仅内置解析器,就不会发生这种情况。让自定义解析器调用内置解析器是不好的做法吗?

最好只为我的所有类型使用自定义解析器吗?我构建自定义解析器的方法是否正确? (参考public函数fetchAll代码片段)

Lighthouse 提供诸如@hasOne、@hasMany、@belongsTo 之类的指令来防止 N+1 问题。您需要做的就是使用它们。

https://lighthouse-php.com/master/eloquent/relationships.html#avoiding-the-n-1-performance-problem

您可以将您的解析器 class 映射到您的架构中,例如

type Query {
    users: [User] @field(resolver: "App\GraphQL\Queries\User@FooFunction")
}

并使用此命令生成此查询解析器 class:

php artisan lighthouse:query User

并将您喜欢的每个查询放在这个名为 FooFunction 的函数中:

<?php

namespace App\GraphQL\Queries;

use Carbon\Carbon;
use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Support\Facades\DB;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;

class User
{
    /**
     * Return a value for the field.
     *
     * @param  null  $rootValue Usually contains the result returned from the parent field. In this case, it is always `null`.
     * @param  mixed[]  $args The arguments that were passed into the field.
     * @param  \Nuwave\Lighthouse\Support\Contracts\GraphQLContext  $context Arbitrary data that is shared between all fields of a single query.
     * @param  \GraphQL\Type\Definition\ResolveInfo  $resolveInfo Information about the query itself, such as the execution state, the field name, path to the field from the root, and more.
     * @return mixed
     */
    public function FooFunction($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
    {
        return
            DB::table('...')
              ->where(...)
              ->get();
    }
}

有点晚了,但问题是我没有完全理解 graphql 模型。自定义解析器只需要发回正确类型的模型,以便模式可以理解它。我的解析器没有返回正确的类型。