Basit bir eticaret sisteminde products ve images tablolarım var. Birbirlerine hasMany ilişkisi ile bağlılar.
Ürün silindiğinde resim de silinecek. Görselin veritabanındaki kaydı silindiğinde dosyayı da silmek için observer oluşturdum ama observer tetiklenmiyor.
İlişkili Tablodaki Verinin Silinmesini Observer ile Yakalamak
Selamlar, Observer
oluşturduktan sonra AppServiceProvider
içerisindeki (ya da register edilmiş herhangi bir ServiceProvider
) boot
metodu içerisinde register ettiniz mi? Eğer etmediyseniz aşağıdaki gibi register edebilirsiniz;
Image::observe(ImageObserver::class);
Ya da ayrı bir Observer
oluşturmak yerine model içerisinde bu işlemi gerçekleştirebilirsiniz;
protected static function boot()
{
parent::boot();
self::deleted(function (self $image) {
Storage::delete($image->path);
});
}
- Düzenlendi
Laravel dökümantasyonundaki gibi modelde php arttibute kullanımıyla kullandım. Bunu da deneyeceğim
Denedim bir değişim yok. Observer benim kullanımımda doğru zaten. Direkt olarak Image sınıfını kullanarak bir görsel sildiğimde observer tetikleniyor. Ama bir ürünü silip relation ile görsel silindiğinde observer tetiklenmiyor. Şuan sıkıntı bu.
aybarsalvarci Observer bir Eloquent özelliği. Düz SQL ile silme yaparsanız tetiklenmez.
Bu örnekte observer ve model eventları tetiklenir:
$products = Product::whereIn('id', $ids)->get();
foreach($products as $product) {
// deleting ve deleted eventları tetiklenir, dolayısıyla observer da çalışır.
// çünkü model ile işlem yapılıyor:
$product->delete();
}
Aşağıdakinde ise model eventları tetiklenmez çünkü SQL ile toplu silme yapılıyor, model kullanılmıyor ve dolayısıyla Eloquent özellikleri devreye girmiyor:
$products = Product::whereIn('id', $ids)
->delete();
Ayrıca images tablosunda product_id için ON DELETE CASCADE kullandıysanız (cascadeOnDelete() yöntemi ile) ilişkili kayıtlar veri tabanı düzeyinde silineceği için resimler silinmez.
@mgsmus Anladım teşekkür ederim. Görselleri teker teker silmem gerekiyor bu durumda.
aybarsalvarci Evet. Ürünler silinirken her bir ürünün görselleri de (eğer bir model ise) aynı şekilde tek tek silinmeli.
ProductObserver:
public function deleted(Product $product): void
{
foreach($product->images as $image) {
// $image karşılık gelen modelde de deleting ve deleted tetiklenir:
$image->delete();
}
}
Elbette bu tamamen her iki modelde de event/observer ile yapmak isterseniz.
Şöyle de yapılabilir:
$product = Product::findOrFail($id);
$images = $product->images()
->pluck('path', 'id')
->toArray();
DB::transaction(function() {
if($images) {
$product->images()
->whereIn('id', array_keys($images))
->delete();
}
$product->delete();
});
if($images) {
Storage::delete(array_values($images));
}
Anladım. Detaylı anlatım için teşekkür ederim.