Tutorial Laravel 12: Menggunakan Context Facade untuk Propagasi Data
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
$tenantIdke 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_idbutuh ada di mana-mana - Request tracing:
request_iduntuk debugging - Feature flags: tracking fitur apa yang aktif per request
Pakai Dependency Injection kalau:
- Data bisnis yang jelas dependensinya (misal
OrderServicebutuhPaymentGateway) - 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
- Tutorial Laravel 12: Job Batching untuk Proses Batch yang Efisien
- Cara Install Laravel 12 untuk Pemula
- Cara Membuat Controller di Laravel 12
Butuh tim yang bantu setup observability dan logging yang proper di aplikasi Laravel? Lihat layanan pengembangan aplikasi kami.
Artikel Lainnya di Kategori Laravel
10 November 2025
Contoh Implementasi Policy dan Gate di Laravel 12: Studi Kasus CMS Multi-Role
Artikel ini melanjutkan penjelasan konsep Policy dan Gate di Laravel 12 dengan studi kasus implementasi lengkap: sistem manajemen konten dengan beberapa level akses. Studi Kasus: Sistem CMS dengan Multi-Role Skenario: aplikasi CMS dengan role admin, editor, dan author. Aturannya: Admin bisa lakukan semua aksi di artikel mana saja Editor bisa buat, edit, dan publish artikel […]
Baca Artikel9 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 Artikel10 November 2025
Apa Itu Policy dan Gate di Laravel 12: Sistem Otorisasi yang Tepat
Bayangkan ada dua pertanyaan berbeda soal keamanan di aplikasi Anda: “Apakah user ini boleh edit artikel?” dan “Apakah user yang login adalah editor?” Pertanyaan pertama terkait Policy: otorisasi berdasarkan resource. Pertanyaan kedua terkait Gate: otorisasi berdasarkan kemampuan/role. Keduanya bagian dari sistem Authorization di Laravel. Apa Itu Gate? Gate adalah cara mendefinisikan otorisasi berbasis kemampuan (ability) […]
Baca ArtikelIngin Membaca Artikel Lainnya?
Temukan lebih banyak insight dan tips tentang teknologi dan bisnis digital.
Lihat Semua Artikel