Kembali ke Artikel
10 November 2025
vandyahmad24
Diperbarui: 18 April 2026

Contoh Implementasi Observer di Laravel 12: Auto-Slug, Audit Trail, dan Cache

Artikel ini melanjutkan penjelasan konsep Observer di Laravel 12 dengan studi kasus implementasi lengkap: sistem audit trail dan auto-slug generation.

Studi Kasus 1: Auto-Slug Generation

Masalah umum: setiap kali artikel dibuat atau diupdate, slug harus di-generate dari title. Tanpa Observer, logika ini tersebar di berbagai controller.

Dengan Observer, cukup satu tempat:

<?php

namespace AppObservers;

use AppModelsArticle;
use IlluminateSupportStr;

class ArticleObserver
{
    public function creating(Article $article): void
    {
        $article->slug = $this->generateUniqueSlug($article->title);
    }

    public function updating(Article $article): void
    {
        if ($article->isDirty('title')) {
            $article->slug = $this->generateUniqueSlug($article->title, $article->id);
        }
    }

    private function generateUniqueSlug(string $title, ?int $excludeId = null): string
    {
        $slug  = Str::slug($title);
        $query = Article::where('slug', $slug);

        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        if (!$query->exists()) {
            return $slug;
        }

        // Tambah angka kalau slug sudah ada
        $counter = 1;
        while (Article::where('slug', "{$slug}-{$counter}")
                      ->when($excludeId, fn ($q) => $q->where('id', '!=', $excludeId))
                      ->exists()) {
            $counter++;
        }

        return "{$slug}-{$counter}";
    }
}

Studi Kasus 2: Audit Trail Otomatis

Rekam semua perubahan pada model penting, berguna untuk compliance, debugging, atau fitur “lihat riwayat perubahan”:

<?php

namespace AppObservers;

use AppModelsArticle;
use AppModelsAuditLog;

class ArticleObserver
{
    public function created(Article $article): void
    {
        $this->log('created', $article, [], $article->getAttributes());
    }

    public function updated(Article $article): void
    {
        $this->log('updated', $article, $article->getOriginal(), $article->getChanges());
    }

    public function deleted(Article $article): void
    {
        $this->log('deleted', $article, $article->getAttributes(), []);
    }

    private function log(string $action, Article $article, array $old, array $new): void
    {
        AuditLog::create([
            'user_id'     => auth()->id(),
            'model_type'  => Article::class,
            'model_id'    => $article->id,
            'action'      => $action,
            'old_values'  => $old,
            'new_values'  => $new,
            'ip_address'  => request()->ip(),
        ]);
    }
}

Model AuditLog:

Schema::create('audit_logs', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
    $table->string('model_type');
    $table->unsignedBigInteger('model_id');
    $table->string('action'); // created, updated, deleted
    $table->json('old_values')->nullable();
    $table->json('new_values')->nullable();
    $table->string('ip_address')->nullable();
    $table->timestamp('created_at');

    $table->index(['model_type', 'model_id']);
});

Studi Kasus 3: Cache Invalidation

Cache artikel halaman statis dan harus di-clear saat artikel berubah:

<?php

namespace AppObservers;

use AppModelsArticle;
use IlluminateSupportFacadesCache;

class ArticleObserver
{
    public function saved(Article $article): void
    {
        // Clear cache artikel individual
        Cache::forget("article:{$article->id}");
        Cache::forget("article:{$article->slug}");

        // Clear cache daftar artikel
        Cache::forget('articles:latest');
        Cache::forget("articles:category:{$article->category_id}");
    }

    public function deleted(Article $article): void
    {
        Cache::forget("article:{$article->id}");
        Cache::forget("article:{$article->slug}");
        Cache::forget('articles:latest');
    }
}

Studi Kasus 4: Observer dengan Multiple Models

Kalau beberapa model butuh audit trail yang sama, buat Observer yang reusable:

<?php

namespace AppObservers;

use AppModelsAuditLog;

class AuditableObserver
{
    public function created($model): void
    {
        AuditLog::create([
            'user_id'    => auth()->id(),
            'model_type' => get_class($model),
            'model_id'   => $model->id,
            'action'     => 'created',
            'new_values' => $model->getAttributes(),
        ]);
    }

    public function updated($model): void
    {
        AuditLog::create([
            'user_id'    => auth()->id(),
            'model_type' => get_class($model),
            'model_id'   => $model->id,
            'action'     => 'updated',
            'old_values' => $model->getOriginal(),
            'new_values' => $model->getChanges(),
        ]);
    }
}

Register ke beberapa model sekaligus:

// Di AppServiceProvider
Article::observe(AuditableObserver::class);
Product::observe(AuditableObserver::class);
Order::observe(AuditableObserver::class);

Bypass Observer saat Seeding

<?php

namespace DatabaseSeeders;

use AppModelsArticle;

class ArticleSeeder extends Seeder
{
    public function run(): void
    {
        // Bypass observer agar tidak trigger audit trail saat seeding
        Article::withoutObservers(function () {
            Article::factory(100)->create();
        });
    }
}

Baca Juga

Butuh tim yang bantu implementasi arsitektur yang clean di aplikasi Laravel? Lihat layanan pengembangan aplikasi kami.

Tag: #laravel #php #tutorial
BACA JUGA

Artikel Lainnya di Kategori Laravel

Laravel

10 November 2025

Apa Itu Contract di Laravel 12? Penjelasan Simpel + Contoh Kode

Bayangkan Anda membangun fitur notifikasi. Hari ini kirim via email, bulan depan ditambah WhatsApp, tahun depan mungkin push notification. Kalau kode Anda langsung bergantung ke implementasi email spesifik, setiap perubahan akan memaksa Anda menyentuh banyak file sekaligus. Di sinilah Contract di Laravel 12 berguna. Apa Itu Contract di Laravel 12? Contract di Laravel adalah sekumpulan […]

Baca Artikel
Laravel

9 November 2025

Notification di Laravel 12: Email, Database, dan Channel Kustom

Hampir semua aplikasi web butuh notifikasi: konfirmasi order, reset password, atau pemberitahuan saat ada komentar baru. Laravel punya sistem notifikasi yang cukup fleksibel: satu kelas bisa kirim ke email, database, Slack, dan channel lain sekaligus. Artikel ini membahas cara kerja notification di Laravel 12, mulai dari membuat kelas notifikasi, kirim via email dan database, sampai […]

Baca Artikel
Laravel

9 November 2025

Tutorial PostgreSQL di Laravel: Setup, JSONB, dan Full-Text Search

Laravel secara default menggunakan MySQL. Tapi kalau proyek Anda butuh fitur seperti JSON columns yang lebih canggih, full-text search bawaan, atau JSONB, PostgreSQL adalah pilihan yang solid. Artikel ini membahas cara setup PostgreSQL di Laravel, termasuk konfigurasi, perbedaan dengan MySQL, dan fitur-fitur PostgreSQL yang bisa dimanfaatkan langsung dari Eloquent. Instalasi dan Konfigurasi Pastikan extension PHP […]

Baca Artikel

Ingin Membaca Artikel Lainnya?

Temukan lebih banyak insight dan tips tentang teknologi dan bisnis digital.

Lihat Semua Artikel