Как я могу использовать политики Laravel для фильтрации ответов списка от GraphQL? - PullRequest
1 голос
/ 08 мая 2020

Я хочу фильтровать (не предотвращать доступ) поля списка, возвращаемые из моего GraphQL API, на основе метода представления в политике модели.

Я написал приведенную ниже директиву, которую добавил в полей в моей схеме.

У меня два вопроса:

  1. Это не самый лучший способ достичь желаемого результата, потому что мне нужно аннотировать каждое поле в моя схема, которая устанавливает отношения. Есть ли лучший способ сделать это?

  2. В приведенном ниже решении есть крайний случай, который не работает. При возврате отфильтрованной коллекции он не загружает вложенные поля объекта, которые были запрошены в схеме. В идеале это должно было бы вести себя рекурсивно, используя один и тот же преобразователь для всех элементов в Коллекции и всех их дочерних полей. Как я могу заставить это работать?

class ViewPolicyFilterDirective extends BaseDirective implements FieldMiddleware {
    /**
     * Filters GraphQL list fields using Policies 'view' method
     *
     * @param \Nuwave\Lighthouse\Schema\Values\FieldValue $fieldValue
     * @param \Closure $next
     * @return \Nuwave\Lighthouse\Schema\Values\FieldValue
     */
    public function handleField(FieldValue $fieldValue, Closure $next): FieldValue {
        // Retrieve the existing resolver function
        /** @var Closure $previousResolver */
        $previousResolver = $fieldValue->getResolver();

        // Wrap around the resolver
        $wrappedResolver = function ($root, array $args, GraphQLContext $context, ResolveInfo $info) use ($previousResolver) {
            // Call the resolver, passing along the resolver arguments
            $result = $previousResolver($root, $args, $context, $info);
            if ($result instanceof Collection && $result->count() > 0 && $result[0] instanceof Model) {
                return $result->filter(function (Model $r) {
                    return Auth::user()->can('view', $r);
                })->toArray();
            } else if ($result instanceof Model && Auth::user()->can('view', $result)) {
                return $result;
            } else if ($result instanceof Model && !Auth::user()->can('view', $result)) {
                throw new AuthorizationException(
                    "You are not authorized to access this"
                );
            }
            return $result;
        };

        // Place the wrapped resolver back upon the FieldValue
        // It is not resolved right now - we just prepare it
        $fieldValue->setResolver($wrappedResolver);

        // Keep the middleware chain going
        return $next($fieldValue);
    }
}
...