Kembali ke Artikel
10 November 2025
Diperbarui: 25 Mei 2026

Tutorial Laravel 12: Menggunakan Context Facade untuk Propagasi Data

laravel

Laravel 12 nambah fitur baru namanya Context. Kalau kamu pernah bingung gimana caranya nyebarin data kayak tenant_id, request_id, atau user_id ke semua log, job, dan event tanpa harus ngoper variabel ke mana-mana — ini solusinya.

Tutorial ini bahas Context dari dasar sampai implementasi nyata. Cocok buat kamu yang udah familiar sama Laravel tapi belum pernah pakai Context facade.

Apa Itu Context di Laravel 12?

Context adalah cara Laravel nyimpen data yang terikat sama satu request atau satu eksekusi. Data ini bisa diakses dari mana aja tanpa harus ngoper variabel ke tiap fungsi atau class.

Bayangin kamu punya aplikasi multi-tenant. Setiap request butuh tahu tenant_id-nya siapa. Biasanya kamu harus:

  • Ngirim $tenantId ke controller
  • Terus ke service
  • Terus ke repository
  • Terus ke job
  • Terus ke log

Ribet. Context bikin ini jadi simpel:

use Illuminate\Support\Facades\Context;

// Set sekali di middleware
Context::add('tenant_id', 123);

// Ambil di mana aja
$tenantId = Context::get('tenant_id'); // 123

Data ini otomatis ikut ke log, job, event, dan exception yang terjadi dalam request yang sama.

Cara Pakai Context: Dasar

Context tersedia lewat facade Illuminate\Support\Facades\Context atau helper context().

Menambah Data ke Context

Context::add('request_id', 'REQ-20260525-0001');
Context::add('user_id', 42);

// Atau sekaligus
Context::add([
    'request_id' => 'REQ-20260525-0001',
    'user_id' => 42,
]);

Mengambil Data dari Context

$requestId = Context::get('request_id');

// Dengan default value kalau tidak ada
$userId = Context::get('user_id', 0);

Menghapus Data dari Context

// Hapus satu key
Context::forget('request_id');

// Hapus semua
Context::flush();

Studi Kasus 1: Request ID di Semua Log

Masalah klasik: saat ada error, susah tahu log mana yang terkait satu request. Apalagi kalau traffic tinggi, log campur aduk.

Solusinya: bikin middleware yang nambah request ID ke Context.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;

class AddRequestContext
{
    public function handle(Request $request, Closure $next): mixed
    {
        Context::add([
            'request_id' => Str::uuid()->toString(),
            'url'        => $request->fullUrl(),
            'method'     => $request->method(),
            'ip'         => $request->ip(),
            'user_id'    => $request->user()?->id,
        ]);

        return $next($request);
    }
}

Daftarkan di bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->prepend(AddRequestContext::class);
})

Sekarang semua log otomatis punya context:

Log::info('Memproses pembayaran');

// Output di log:
// [2026-05-25 10:23:45] local.INFO: Memproses pembayaran 
// {"request_id":"abc-123","url":"/checkout","user_id":42}

Kalau ada error, tinggal cari semua log dengan request_id yang sama. Debugging jadi jauh lebih gampang.

Studi Kasus 2: Multi-Tenancy dengan Context

Aplikasi multi-tenant butuh tenant_id di hampir semua query. Biasanya kamu harus ngirim $tenantId ke mana-mana. Dengan Context, cukup set sekali di middleware:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;

class ResolveTenant
{
    public function handle(Request $request, Closure $next): mixed
    {
        // Resolve tenant dari subdomain atau header
        $tenant = $this->getTenantFromRequest($request);

        Context::add('tenant_id', $tenant->id);

        return $next($request);
    }

    private function getTenantFromRequest(Request $request)
    {
        // Contoh: dari subdomain
        $subdomain = explode('.', $request->getHost())[0];
        return Tenant::where('subdomain', $subdomain)->firstOrFail();
    }
}

Sekarang di service atau repository, tinggal ambil dari Context:

class OrderService
{
    public function getCurrentTenantOrders()
    {
        $tenantId = Context::get('tenant_id');

        return Order::where('tenant_id', $tenantId)->get();
    }
}

Catatan penting: Jangan bergantung 100% pada Context untuk data bisnis kritis. Kalau kamu jalanin Artisan command atau test, Context mungkin kosong. Selalu kasih default value atau cek null.

