Область действия по умолчанию для красноречивых моделей?
Вот пример базы данных-таблица (users
):
id - int(11) auto_increment
name - varchar(100)
banned - int(1)
banned
-это логическое значение, которое 0
( false
). Если пользователь был запрещен, значение равно 1
.
Я хотел бы исключить всех запрещенных пользователей из всех запросов по умолчанию . Я мог бы создать область запроса, а затем использовать ее везде. Однако я бы предпочел просто иметь этот чек по умолчанию.
Я также мог бы создать newQuery
Однако таким образом я не смогу отключить это поведение. Я мог бы захотеть увидеть запрещенных пользователей в моей личной админ-панели, но не смог бы, так как это ограничение будет применяться к любому запросу, сделанному через Eloquent.
Есть идеи, как решить эту проблему?


Ответы - Область действия по умолчанию для красноречивых моделей? / Default scope for Eloquent-models?

16.02.2014 07:25:31
Почему бы вам не использовать переменную config для этого:
public function newQuery($excludeDeleted = true)
{
$builder = parent::newQuery($exludeDeleted);
if (Config::get('hide_banned_users', true) !== false) {
$builder->where('banned', '=', '0');
}
return $builder;
}
и измените значение конфигурации всякий раз, когда вам нужно увидеть запрещенных пользователей.

16.02.2014 07:59:07
Это звучит очень похоже на мягкое удаление, но с banned_at
вместо deleted_at
. Если поведение по умолчанию-не показывать запрещенных пользователей, я думаю, что более интуитивно понятно явно попросить запрещенных (напримерwithTrashed
), когда они вам нужны (панель администратора).


04.02.2015 07:05:30
Я настоятельно рекомендую использовать шаблон проектирования репозитория для запросов БД вместо выполнения прямых красноречивых запросов в контроллерах и везде.
// 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 действительно легко распространять небольшие красноречивые запросы здесь и там, но в долгосрочной перспективе это будет действительно раздражать, чтобы обновить/изменить и справиться. Попробуйте поискать Laravel Design Pattern
, и там будет много информации и примеров. Сделал мой день уже пару раз.
Этот паттерн также позволяет легче отделаться от всего красноречивого с чем-то другим, если это необходимо.

19.04.2019 07:37:39
Laravel предоставляет глобальные области именно для этой цели. Из документов:
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);
}
}

21.01.2020 12:14:52
Отвечая здесь для других, которые могут искать аналогичный ответ.
Вы можете создать глобальную область, заставить модель использовать глобальную область по умолчанию,а затем использовать 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();