Front Controller Pattern

Pernahkah kamu perhatikan bahwa di aplikasi PHP biasa, setiap halaman punya file sendiri (produk.php, login.php, checkout.php)? Ini berarti setiap file harus mengatur koneksi database, session, dan keamanan sendiri-sendiri — sangat rawan lupa dan inkonsisten.

Front Controller menyelesaikan masalah ini dengan satu file yang menjadi pintu masuk semua request.

Tanpa Front Controller vs Dengan Front Controller

❌ TANPA Front Controller (cara lama):
Browser → produk.php    → (koneksi DB, cek auth, proses, tampilkan)
Browser → login.php     → (koneksi DB, session, proses, tampilkan)
Browser → checkout.php  → (koneksi DB, cek auth, proses, tampilkan)
          ↑ Setiap file mengatur semuanya sendiri!

✅ DENGAN Front Controller (cara modern):
Browser → index.php → (koneksi DB, cek auth, tentukan route) → handler
          ↑ Satu pintu masuk, setup terpusat!

Analogi

Bayangkan sebuah gedung perkantoran:

  • Tanpa Front Controller = Gedung tanpa resepsionis. Tamu langsung masuk ke ruangan manapun.
  • Dengan Front Controller = Gedung dengan resepsionis di lobby. Tamu harus lapor dulu, lalu diarahkan ke ruangan yang benar.

Implementasi Sederhana

1. File .htaccess — Arahkan Semua Request ke index.php

# .htaccess (untuk Apache / Laravel Herd)
RewriteEngine On

# Jika bukan file atau folder yang ada (CSS, JS, gambar), arahkan ke index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Dengan .htaccess ini:

  • http://toko.test/produk → masuk ke index.php (URL: /produk)
  • http://toko.test/login → masuk ke index.php (URL: /login)
  • http://toko.test/style.css → langsung kirim file CSS (tidak lewat index.php)

2. File index.php — Front Controller

<?php
// index.php — Satu-satunya pintu masuk aplikasi
declare(strict_types=1);

// ═══════════════════════════════════════════
// 1. BOOTSTRAP: Setup yang berlaku untuk SEMUA halaman
// ═══════════════════════════════════════════

// Environment config
require __DIR__ . '/config/app.php';

// Koneksi database
require __DIR__ . '/config/database.php';

// Helper functions
require __DIR__ . '/helpers/functions.php';

// Session
session_start();

// ═══════════════════════════════════════════
// 2. ROUTING: Tentukan halaman mana yang diminta
// ═══════════════════════════════════════════

// Ambil URL path (buang query string)
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path = rtrim($path, '/') ?: '/';

// Method HTTP (GET, POST, PUT, DELETE)
$method = $_SERVER['REQUEST_METHOD'];

// ═══════════════════════════════════════════
// 3. ROUTE MAP: Hubungkan URL → file handler
// ═══════════════════════════════════════════

$routes = [
    // Halaman publik
    'GET /'          => 'pages/home.php',
    'GET /produk'    => 'pages/produk/index.php',
    'GET /produk/detail' => 'pages/produk/detail.php',

    // Authentication
    'GET /login'     => 'pages/auth/login.php',
    'POST /login'    => 'pages/auth/login-proses.php',
    'GET /register'  => 'pages/auth/register.php',
    'POST /register' => 'pages/auth/register-proses.php',
    'GET /logout'    => 'pages/auth/logout.php',

    // Admin (perlu login + role admin)
    'GET /admin'           => 'pages/admin/dashboard.php',
    'GET /admin/produk'    => 'pages/admin/produk/index.php',
    'GET /admin/produk/tambah' => 'pages/admin/produk/tambah.php',
    'POST /admin/produk/tambah' => 'pages/admin/produk/tambah-proses.php',

    // API
    'GET /api/produk'     => 'api/produk.php',
    'POST /api/produk'    => 'api/produk-tambah.php',
];

// ═══════════════════════════════════════════
// 4. DISPATCH: Jalankan handler yang sesuai
// ═══════════════════════════════════════════

