Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Возможности 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();

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.