问题
Here is a sample database-table (users
):
id - int(11) auto_increment
name - varchar(100)
banned - int(1)
The column banned
is a boolean value which is 0
(false
) by default. If an user has been banned, the value is 1
.
I'd like to exclude any banned users from all queries by default. I could create a query scope and then use that everywhere. However, I'd much more prefer simply having that check on by default.
I could also create a newQuery
-method of my own, like so:
// Inside User-model, which extends Eloquent
public function newQuery($excludeDeleted = true)
{
$builder = parent::newQuery($exludeDeleted);
$builder->where('banned', '=', '0');
return $builder;
}
However, this way I wouldn't be able to switch off this behaviour. I might want to see the banned users in my private admin panel, but would not be able to, as this restriction would be applied to any query done via Eloquent.
Any idea on how to solve this problem?
回答1:
I strongly suggest on using Repository Design Pattern for DB queries instead of doing direct Eloquent queries in controllers and everywhere.
// 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();
}
}
Now you can instiate the repository class where ever you need queries and you have unified API to the calls. In Laravel it's really easy to spread small Eloquent queries here and there but in the long run it will be really annoying to update/change and cope. Try googling for Laravel Design Pattern
and there's lots of information and examples about it. Has made my day couple of times already.
This pattern also makes easier to ditch the whole Eloquent with something else if necessary.
回答2:
This sounds a lot like soft deleting, but with banned_at
instead of deleted_at
. If the default behaviour is not to show the banned users, I think it is more intuitive to explicitly ask for the banned (like withTrashed
) when you need them (admin panel).
回答3:
Laravel provides Global Scopes for exactly this purpose. From the docs:
class AgeScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
return $builder->where('age', '>', 200);
}
}
class User extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new AgeScope);
}
}
回答4:
Why don't you use config variable for that:
public function newQuery($excludeDeleted = true)
{
$builder = parent::newQuery($exludeDeleted);
if (Config::get('hide_banned_users', true) !== false) {
$builder->where('banned', '=', '0');
}
return $builder;
}
and change the config value whenever you need to see the banned users.
来源:https://stackoverflow.com/questions/21812826/default-scope-for-eloquent-models