$routeKey = "$method $path";

if (isset($routes[$routeKey])) {
    $handlerFile = __DIR__ . '/' . $routes[$routeKey];

    if (file_exists($handlerFile)) {
        require $handlerFile;
    } else {
        http_response_code(500);
        echo "Error: Handler file not found: $handlerFile";
    }
} else {
    // Route tidak ditemukan → 404
    http_response_code(404);
    require __DIR__ . '/pages/errors/404.php';
}

3. Contoh Handler (Page File)

<?php
// pages/produk/index.php — Tidak perlu setup apapun!
// Database, session, helpers sudah load dari index.php

$stmt = $pdo->query("SELECT * FROM produk WHERE status = 'aktif' ORDER BY id DESC");
$produkList = $stmt->fetchAll();

$title = 'Daftar Produk';
require __DIR__ . '/../../templates/header.php';
?>

<h1>Produk Kami</h1>
<div class="produk-grid">
    <?php foreach ($produkList as $produk): ?>
        <div class="produk-card">
            <h3><?= esc($produk['nama']) ?></h3>
            <p>Rp <?= number_format($produk['harga'], 0, ',', '.') ?></p>
            <a href="/produk/detail?id=<?= $produk['id'] ?>">Lihat Detail</a>
        </div>
    <?php endforeach; ?>
</div>

<?php require __DIR__ . '/../../templates/footer.php'; ?>

Middleware: Guard di Pintu Masuk

Karena semua request lewat satu pintu, kita bisa menambahkan pengecekan global:

<?php
// Di index.php, sebelum dispatch

// Middleware: Proteksi halaman admin
if (str_starts_with($path, '/admin')) {
    require __DIR__ . '/config/auth.php';
    requireRole('admin');
}

// Middleware: Force HTTPS di production
if (ENVIRONMENT === 'production' && empty($_SERVER['HTTPS'])) {
    header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
    exit;
}

// Middleware: CORS untuk API
if (str_starts_with($path, '/api/')) {
    header('Content-Type: application/json');
    header('Access-Control-Allow-Origin: *');
}

Keuntungan Front Controller

Tanpa FCDengan FC
Setup di setiap fileSetup sekali di index.php
Lupa session_start() → bugOtomatis, tidak bisa lupa
Keamanan tidak konsistenMiddleware terpusat
URL = nama file (produk.php)URL bersih (/produk)
Sulit tambah fitur globalTinggal tambah middleware
project/
├── index.php          ← Front Controller (satu-satunya entry point)
├── .htaccess          ← Rewrite rules
├── config/
│   ├── app.php        ← Environment config
│   ├── database.php   ← Koneksi PDO
│   └── auth.php       ← Authentication helpers
├── helpers/
│   ├── functions.php  ← Helper umum (esc, formatRupiah, dll)
│   └── validator.php  ← Validator class
├── pages/
│   ├── home.php
│   ├── produk/
│   │   ├── index.php
│   │   └── detail.php
│   ├── auth/
│   │   ├── login.php
│   │   └── register.php
│   ├── admin/
│   │   └── dashboard.php
│   └── errors/
│       ├── 404.php
│       └── 403.php
├── api/
│   └── produk.php
├── templates/
│   ├── header.php
│   └── footer.php
└── public/
    ├── css/
    ├── js/
    └── images/
NOTE
  • Entry point: public/index.php
  • Routes: routes/web.php dan routes/api.php
  • Middleware: app/Http/Middleware/

Perbedaannya: Laravel menggunakan class-based controller dan dependency injection, bukan file include.

Latihan

  1. Refactor project Toko Online: buat index.php sebagai front controller
  2. Buat minimal 5 routes (home, produk, detail produk, login, admin)
  3. Tambahkan middleware untuk proteksi halaman admin
  4. Pastikan file CSS/JS/gambar tetap bisa diakses langsung (tidak lewat front controller)

Selanjutnya

Sekarang kamu paham arsitektur front controller. Lanjut ke Environment & Config → untuk belajar memisahkan konfigurasi sensitif dari kode.

Artikel Terkait