Возможности Eloquent
Модель Eloquent — не только доступ к таблице. В ней собирают всё, что относится к данным: частые условия запросов, преобразование значений, правила удаления. Тогда контроллеры остаются короткими.
Области запросов
Условие, которое повторяется в разных местах, выносят в модель. Метод помечают атрибутом Scope:
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
#[Scope]
protected function published(Builder $query): void
{
$query->where('is_published', true);
}
}$posts = Post::published()->latest()->get();В версиях до Laravel 12 метод называют scopePublished, а вызывают так же — published().
Преобразование типов
База возвращает всё строками и числами. Метод casts() указывает, во что превращать столбцы:
class Post extends Model
{
protected function casts(): array
{
return [
'is_published' => 'boolean',
'published_at' => 'datetime',
'settings' => 'array',
'price' => 'decimal:2',
];
}
}Теперь $post->published_at — объект даты с методами, а $post->settings — массив, который хранится в базе как JSON.
echo $post->published_at->format('d.m.Y');
echo $post->published_at->diffForHumans();Вычисляемые свойства
Аксессор изменяет значение при чтении, мутатор — при записи:
use Illuminate\Database\Eloquent\Casts\Attribute;
class User extends Model
{
protected function name(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
protected function fullName(): Attribute
{
return Attribute::make(
get: fn () => "{$this->first_name} {$this->last_name}",
);
}
}$user->full_name работает как обычное свойство, хотя такого столбца в таблице нет.
Мягкое удаление
С трейтом SoftDeletes запись не удаляется, а помечается датой в столбце deleted_at. Обычные запросы её больше не видят:
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
}В миграции столбец создаёт $table->softDeletes().
$post->delete();
Post::withTrashed()->get(); // включая удалённые
Post::onlyTrashed()->get(); // только удалённые
$post->restore();
$post->forceDelete(); // удалить окончательноСоздать или обновить
$user = User::firstOrCreate(
['email' => 'anna@example.com'],
['name' => 'Anna'],
);
$setting = Setting::updateOrCreate(
['key' => 'theme'],
['value' => 'dark'],
);Первый массив — условие поиска, второй — значения для новой или обновляемой записи.
События модели
Модель сообщает о своих изменениях. Обработчики регистрируют в методе booted():
use Illuminate\Support\Str;
class Post extends Model
{
protected static function booted(): void
{
static::creating(function (Post $post) {
$post->slug = Str::slug($post->title);
});
}
}Есть события creating, created, updating, updated, deleting, deleted.
Частая ошибка
События не срабатывают при массовых запросах. Post::where('user_id', 5)->delete() удаляет строки одним запросом и не вызывает обработчики deleting. Если они нужны, удаляйте модели по одной:
Post::where('user_id', 5)->get()->each->delete();