Я хочу фильтровать (не предотвращать доступ) поля списка, возвращаемые из моего GraphQL API, на основе метода представления в политике модели.
Я написал приведенную ниже директиву, которую добавил в полей в моей схеме.
У меня два вопроса:
Это не самый лучший способ достичь желаемого результата, потому что мне нужно аннотировать каждое поле в моя схема, которая устанавливает отношения. Есть ли лучший способ сделать это?
В приведенном ниже решении есть крайний случай, который не работает. При возврате отфильтрованной коллекции он не загружает вложенные поля объекта, которые были запрошены в схеме. В идеале это должно было бы вести себя рекурсивно, используя один и тот же преобразователь для всех элементов в Коллекции и всех их дочерних полей. Как я могу заставить это работать?
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);
}
}