Laravel Observer Sistemi
3 min readNov 5, 2024
Laravel Observer sistemini detaylıca inceleyelim:
1. Observer Nedir?
- Model olaylarını (events) dinlemek ve yönetmek için kullanılan sınıflardır
- Eloquent model olaylarını merkezi bir noktadan yönetmeyi sağlar
- SOLID prensiplerine uygun kod yazmayı destekler
2. Ne Zaman Kullanılır?
Örnek senaryolar:
- Kullanıcı kaydedildiğinde otomatik profil oluşturma
- Ürün stok değişimlerini loglama
- Sipariş durumu değiştiğinde bildirim gönderme
- Dosya silindiğinde storage'dan fiziksel silme işlemi
- Veri değişikliklerinde cache temizleme
3. Observer Oluşturma ve Kaydetme:
a) Observer Oluşturma:
# Observer oluşturma komutu
php artisan make:observer UserObserver --model=User
b) Observer Yapısı:
class UserObserver
{
public function created(User $user)
{
// Kullanıcı oluşturulduğunda
}
public function updated(User $user)
{
// Kullanıcı güncellendiğinde
}
public function deleted(User $user)
{
// Kullanıcı silindiğinde
}
public function restored(User $user)
{
// Soft delete'den geri getirildiğinde
}
public function forceDeleted(User $user)
{
// Zorla silindiğinde
}
}
c) Observer Kaydetme:
// app/Providers/EventServiceProvider.php
use App\Models\User;
use App\Observers\UserObserver;
public function boot()
{
User::observe(UserObserver::class);
}
4. Observer Metodları ve Kullanımları:
a) Creating/Created:
public function creating(User $user)
{
// Kayıt olmadan önce
$user->uuid = Str::uuid();
}
public function created(User $user)
{
// Kayıt olduktan sonra
Profile::create(['user_id' => $user->id]);
}
b) Updating/Updated:
public function updating(User $user)
{
// Güncelleme olmadan önce
if ($user->isDirty('email')) {
$user->email_verified_at = null;
}
}
public function updated(User $user)
{
// Güncelleme olduktan sonra
if ($user->wasChanged('password')) {
Notification::send($user, new PasswordChanged);
}
}
c) Deleting/Deleted:
public function deleting(User $user)
{
// Silinmeden önce
Storage::delete($user->avatar_path);
}
public function deleted(User $user)
{
// Silindikten sonra
Log::info("User {$user->email} was deleted");
}
5. Pratik Örnekler:
a) Ürün Stok Takibi:
class ProductObserver
{
public function updated(Product $product)
{
if ($product->wasChanged('stock')) {
// Stock değişim logu
StockLog::create([
'product_id' => $product->id,
'old_stock' => $product->getOriginal('stock'),
'new_stock' => $product->stock,
'type' => $product->stock > $product->getOriginal('stock')
? 'increase'
: 'decrease'
]);
// Düşük stok bildirimi
if ($product->stock <= $product->min_stock) {
Notification::send(
User::role('inventory-manager')->get(),
new LowStockAlert($product)
);
}
}
}
}
b) Sipariş Durumu Takibi:
class OrderObserver
{
public function updating(Order $order)
{
if ($order->isDirty('status')) {
$order->status_changes = array_merge(
$order->status_changes ?? [],
[
'from' => $order->getOriginal('status'),
'to' => $order->status,
'at' => now(),
'by' => auth()->id()
]
);
}
}
public function updated(Order $order)
{
if ($order->wasChanged('status')) {
// Müşteriye bildirim
$order->customer->notify(new OrderStatusChanged($order));
// Status'a göre işlemler
match ($order->status) {
'shipped' => $this->handleShipped($order),
'delivered' => $this->handleDelivered($order),
'cancelled' => $this->handleCancelled($order),
default => null
};
}
}
}
6. Advanced Kullanımlar:
a) Conditional Observers:
class UserObserver
{
public function created(User $user)
{
if ($user->shouldCreateProfile()) {
Profile::create(['user_id' => $user->id]);
}
}
}
b) Queue Kullanımı:
class UserObserver
{
public function created(User $user)
{
// Arka planda çalıştırma
ProcessUserRegistration::dispatch($user);
}
}
c) Cache Yönetimi:
class PostObserver
{
public function saved(Post $post)
{
Cache::tags(['posts'])->flush();
}
}
7. Observer ile Event Farkları:
// Observer Yaklaşımı
class UserObserver
{
public function created(User $user)
{
// İşlemler burada
}
}
// Event Yaklaşımı
class UserCreated
{
public $user;
public function __construct(User $user)
{
$this->user = $user;
}
}
class SendWelcomeEmail
{
public function handle(UserCreated $event)
{
// İşlemler burada
}
}
8. Testing:
class UserObserverTest extends TestCase
{
public function test_profile_is_created_when_user_is_created()
{
$user = User::factory()->create();
$this->assertDatabaseHas('profiles', [
'user_id' => $user->id
]);
}
public function test_notification_is_sent_when_password_changed()
{
Notification::fake();
$user = User::factory()->create();
$user->update(['password' => 'new-password']);
Notification::assertSentTo($user, PasswordChanged::class);
}
}
9. Best Practices:
Single Responsibility:
// Kötü
public function updated(User $user)
{
// Profile güncelle
// Mail gönder
// Cache temizle
// Log tut
}
// İyi
public function updated(User $user)
{
$this->updateProfile($user);
$this->sendNotifications($user);
$this->handleCache($user);
$this->logChanges($user);
}
Error Handling:
public function created(User $user)
{
try {
Profile::create(['user_id' => $user->id]);
} catch (Exception $e) {
Log::error('Profile creation failed', [
'user' => $user->id,
'error' => $e->getMessage()
]);
}
}
Performance Optimization:
public function updated(Post $post)
{
if (!$post->wasChanged()) {
return;
}
Cache::tags(['posts'])->flush();
}