Урок 11

Продвинутые техники Eloquent

Сравнение моделей

if ($post->is($anotherPost)) {
    // та же запись
}

if ($post->isNot($anotherPost)) {
    // разные записи
}

Обновление связанных меток времени

Если нужно обновлять updated_at родителя при изменении дочерней модели:

class Comment extends Model
{
    protected $touches = ['post'];

    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}

Теперь при обновлении комментария обновится и post.updated_at.

Свежие данные

$fresh = $post->fresh(); // новый объект из БД
$post->refresh(); // обновляет текущий объект

Клонирование

$copy = $post->replicate();
$copy->title = 'Копия';
$copy->save();

Условная загрузка

$posts = Post::with(['comments' => function ($query) {
    $query->when($request->has('approved'), fn ($q) => $q->where('approved', true));
}])->get();

Chunk и Cursor для больших данных

Post::chunk(200, function ($posts) {
    foreach ($posts as $post) {
        // обработка
    }
});

foreach (Post::cursor() as $post) {
    // обработка
}

chunk выполняет несколько запросов, cursor — один. cursor экономит память.

События модели

protected static function booted(): void
{
    static::creating(function ($post) {
        $post->slug = Str::slug($post->title);
    });

    static::deleted(function ($post) {
        // очистка связанных данных
    });
}

События: retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored.

Pruning старых записей

Модель может сама удалять старые записи:

use Illuminate\Database\Eloquent\Prunable;
use Illuminate\Database\Eloquent\MassPrunable;

class LoginLog extends Model
{
    use MassPrunable;

    public function prunable()
    {
        return static::where('created_at', '<=', now()->subDays(30));
    }
}

Запуск:

php artisan model:prune