Studi Kasus 3: Propagasi Context ke Queue Jobs

Masalah: ketika request trigger job di queue, context (request ID, user ID) hilang karena job jalan di worker terpisah.

Kabar baiknya: Context otomatis dipropagasi ke jobs kalau job implement ShouldQueue.

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Log;

class ProcessPayment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public function __construct(
        private int $orderId
    ) {}

    public function handle(): void
    {
        // Context dari request yang dispatch job ini otomatis tersedia
        $requestId = Context::get('request_id');

        Log::info("Memproses pembayaran order {$this->orderId}", [
            'request_id' => $requestId,
        ]);

        // proses pembayaran...
    }
}

Best practice: Untuk data penting kayak tenant_id, simpan juga sebagai property Job. Jangan cuma andalin Context, karena lifecycle worker bisa beda-beda.

Studi Kasus 4: Hidden Context untuk Data Sensitif

Kadang kamu butuh data di Context tapi nggak mau muncul di log (misalnya token atau API key).

// Tambah context tersembunyi — tidak masuk ke log
Context::addHidden([
    'payment_token' => $request->payment_token,
    'api_key'       => config('services.payment.key'),
]);

// Ambil di bagian lain
$token = Context::getHidden('payment_token');

Data ini tetap bisa diakses di kode, tapi nggak akan muncul di log output.

Kapan Pakai Context vs Dependency Injection?

Context bukan pengganti dependency injection. Ini panduan kapan pakai mana:

Pakai Context kalau:

  • Data perlu tersebar ke banyak layer (log, job, event) tanpa ubah signature
  • Multi-tenant: tenant_id butuh ada di mana-mana
  • Request tracing: request_id untuk debugging
  • Feature flags: tracking fitur apa yang aktif per request

Pakai Dependency Injection kalau:

  • Data bisnis yang jelas dependensinya (misal OrderService butuh PaymentGateway)
  • Konfigurasi statis (cukup lewat config atau env)
  • Kode yang perlu di-test dengan mock/stub

Intinya: Context untuk data “ambient” yang perlu ada di mana-mana. DI untuk dependensi eksplisit yang jelas.

Testing Kode yang Pakai Context

Di test, kamu harus set Context secara manual:

use Illuminate\Support\Facades\Context;

public function test_service_menggunakan_tenant_dari_context()
{
    Context::flush(); // Pastikan kosong dulu
    Context::add('tenant_id', 10);

    $service = app(OrderService::class);
    $orders = $service->getCurrentTenantOrders();

    $this->assertTrue(
        $orders->every(fn ($order) => $order->tenant_id === 10)
    );
}

Jangan lupa Context::flush() di setUp() atau tearDown() biar nggak ada kebocoran state antar test.

Pitfall yang Harus Dihindari

1. Overuse Context = Global State

Kalau semua data masuk Context, kode jadi susah di-trace. Pakai Context cuma untuk data yang emang perlu ada di mana-mana.

2. Lupa Guard di CLI/Artisan

Artisan command jalan tanpa request, jadi Context bisa kosong. Selalu kasih default:

$tenantId = Context::get('tenant_id');

if (is_null($tenantId)) {
    throw new \RuntimeException('Tenant ID tidak tersedia di context');
}

3. Ubah Context di Layer Bawah

Kalau middleware A set tenant_id, jangan ubah lagi di service atau repository. Bikin aturan: Context cuma di-set di middleware, layer lain cuma baca.

Ringkasan

Context facade di Laravel 12 bikin kamu bisa nyebarin data ke seluruh aplikasi tanpa harus ngoper variabel ke mana-mana. Cocok buat:

  • Request tracing dengan request_id
  • Multi-tenancy dengan tenant_id
  • Feature flags dan debugging
  • Propagasi data ke log, job, dan event

Tapi ingat: jangan overuse. Pakai Context untuk data ambient, pakai DI untuk dependensi eksplisit.

Baca Juga

Butuh tim yang bantu setup observability dan logging yang proper di aplikasi Laravel? Lihat layanan pengembangan aplikasi kami.

Tag: #laravel #php #tutorial
BACA JUGA

Artikel Lainnya di Kategori Laravel

Ingin Membaca Artikel Lainnya?

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

Lihat Semua Artikel