Cara Soft Delete di Laravel: Restore Data & Hapus Permanen dengan Aman (Panduan 2026)
Cara Soft Delete di Laravel: Restore Data & Hapus Permanen dengan Aman (Panduan 2026)
Soft delete di Laravel adalah cara menghapus data tanpa benar-benar menghilangkannya dari database: Laravel hanya mengisi kolom deleted_at dengan waktu penghapusan, menyembunyikan baris itu dari query biasa, dan membiarkan Anda memulihkannya kapan saja dengan restore() atau menghapusnya permanen dengan forceDelete().
Kalau Anda pernah panik karena admin salah klik hapus produk atau postingan penting — dan data itu lenyap tanpa jejak — artikel ini untuk Anda. Di toko online, kasir, maupun sistem informasi, tombol hapus yang langsung menghancurkan baris database adalah risiko yang tidak perlu. Soft delete memberi tombol "undo" yang nyata, asalkan dipasang lengkap dengan halaman sampah, aturan hapus permanen, dan jadwal pembersihan.
Apa itu Soft Delete di Laravel?
Secara default, $product->delete() di Eloquent menjalankan perintah SQL DELETE — baris hilang selamanya. Dengan trait SoftDeletes, perintah yang sama berubah menjadi UPDATE yang mengisi deleted_at. Barisnya tetap ada, tetapi Eloquent otomatis mengecualikannya dari semua query normal. Inilah perilaku yang didokumentasikan di dokumentasi Eloquent Laravel.
Artinya, tiga hal ini berlaku sekaligus:
Product::all()tidak lagi menampilkan produk yang sudah di-soft-delete.Product::find($id)mengembalikannulluntuk produk yang sudah di-soft-delete, seolah-olah tidak ada.- Data masih bisa dipulihkan penuh, termasuk relasi dan riwayatnya, selama belum di-
forceDelete().
Soft Delete vs Hard Delete: Kapan Pakai yang Mana?
Aspek Soft Delete (delete()) Hard Delete (forceDelete()) | ||
| Baris di database | Tetap ada, deleted_at terisi | Hilang permanen |
| Bisa dipulihkan? | Ya, dengan restore() | Tidak (kecuali dari backup) |
| Muncul di query biasa? | Tidak | Tidak (karena sudah tidak ada) |
| Cocok untuk | Produk, pelanggan, order, postingan | Data sampah lama, data sensitif yang wajib dihapus |
| Risiko utama | Tabel membengkak bila tak pernah dibersihkan | Salah hapus = hilang selamanya |
Aturan praktisnya: jadikan soft delete sebagai perilaku default untuk data bisnis, dan cadangkan hard delete hanya untuk pembersihan terjadwal atau permintaan penghapusan data yang sah. Untuk strategi cadangan sebelum menghapus permanen, baca juga panduan backup otomatis website Laravel.
Bagaimana Cara Mengaktifkan Soft Delete di Laravel?
Hanya ada dua langkah inti: tambah kolom deleted_at dan pasang trait di model.
Langkah 1: Tambah Kolom deleted_at Lewat Migrasi
Untuk tabel yang sudah ada, buat migrasi baru — jangan mengedit migrasi lama yang sudah jalan di produksi:
Jalankan php artisan migrate, dan kolom deleted_at (nullable timestamp) akan tersedia. Untuk tabel baru, cukup tambahkan $table->softDeletes(); di dalam Schema::create.
Langkah 2: Pasang Trait SoftDeletes di Model
Sejak titik ini, $product->delete() tidak lagi menghancurkan data. Untuk memeriksa apakah sebuah instance sudah terhapus lunak, gunakan $product->trashed() yang mengembalikan true atau false.
Bagaimana Cara Menampilkan, Memulihkan, dan Menghapus Permanen Data?
Inilah bagian yang paling sering dilewati tutorial singkat: soft delete tanpa halaman sampah sama saja bohong. Data "bisa dipulihkan" tetapi tidak ada tombolnya. Buat tiga aksi ini di controller.
1. Menampilkan Data yang Sudah Dihapus (Halaman Sampah)
Eloquent menyediakan tiga scope query khusus:
Halaman sampah sebaiknya menampilkan kolom deleted_at agar admin tahu kapan tiap baris dihapus, plus dua tombol: "Pulihkan" dan "Hapus Permanen". Urutkan dari deleted_at terbaru agar data yang baru salah hapus mudah ditemukan.
2. Memulihkan Data dengan restore()
Jebakan paling umum di sini: Product::find($id) mengembalikan null untuk data yang terhapus, sehingga restore gagal dengan error "non-object". Ambil dulu dari sampah:
Anda juga bisa memulihkan banyak baris sekaligus lewat query, tetapi ingat: restore massal tidak memicu model event untuk tiap baris, sesuai dokumentasi Laravel. Jadi kalau Anda punya listener yang mengirim notifikasi saat produk dipulihkan, gunakan loop per model, bukan restore massal.
3. Menghapus Permanen dengan forceDelete()
Untuk keamanan, jangan pernah menaruh forceDelete() di tombol yang sama mudahnya dengan hapus biasa. Praktik yang kami rekomendasikan di source code produksi:
- Hanya role admin/super admin yang boleh mengakses route
forceDelete— selaraskan dengan sistem role yang Anda pakai, misalnya seperti pada panduan multi role & permission di Laravel. - Minta konfirmasi kedua (modal konfirmasi dengan nama data yang akan dihapus).
- Catat siapa yang menghapus permanen, kapan, dan data apa — pasang activity log pada aksi ini, karena inilah satu-satunya aksi hapus yang tidak bisa di-undo.
Apa Saja Jebakan Soft Delete yang Sering Menjatuhkan Developer?
Bagian ini yang membedakan implementasi asal jalan dengan implementasi siap produksi. Empat jebakan berikut jarang dibahas tutorial dasar, tetapi semuanya pernah menimbulkan bug nyata.
1. Restore Bisa Gagal karena Kolom Unique
Skenario klasik: produk dengan SKU KOPI-001 dihapus, lalu admin membuat produk baru dengan SKU yang sama. Saat produk lama dipulihkan, database menolak karena constraint unique dilanggar. Solusinya, sebelum restore(), cek bentrokan:
Aturan validasi unique di form pun perlu disesuaikan: secara default validator Laravel mengabaikan baris yang ter-soft-delete atau tidak, tergantung aturan yang Anda tulis — uji selalu dengan skenario hapus-buat-pulihkan, bukan hanya hapus-pulihkan.
2. Relasi Tidak Ikut Terhapus atau Pulih Otomatis
Soft delete tidak bersifat cascade. Menghapus produk tidak otomatis me-soft-delete varian, gambar, atau order item-nya — dan memulihkan produk tidak otomatis memulihkan relasinya. Tentukan kebijakan eksplisit per relasi: apakah anak ikut disembunyikan, tetap tampil dengan label "produk dihapus", atau ikut dipulihkan bersama induknya. Jangan biarkan perilaku ini terjadi secara kebetulan.
3. Query dan Laporan Bisa Salah Hitung
Karena query biasa menyembunyikan data terhapus, laporan penjualan, stok, atau statistik yang memakai count() dan sum() otomatis mengecualikan data sampah — biasanya itu yang Anda mau. Tetapi berhati-hatilah pada laporan audit atau rekonsiliasi yang justru harus mencakup semua baris: di sana pakai withTrashed() secara eksplisit. Kebalikannya juga berlaku: jangan pakai withTrashed() di halaman katalog pelanggan, karena produk yang sengaja dihapus akan muncul kembali.
4. File Tidak Terhapus Saat Baris Di-soft-delete
Menghapus produk tidak menghapus file gambarnya di storage — dan itu benar, karena data masih bisa dipulihkan. File baru boleh dihapus saat forceDelete() berjalan, misalnya lewat model event forceDeleted. Detail validasi dan penyimpanan file yang aman dibahas di panduan upload file di Laravel. Jangan menghapus file pada event deleted biasa, karena restore nanti akan menghasilkan produk tanpa gambar.
Bagaimana Cara Membersihkan Sampah Lama Secara Otomatis?
Soft delete tanpa pembersihan membuat tabel membengkak. Solusinya: jadwal purge — hapus permanen data yang sudah di sampah lebih dari, misalnya, 30 hari. Di Laravel, daftarkan perintah terjadwal di scheduler:
Tiga catatan penting untuk purge ini:
- Pastikan backup jalan dulu. Purge yang menghapus ribuan baris tidak bisa di-undo; jadwalkan purge setelah backup harian, bukan sebelumnya.
- Jangan purge data yang masih terikat kewajiban hukum atau akuntansi. Order, invoice, dan data transaksi sering wajib disimpan bertahun-tahun — kecualikan model-model itu dari purge otomatis.
- Beri tahu admin. Tampilkan di halaman sampah: "Data di sampah akan dihapus permanen setelah 30 hari." Transparansi ini mencegah komplain "kok data saya hilang sendiri".
Cara Ini Tidak Cocok Jika...
Jujur saja, soft delete bukan jawaban untuk semua kasus. Jangan memakainya jika:
- Data wajib lenyap demi privasi. Permintaan penghapusan data pribadi (misalnya akun pengguna yang minta dihapus) harus benar-benar menghapus, bukan sekadar menyembunyikan — soft delete justru melanggar maksud permintaan itu.
- Tabel sangat besar dan sering ditulis. Pada tabel log jutaan baris, kolom
deleted_atdan indeks tambahannya menambah beban; arsipkan ke tabel terpisah atau hapus langsung. - Constraint unique tidak bisa ditoleransi. Bila domain Anda tidak mengizinkan duplikasi historis sama sekali, desainlah penghapusan dan arsip secara eksplisit, bukan mengandalkan
deleted_at.
Untuk kasus-kasus itu, hard delete plus backup yang solid adalah pilihan yang lebih jujur daripada soft delete setengah-setengah.
FAQ: Soft Delete Laravel
Apakah soft delete memperlambat query?
Sedikit, karena Eloquent menambahkan kondisi deleted_at IS NULL pada setiap query. Pada tabel berukuran wajar dampaknya tidak terasa; pastikan kolom deleted_at terindeks bila tabel Anda besar.
Apakah delete() pada model dengan SoftDeletes bisa dibatalkan?
Ya, selama belum forceDelete(). Gunakan restore() pada instance yang diambil lewat onlyTrashed() atau withTrashed().
Mengapa find() mengembalikan null untuk data yang saya hapus?
Karena itu perilaku yang disengaja: query normal mengecualikan data terhapus. Gunakan withTrashed()->find($id) bila Anda memang perlu mengambilnya.
Apakah soft delete menghapus data dari database?
Tidak. Baris tetap ada dengan deleted_at terisi. Hanya forceDelete() yang menjalankan DELETE sungguhan.
Bisakah soft delete dipakai bersama forceDeleteQuietly() dan restoreQuietly()?
Bisa. Varian Quietly menjalankan aksi yang sama tanpa memicu model event — berguna untuk purge massal atau seeder, tetapi jangan dipakai bila ada listener penting seperti penghapusan file.
Berapa lama sebaiknya data disimpan di sampah?
Tidak ada angka universal; 30 hari adalah titik awal yang masuk akal untuk produk dan konten. Sesuaikan dengan kebutuhan bisnis dan kewajiban penyimpanan data Anda, lalu tulis aturannya di halaman sampah.
Apakah saya perlu soft delete untuk semua model?
Tidak. Terapkan pada data bisnis yang merugikan bila hilang karena salah klik (produk, pelanggan, postingan). Untuk data sekali pakai seperti token atau log sementara, hard delete lebih tepat.
Penutup
Soft delete di Laravel hanya membutuhkan satu kolom dan satu trait, tetapi nilai sebenarnya datang dari kelengkapannya: halaman sampah, restore yang menangani bentrokan unique, forceDelete yang dijaga otorisasi dan activity log, serta purge terjadwal yang tidak berjalan tanpa backup. Pasang keempatnya, dan tombol hapus berubah dari risiko menjadi fitur yang menenangkan.
Kalau Anda membangun toko online atau sistem informasi dari source code dan ingin fitur seperti ini sudah terpasang rapi sejak awal, jelajahi katalog di kioskoding.com.
Artikel Terkait
Pollora: Framework Laravel untuk WordPress — WordPress Jalan di Dalam Aplikasi Laravel
02 Nov 2026
WordPress 7.1.4 Rilis 28 Oktober 2026: 22 Perbaikan Keamanan, Update Sekarang Jangan Tunggu 7.2
02 Nov 2026
Cara Membuat Activity Log di Laravel: Lacak Siapa Mengubah Apa (Panduan Lengkap 2026)
02 Nov 2026
PHP2Shell Masuk Katalog KEV CISA 26 Oktober 2026: Eksploitasi Terkonfirmasi, Tenggat Patch Hari Ini
30 Oct 2026