Laravel:如何"禁用"全局范围以便将"非活动"对象包含在查询中?

jsp*_*hpl 4 php laravel eloquent

我在使用全局范围时遇到问题,尤其是删除范围.

在我的用户模型中,我有一个ActivatedUsersTrait,即引入了一个全球范围内只查询与列用户"激活"设置为true(电子邮件验证之后,用户被"激活").

到目前为止一切正常,当我查询User :: all()时,我只获得具有activated = true的用户.

我现在的问题是,如何将未激活的用户包含在我的查询中,就像SoftDeletingTrait通过withTrashed()一样?这只与我的ActivationController有关,我需要获取User,设置activate = true并将它们保存回db.

我在ActiveUsersTrait中创建了一个withInactive()方法,基于我在SoftDeletingTrait中找到的方法,但是当我在User :: withInactive-> get()上运行查询时,未激活的用户将不会显示在结果.

这是我的ActiveUsersTrait:

use PB\Scopes\ActiveUsersScope;

trait ActiveUsersTrait {

    public static function bootActiveUsersTrait()
    {
        static::addGlobalScope(new ActiveUsersScope);
    }

    public static function withInactive()
    {
        // dd(new static);
        return (new static)->newQueryWithoutScope(new ActiveUsersScope);
    }

    public function getActivatedColumn()
    {
        return 'activated';
    }

    public function getQualifiedActivatedColumn()
    {
        return $this->getTable().'.'.$this->getActivatedColumn();
    }

}
Run Code Online (Sandbox Code Playgroud)

和我的ActiveUsersScope:

use Illuminate\Database\Eloquent\ScopeInterface;
use Illuminate\Database\Eloquent\Builder;

class ActiveUsersScope implements ScopeInterface {

    public function apply(Builder $builder)
    {
        $model = $builder->getModel();

        $builder->where($model->getQualifiedActivatedColumn(), true);

    }

    public function remove(Builder $builder)
    {
        $column = $builder->getModel()->getQualifiedActivatedColumn();

        $query = $builder->getQuery();

        foreach ((array) $query->wheres as $key => $where)
        {
            if ($this->isActiveUsersConstraint($where, $column))
            {
                unset($query->wheres[$key]);

                $query->wheres = array_values($query->wheres);
            }
        }
    }

    protected function isActiveUsersConstraint(array $where, $column)
    {
        return $where['type'] == 'Basic' && $where['column'] == $column;
    }
}
Run Code Online (Sandbox Code Playgroud)

任何帮助都非常感谢!

提前致谢!-约瑟夫

voi*_*ate 24

雄辩的查询现在有了一个removeGlobalScopes()方法.

请参阅:https://laravel.com/docs/5.3/eloquent#query-scopes(在"删除全局范围"子标题下).

来自文档:

// Remove one scope
User::withoutGlobalScope(AgeScope::class)->get();

// Remove all of the global scopes...
User::withoutGlobalScopes()->get();

// Remove some of the global scopes...
User::withoutGlobalScopes([
    FirstScope::class, SecondScope::class
])->get();
Run Code Online (Sandbox Code Playgroud)


Def*_*ral 11

SoftDeletingTrait清理更简单,因为它不涉及任何绑定(它是一个"空",而不是"基本"在哪里).您遇到的问题是[n => true]的绑定仍然存在,即使您手动删除where也是如此.

我正在考虑制作公关,因为我自己遇到了同样的问题,而且没有很好的方法可以跟踪哪些人和哪些绑定在一起.

如果您只使用简单查询,则可以或多或少地跟踪绑定的索引:

use Illuminate\Database\Eloquent\ScopeInterface;
use Illuminate\Database\Eloquent\Builder;

class ActiveUsersScope implements ScopeInterface {

    /**
     * The index in which we added a where clause
     * @var int
     */
    private $where_index;

    /**
     * The index in which we added a where binding
     * @var int
     */
    private $binding_index;

    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @return void
     */
    public function apply(Builder $builder)
    {
        $model = $builder->getModel();

        $builder->where($model->getQualifiedActivatedColumn(), true);

        $this->where_index = count($query->wheres) - 1;

        $this->binding_index = count($query->getRawBindings()['where']) - 1;
    }

    /**
     * Remove the scope from the given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @return void
     */
    public function remove(Builder $builder)
    {
        $query = $builder->getQuery();

        unset($query->wheres[$this->where_index]);
        $where_bindings = $query->getRawBindings()['where'];
        unset($where_bindings[$this->binding_index]);
        $query->setBindings(array_values($where_bindings));
        $query->wheres = array_values($query->wheres);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意我们如何存储添加了where子句和绑定的索引,而不是循环并检查我们是否找到了正确的索引.这几乎感觉就像是一个更好的设计 - 我们添加了where子句和绑定,所以我们应该知道它在哪里而不必遍历所有where子句.当然,如果其他东西(比如::withTrashed)也在搞乱where数组,那么它们都会变得混乱.不幸的是,where bindings和where子句只是平面数组,所以我们无法准确地听取它们的变化.更加面向对象的方法更好地自动管理子句及其绑定之间的依赖关系.

显然,这种方法可以从一些更漂亮的代码和数组密钥存在的验证等方面受益.但是这应该让你开始.由于全局范围不是单例(无论何时newQuery()调用它们都会应用),因此这种方法在没有额外验证的情况下应该是有效的.

希望这有助于"现在足够好"的标题!