Очистка моделей

pruning models

В Laravel 8.50 появилась новая функция Models Pruning (Очистка моделей). С помощью неё можно автоматически зачищать модели от старых записей.

Предположим, что у нас есть чат и нам нужно удалять все сообщения старше одной недели. Добавляем в модель трейт Illuminate\Database\Eloquent\Prunable и реализуем метод prunable, который должен вернуть конструктор запросов с условиями очищения.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;

class Message extends Model
{
    use Prunable;
    
    public function prunable()
    {
        return static::where('created_at', '<=', now()->subDays(7));
    }
}

Также можно реализовать метод pruning, который выполнится перед очисткой экземпляра модели. Например мы можем удалить приаттаченные к сообщению файлы.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;

class Message extends Model
{
    use Prunable;

    public function attachment()
    {
        return $this->hasOne(Attachment::class);
    }

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

    protected function pruning()
    {
        return $this->attachment->delete();
    }    
}

Чтобы всё это заработало нужно запланировать выполнение команды model:prune в App\Console\Kernel с определенным интервалом. Зададим ежедневную очистку:

/**
 * Define the application's command schedule.
 *
 * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
 * @return void
 */
protected function schedule(Schedule $schedule)
{
    $schedule->command('model:prune')->daily();
}

Если необходимо задать разный интервал для разных моделей, то используйте опцию --model. Сами классы можно перечислять через запятую:

$schedule->command('model:prune', [
    '--model' => [Message::class, Attachment::class],
])->daily();

Также есть трейт Illuminate\Database\Eloquent\MassPrunable. Он позволяет очищать модели с помощью запросов массового удаления, в отличии от первого трейта, который удаляет по одному экземпляру. Обратите внимание, что в таком случае не будет вызываться метод pruning и не будут отправляться события deleting и deleted, так как, в целях быстродействия, модели не извлекаются перед удалением.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\MassPrunable;

class Message extends Model
{
    use MassPrunable;

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

Автор: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.