“Bazı veriler veritabanında kaybolmaz”
“Bazı veriler veritabanında kaybolmaz”
Senaryoyu hayal et: müşteri, çalışan bir siparişi yanlışlıkla sildiği için panikle arıyor. Veritabanını açıyorsun ve… yok. Silindi. DELETE her zaman DELETEdir. Şimdi yedek mi alacaksın, yoksa ağlayacak mısın?
Şimdi aynı senaryoya bakalım, ama $siparis->restore() yazıyorsun ve kayıt geri geliyor. Günü kurtardın.
Bunun çözümü Soft Delete: Gerçekten satırı silmek yerine, Laravel onu silinmiş olarak işaretler ve sorgularda artık görünmez hale getirir. Hâlâ orada durur, sadece görünmezdir. İstediğin zaman geri getirebilirsin.
Problem: delete() kesindir
Problem:
delete() kesindirSoft delete yoksa, bu işlem geri döndürülemez:
$siparis->delete(); // elveda. sonsuza kadar. 💀
Veritabanında, raporlarda, hatta hayatın her alanında silinenler. Biri yanlışlıkla silerse veya bir denetim için geçmişe dönük verilere ihtiyaç duyarsan kayıp. Üretim ortamında “yanlışlıkla silmek” ne kadar sık gerçekleştiğine inanamazsın.
Çözüm: Üç adımda hallet
Çözüm: Üç adımda hallet
Öncelikle, migration’ınıza deleted_at sütununu ekleyin. Laravel bunun için özel bir yardımcıya sahiptir:
Schema::table('siparisler', function (Blueprint $table) {
$table->softDeletes(); // deleted_at sütununu oluşturur (nullable)
});
Daha sonra, model’inizde SoftDeletes trait’ini kullanın:
use Illuminate\Database\Eloquent\SoftDeletes;
class Siparis extends Model
{
use SoftDeletes;
}
Artık delete() işlemi, başka hiçbir şey yapmadan davranışını değiştirdi:
$siparis->delete();
// satırı silmez — yalnızca deleted_at sütununu şu anki tarih/saat ile doldurur
Ve en iyisi: normal sorgular otomatik olarak silinmiş kayıtları görmezden gelir. Siparis::all() soft-delete edilen hiçbir şeyi getirmez. El ile filtrelemene gerek yok.
Geri getirme ve silinmişleri görme
Geri getirme ve silinmişleri görme
Geri getirme işlemi bir satırdır:
$siparis->restore(); // deleted_at null olur, kayıt "hayata döner"
Silinmişleri incelemek için withTrashed kullanabilirsin:
Siparis::withTrashed()->get(); // her şeyi, silinmiş olanlarla birlikte getirir
Yalnızca silinmişleri görmek için (bir “çöp kutusu” ekranı oluşturmak için):
Siparis::onlyTrashed()->get();
Ve gerçekten silmek gerekiyorsa, o zaman geri dönüşü olmayan bir işlem:
$siparis->forceDelete(); // artık gerçekten gitmiştir
Pratikte nasıl kullanılır
Pratikte nasıl kullanılır
Kullanıcı için çöp kutusu. Kullanıcının öğeleri sildiği bir ekran, ancak 30 gün içinde geri yükleme yapma fırsatı var. onlyTrashed() listeler, restore() geri yükler.
Denetim ve geçmiş. Finans ve hukuk gibi sektörler genellikle hiçbir şeyin kaybolmamasını talep eder. Soft delete, günlük ekranları kirletmeden iz bırakmanızı sağlar.
Kodda durumu kontrol etme. Bir kaydın silinmiş olup olmadığını kontrol edebilirsin:
if ($siparis->trashed()) {
// bu kayıt çöp kutusunda
}
Tuzağın 1: unique soft delete’i bilmez
Tuzağın 1:
unique soft delete’i bilmezBu, birçok kişinin başına gelir. Senin bir email kolonun var ve bu kolon için unique indeksi var. Kullanıcı [email protected] soft-deleted oldu. Yeniden kaydolmaya çalıştığında, veritabanı reddeder çünkü eski satır hâlâ orada, e-posta adresini kaplayarak.
Veritabanındaki unique, deleted_at‘dan etkilenmez — onun için, kayıt hâlâ mevcuttur. Doğrulamada bunu açıkça belirtmelisin. unique kuralında, silinmiş olanları göz ardı et:
use Illuminate\Validation\Rule;
Rule::unique('kullanicilar', 'email')->whereNull('deleted_at');
Bu şekilde doğrulama yalnızca aktif kayıtları dikkate alır ve soft delete ile “serbest bırakılan” e-posta adresi kullanılır hale gelir.
Tuzağın 2: Silinmiş kayıt ile ilişki
Tuzağın 2: Silinmiş kayıt ile ilişki
Bu da kafa karıştırabilir. Sipariş soft-deleted oldu, ancak onu bir ilişkide yüklemeye çalıştığında kayıt kaybolur:
$musteri->siparisler; // silinmiş siparişler gelmez
Bu çoğu zaman istediğin şeydir. Ama bu böyle değilse — tam müşteri geçmişini oluşturmak gibi — ilişki de withTrashed ile yüklenebilir:
public function siparisler()
{
return $this->hasMany(Siparis::class)->withTrashed();
}
Veya model’i değiştirmeden anlık olarak:
$musteri->siparisler()->withTrashed()->get();
Bonus: Peki şimdi?
Bonus: Peki şimdi?
Projenizin tablolarına bakın ve her biri için kendinize sorun: “Eğer biri bunu yanlışlıkla silerse, sorun olur mu?” Sipariş, fatura, sözleşme, kullanıcı — büyük ihtimalle evet. Test için oluşturup attığınız kategori — muhtemelen hayır. Soft delete harika, ancak her yerde olmamalı; ekstra bir sütun ve daha karmaşık bir sorgu maliyet oluşturur.
Ve “her şeyi sonsuza dek saklamak” fikrine dikkat edin. Verilerin türüne bağlı olarak (örneğin LGPD), bir süre sonra gerçekten silmek zorunda olabilirsiniz. Bu durumda, eski kayıtlarla birlikte bir iş oluşturmak forceDelete() ile halledebilir.
Sekmeyi kapatmadan önce
Sekmeyi kapatmadan önce
Hiç delete() ile önemli bir kaydı üretim ortamında kaybettiniz mi? Yoksa önceden konulmuş bir soft delete ile kurtuldunuz mu?
Bu konular hakkında düşüncelerinizi aşağıda paylaşın. Bu makalenin projenizde ileride bir felaket yaşamaktan kaçınmanıza yardımcı olabileceğini düşünüyorsanız, kaydedin ve hala her şeyi doğrudan veritabanında silen bir arkadaşınıza gönderin. 😅
Kaynak: Orijinal Makale


