以下是一个示例数据库表(users
):
id - int(11) auto_increment
name - varchar(100)
banned - int(1)
列banned
是一个布尔值,默认为0
(false
)。如果用户已被禁止,则值为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将此限制应用于任何查询。
关于如何解决这个问题的任何想法?
答案 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"]
)
)