请问模型关联关系中如何使用多字段条件

1. 运行环境

1). 当前使用的 Laravel 版本?

10.2.0

2. 问题描述?

用户授权策略 policy 中使用 update 方法参数中注入了目标模型,我如果想在之后的程序中复用该模型,而不想重新 find 查询,有没有解决方案?

3.补充一下代码

比如我有一个 TeamPolicy 采用自发现方式调用。

# 完整代码较长,我只贴关键部分
class TeamPolicy
{
    /**
     * 我想复用 update 方法参数中的 team
     * 因为它在校验用户权限的时候将被首次查询
     */
    public function update(User $user, Team $team): bool
    {
        // 如果是团队的创建者,可以修改
        if ($user->id === $team->owner_id) {
            return  true;
        }

        // 如果有团队修改权限,可以修改
        if (!$user->can('teams.update')) {
            return  false;
        }

        return  true;
    }
}

然后我在 TeamUpdate 类型中想复用它不想重新查询,请问如何绑定这个实例

final class TeamUpdate
{
    readonly public TeamUpdateService $teamUpdateService;
    public function __construct(Team $team)
    {
        # 以下这行虽然可以看到 $team 被传入实例,但其中的数据是空的
        # 请问如何查询到上面授权策略注入的实例。
        info('app', [$team,]);
        $this->teamUpdateService = app(TeamUpdateService::class);
    }

    /**
     * 更新团队
     *
     * @param null $_
     * @param array{} $args
     * @return Team
     * @throws Throwable
     * @throws ValidationException
     */
    public function __invoke($_, array $args): Team
    {
        $input          = data_get($args, 'teamUpdateInput');
        info('app', [app(Team::class,Arr::only($input,['id'])),]);
        $team           = Team::find(data_get($input, 'id'));
        /** @var User $user */
        $user           = auth()->user();
        throw_if(!$team, GraphQLRenderException::class, '团队不存在');
        $data           = Arr::only($input, ['name', 'quota']);
        throw_if(
            isset($data['quota']) && !$user->can('teams.audit'),
            GraphQLRenderException::class,
            '没有权限修改团队额度'
        );

        return  $this->teamUpdateService->handle($team, $data);
    }
}
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

是意味着 inspect 方法最终会调用策略方法吗?

普通的策略方法返回简单的布尔值,所以很难满足一些特殊情况

策略响应可以包含更多信息,这是它的 toArray() 方法

public function toArray()
{
    return [
        // 这个布尔值可以使策略响应像普通策略方法一样被判断
        'allowed' => $this->allowed(),
        'message' => $this->message(),
        'code' => $this->code(),
    ];
}

文档上判断策略响应的示例

$response = Gate::inspect('update', $post);

// 这个返回的就是布尔值
if ($response->allowed()) {
    // The action is authorized...
} else {
    echo $response->message();
}

但这些不能解决你的问题。。。

1年前 评论
讨论数量: 13

如果你想在多个控制器或服务类中需要复用该模型,你可以使用 Laravel 服务容器来注册该模型,并在需要时从容器中获取该模型的实例

1年前 评论

把代码贴出来看看

1年前 评论
sanders (楼主) 1年前
Adachi (作者) 1年前
sanders (楼主) 1年前

策略那里不是注入而是传入吧
策略方法
使用策略授权操作

你的 $team 已经查出来了

$team = Team::find(data_get($input, 'id'));

不应该是这样判断吗

$user->can('update', $team);
1年前 评论
sanders (楼主) 1年前
sanders (楼主) 1年前

file

嗯,抱歉,肤浅了,我没用过 策略方法,我以为你所谓的team是类似管理所有权限的东西,我是在中间件拦截判断的是否有权限curd

1年前 评论
sanders (楼主) 1年前

是意味着 inspect 方法最终会调用策略方法吗?

普通的策略方法返回简单的布尔值,所以很难满足一些特殊情况

策略响应可以包含更多信息,这是它的 toArray() 方法

public function toArray()
{
    return [
        // 这个布尔值可以使策略响应像普通策略方法一样被判断
        'allowed' => $this->allowed(),
        'message' => $this->message(),
        'code' => $this->code(),
    ];
}

文档上判断策略响应的示例

$response = Gate::inspect('update', $post);

// 这个返回的就是布尔值
if ($response->allowed()) {
    // The action is authorized...
} else {
    echo $response->message();
}

但这些不能解决你的问题。。。

1年前 评论

因为我在 lighthouse 的代码里面也没有找到直接对 can 方法的调用,而是在里面看到了对拦截器 inspect 方法的调用,类似这样: $response = $gate->inspect($ability, $arguments); 。总的来说,lighthouse 似乎没有在校验权限时对已查询的模型做缓冲处理,除非我去用自定义的指令去替换它。

我没用过 Lighthouse,按你说的只搜到了这个。

这里的 $model 是传入的,你看能否在这里找到突破口。

file

1年前 评论
sanders

@lddtime

可能我没理解你说的有关inspect方法的问题,于是我还是翻了一下框架的源码,说一下几个问题我自己的结论

Gate::inspect() 方法,会去调用策略

以下是框架默认Gate这方面实现的源码:

    protected function resolveAuthCallback($user, $ability, array $arguments)
    {
        if (isset($arguments[0]) &&
            ! is_null($policy = $this->getPolicyFor($arguments[0])) &&
            $callback = $this->resolvePolicyCallback($user, $ability, $arguments, $policy)) {
            return $callback;
        }

        if (isset($this->stringCallbacks[$ability])) {
            [$class, $method] = Str::parseCallback($this->stringCallbacks[$ability]);

            if ($this->canBeCalledWithUser($user, $class, $method ?: '__invoke')) {
                return $this->abilities[$ability];
            }
        }

        if (isset($this->abilities[$ability]) &&
            $this->canBeCalledWithUser($user, $this->abilities[$ability])) {
            return $this->abilities[$ability];
        }

        return function () {
            //
        };
    }

lighthouse @can 指令的问题

我没用过 Lighthouse,按你说的只搜到了这个。
这里的 $model 是传入的,你看能否在这里找到突破口。

是的,我也是找到这里,但他只是用于权限校验,没有进行缓冲。

确定的是 @can 指令容易产生这种重复查询的缺陷,对此我能想到的有如下两种方案:

1. 封装自己的指令替换 @can 指令

继承 CanDirective 覆盖其 modelsToCheck 方法,将查到的模型缓冲到 GraphQLContext 里面供之后的代码取用。

2. 在解析器里面调用 Gate 的方法

graphql schema 声明中去掉 @can 指令的调用,直接在之后的字段解析器里面调用 Gate 的方法。

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!