Eloquent模型的默认范围?

时间:2014-02-16 14:57:29

标签: laravel laravel-4 eloquent

以下是一个示例数据库表(users):

id - int(11) auto_increment
name - varchar(100)
banned - int(1)

banned是一个布尔值,默认为0false)。如果用户已被禁止,则值为1

我希望默认情况下从所有查询中排除任何被禁用的用户。我可以创建一个query scope,然后在任何地方使用它。但是,我更喜欢在默认情况下进行检查。

我也可以创建一个newQuery - 我自己的方法,如下所示:

// Inside User-model, which extends Eloquent
public function newQuery($excludeDeleted = true)
{
    $builder = parent::newQuery($exludeDeleted);
    $builder->where('banned', '=', '0');
    return $builder;
}

然而,这样我就无法关闭此行为。我可能希望在我的私人管理面板中看到被禁用的用户,但是无法通过Eloquent将此限制应用于任何查询。

关于如何解决这个问题的任何想法?

6 个答案:

答案 0 :(得分:3)

我强烈建议将Repository Design Pattern用于数据库查询,而不是在控制器和任何地方进行直接的Eloquent查询。

// Quick example, not tested
class UserRepositoy { // You should create an interface and maybe super class for handling common cases like caching, find(), all() etc

    protected $include_banned = false;
    protected $model;

    public function __construct() // you can use DI here
    {
            $this->model = new User;
    }

    public function setIncludeBanned($bool)
    {
        $this->include_banned = $bool;
    }

    protected function includeBanned($query)
    {
        if ($this->include_banned) {
            return $query->where('banned', 1);
        }
    }

    public function find($id)
    {
        $res = $this->model->where('id', $id);

        $res = $this->includeBanned($res);

        return $res->get();
    }

}

现在,您可以在需要查询的地方查找存储库类,并为调用提供统一的API。在Laravel中,很容易在这里和那里传播小的Eloquent查询,但从长远来看,更新/更改和应对会非常烦人。尝试谷歌搜索Laravel Design Pattern,有很多关于它的信息和示例。已经成功了几天。

如果有必要,这种模式也可以更容易地抛弃整个Eloquent。

答案 1 :(得分:3)

在Model类上实现而不是创建一个单独的类

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class User extends Model
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('banned', function (Builder $builder) {
            $builder->where('banned', 0);
        });
    }
}

答案 2 :(得分:1)

这听起来很像soft deleting,但banned_at代替deleted_at。如果默认行为不是显示被禁用户,我认为在您需要时(管理员面板)明确要求被禁止(如withTrashed)更为直观。

答案 3 :(得分:1)

在这里为可能正在寻找类似答案的其他人答复。

您可以创建一个全局范围,让模型默认使用全局范围,然后在您要在不应用该范围的情况下进行查询时使用withoutGlobalScope

请参阅Laravel文档:https://laravel.com/docs/5.8/eloquent#global-scopes


因此,在您的情况下,您将创建一个新的全局范围以查询未被禁止的用户。

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class ExcludeBannedScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('banned', '=', 0);
    }
}

将全局范围应用于用户模型。

<?php

namespace App;

use App\Scopes\ExcludeBannedScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new ExcludeBannedScope);
    }
}

这现在会将where banned = 0添加到所有查询中。

您要在“管理”部分中查看所有用户(包括被禁止的用户)

User::withoutGlobalScope(\App\Scopes\ExcludeBannedScope::class)->get();

答案 4 :(得分:0)

为什么不使用配置变量:

public function newQuery($excludeDeleted = true)
{
    $builder = parent::newQuery($exludeDeleted);
    if (Config::get('hide_banned_users', true) !== false) {
        $builder->where('banned', '=', '0');
    }
    return $builder;
}

并在需要查看被禁用户时更改配置值。

答案 5 :(得分:0)

Laravel为此提供了Global Scopes。从文档中:

df.drop(["Terri"], axis=1).join(
    pd.DataFrame(
        df['Terri'].str.split("-")\
            .apply(lambda x: pd.Series(myRange(*map(int, x))))\
            .stack()\
            .reset_index(level=1, drop=True),
        columns=["Terri"]
    )
)