【问题标题】:Gracefully exiting Laravel scopes优雅地退出 Laravel 作用域
【发布时间】:2020-11-10 14:59:35
【问题描述】:

我有一个作用域,它根据用户角色以一种限制方式运行,您可以将一组规则转发到限制数据库最终输出的作用域。

一个真正简化的角色限制示例:

{
    "first_name": "=foo%"
}

将只返回first_namefoo% 开头的记录,这实际上意味着我已禁止具有该角色的用户查看任何不以foo% 开头的记录。

这种方法的问题是,如果某人没有施加任何限制,他就会看到一切。我知道这是一个有效的假设,但如果没有施加任何限制,我想禁止一切,这样如果创建了新角色,它就没有任何权利。

目前我正在为这种情况抛出异常:

public function apply(Builder $builder, Model $model)
{
    $input = $this->getAuthValues(get_class($model));

    if (count($input) < 1) {
        throw new \Exception('No rights for you');
    }

    $jsonQuery = new JsonQuery($builder, $input); <-- class responsible for assembling the queries based on the input
    $jsonQuery->search();
}

但这当然也不例外。在这种情况下,我希望返回空数组。

我可以使用某种方法优雅地退出范围以及一个空结果,而不是在之后实际执行查询吗?

【问题讨论】:

    标签: php laravel authorization laravel-7 scopes


    【解决方案1】:

    我想出了一个解决方案来进行一个不可能的查询,它会返回 0 个结果。

    public function apply(Builder $builder, Model $model)
    {
        $input = $this->getAuthValues(get_class($model));
    
        if (count($input) < 1) {
            $builder->whereRaw('1 = 0');
            return;
        }
    
        $jsonQuery = new JsonQuery($builder, $input);
        $jsonQuery->search();
    }
    

    【讨论】:

    • 不错的解决方案!简单多了!
    【解决方案2】:

    由于作用域通常是链接的(流畅地调用),并且作用域不直接负责执行查询,我认为你不能“优雅地退出”,因为下一次调用仍然会期待一个 Builder 对象继续努力。

    一种可能的解决方案(不简单)是创建一个扩展Builder 类的类,并覆盖所有负责从数据库中实际获取结果的方法。我不确定您需要覆盖的所有方法才能在所有情况下都没有错误地工作。您可能还想处理AbortedBuilder 中的一些插入和更新案例。

    class AbortedBuilder extends Builder
    {
        ...
    
        /**
         * Run the query as a "select" statement against the connection.
         *
         * @return array
         */
        protected function runSelect()
        {
            return [];
        }
        
        ...
    
        /**
         * Run a pagination count query.
         *
         * @param  array  $columns
         * @return array
         */
        protected function runPaginationCountQuery($columns = ['*'])
        {
            return [];        
        }
    
        ...
    
        /**
         * Insert a new record and get the value of the primary key.
         *
         * @param  array  $values
         * @param  string|null  $sequence
         * @return int
         */
        public function insertGetId(array $values, $sequence = null)
        {
            throw new \Exception('You are trying to insert using an aborted query!');
        }
    
        ...
    }
    

    那么在你的范围内你可以这样做:

    public function apply(Builder $builder, Model $model)
    {
        $input = $this->getAuthValues(get_class($model));
    
        if (count($input) < 1) {
            $builder = new AbortedBuilder();
        } else {
            $jsonQuery = new JsonQuery($builder, $input);
            $jsonQuery->search();
    }
    

    【讨论】:

    • 谢谢库尔特。想多了,其实我想出了一个更简单的解决方案。我会把它贴在下面
    猜你喜欢
    • 2011-10-20
    • 1970-01-01
    • 2013-07-21
    • 2019-04-14
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    相关资源
    最近更新 更多