Home » Tutorial » Tutorial Membuat Routing Sederhana dengan PHP OOP

Tutorial Membuat Routing Sederhana dengan PHP OOP

Membuat aplikasi web yang terstruktur dan mudah dikelola adalah kunci. Salah satu pondasi penting dalam membangun aplikasi semacam itu adalah sistem routing. Routing bertanggung jawab untuk mengarahkan permintaan pengguna ke bagian kode yang tepat. Dengan menerapkan Object-Oriented Programming (OOP), kita bisa menciptakan sistem routing yang bersih, fleksibel, dan mudah dikembangkan. Artikel ini akan memandu kamu langkah demi langkah dalam membangun sistem routing sederhana menggunakan PHP OOP, dengan gaya bahasa yang santai namun tetap informatif. Mari kita mulai!

Mengenal Konsep Routing dalam Pengembangan Web PHP

Sebelum kita menyelami kode, mari kita pahami dulu apa itu routing. Secara sederhana, routing adalah mekanisme yang menentukan bagaimana aplikasi kamu merespons permintaan URL. Ketika kamu mengetik https://www.contoh.com/produk/detail/1 di browser, routing inilah yang bekerja di belakang layar untuk memastikan permintaan tersebut diolah oleh fungsi atau metode yang bertugas menampilkan detail produk dengan ID 1. Tanpa routing yang baik, aplikasi kita akan menjadi kumpulan file yang sulit diatur dan diintegrasikan.

Mengapa Routing Penting untuk Aplikasi PHP Kamu?

Pentingnya routing dalam pengembangan web tidak bisa diremehkan. Bayangkan jika setiap halaman di aplikasi kamu harus memiliki file PHP tersendiri di root direktori. Tentu ini akan sangat tidak efisien dan berantakan, apalagi jika aplikasi kamu tumbuh besar. Routing membantu kita mencapai beberapa hal penting:

  • URL yang Bersih dan Mudah Dibaca: Routing memungkinkan kita memiliki URL yang ramah SEO dan mudah diingat oleh pengguna (misalnya, /artikel/judul-artikel daripada /artikel.php?id=123).
  • Pemisahan Tanggung Jawab (Separation of Concerns): Dengan routing, logika untuk menangani URL terpisah dari logika bisnis aplikasi, membuat kode lebih modular dan mudah dipelihara.
  • Keamanan: Routing bisa menjadi lapisan pertama dalam memfilter permintaan yang tidak sah atau berbahaya sebelum mencapai logika aplikasi inti.
  • Fleksibilitas: Kamu bisa dengan mudah mengubah struktur URL tanpa harus mengubah banyak kode di dalam aplikasi.

Perbedaan Routing Sederhana dan Routing Kompleks

Routing bisa sesederhana mengarahkan semua permintaan ke satu file index.php dan menangani semuanya di sana, atau bisa juga sangat kompleks dengan dukungan untuk middleware, grouping route, parameter binding, dan lain-lain. Untuk artikel ini, kita akan fokus pada routing sederhana yang mampu mengidentifikasi URL dan mengarahkan ke controller atau fungsi yang sesuai. Ini adalah fondasi yang baik sebelum kamu melangkah ke implementasi yang lebih rumit, seperti yang biasa ditemukan di PHP framework.

Mempersiapkan Lingkungan Pengembangan PHP Kita

Sebelum menulis kode, pastikan kamu memiliki lingkungan pengembangan PHP yang berfungsi. Kamu akan membutuhkan:

  • Web Server: Apache atau Nginx dengan PHP terinstal.
  • PHP: Versi 7.4 atau lebih baru direkomendasikan.
  • Teks Editor: Visual Studio Code, Sublime Text, atau lainnya.

Kita akan membuat struktur folder sederhana untuk proyek ini:

simple-router/
├── public/
│   └── index.php
├── app/
│   ├── Controllers/
│   │   └── HomeController.php
│   └── Router.php
└── .htaccess

File .htaccess (jika menggunakan Apache) akan sangat penting untuk mengarahkan semua permintaan ke public/index.php. Ini dikenal sebagai front controller pattern.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ public/index.php [QSA,L]
</IfModule>

Kode di atas memberitahu Apache untuk:

  • RewriteEngine On: Mengaktifkan modul rewrite.
  • RewriteCond %{REQUEST_FILENAME} !-f: Jika permintaan bukan file yang ada.
  • RewriteCond %{REQUEST_FILENAME} !-d: Dan jika permintaan bukan direktori yang ada.
  • RewriteRule ^(.*)$ public/index.php [QSA,L]: Maka arahkan semua permintaan ke public/index.php. QSA (Query String Append) memastikan parameter query tetap ada, dan L (Last) menghentikan pemrosesan rewrite lebih lanjut.

Membangun Kelas Router dengan Prinsip PHP OOP

Inti dari sistem routing kita adalah kelas Router. Kelas ini akan bertanggung jawab untuk mendefinisikan route, mencocokkan URL yang diminta, dan memanggil callback atau controller yang sesuai. Konsep dasar belajar PHP OOP akan sangat membantu di sini.

Desain Kelas Router Kita

Kelas Router akan memiliki beberapa properti dan metode:

  • $routes (array): Menyimpan daftar semua route yang terdaftar. Setiap route akan memiliki metode HTTP (GET, POST, dll.), pola URL, dan callback (fungsi atau metode controller).
  • addRoute(string $method, string $path, callable|array $callback): Metode untuk menambahkan route baru ke dalam $routes.
  • dispatch(): Metode utama yang akan mencocokkan URL yang diminta dengan route yang terdaftar dan mengeksekusi callback yang sesuai.

Mari kita mulai dengan kerangka dasar kelas Router di app/Router.php:

<?php

namespace App;

class Router
{
    private $routes = [];

    public function addRoute(string $method, string $path, $callback)
    {
        $this->routes[] = [
            'method' => $method,
            'path' => $path,
            'callback' => $callback,
        ];
    }

    public function get(string $path, $callback)
    {
        $this->addRoute('GET', $path, $callback);
    }

    public function post(string $path, $callback)
    {
        $this->addRoute('POST', $path, $callback);
    }

    public function dispatch()
    {
        $uri = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
        $method = $_SERVER['REQUEST_METHOD'];

        foreach ($this->routes as $route) {
            if ($route['method'] === $method && preg_match("#^" . $route['path'] . "$#", $uri, $matches)) {
                array_shift($matches); // Remove the full match

                if (is_callable($route['callback'])) {
                    call_user_func_array($route['callback'], $matches);
                } elseif (is_array($route['callback']) && count($route['callback']) === 2) {
                    $controller = new $route['callback'][0]();
                    call_user_func_array([$controller, $route['callback'][1]], $matches);
                }
                return;
            }
        }

        // If no route matches
        header("HTTP/1.0 404 Not Found");
        echo "404 Not Found";
    }
}

Penjelasan Bagian Penting Kelas Router

Properti

private $routes = [];
Digunakan untuk menyimpan semua daftar route yang telah didaftarkan, baik GET, POST, maupun lainnya.

Metode untuk Mendaftarkan Route

addRoute(string $method, string $path, $callback)

Metode inti untuk menambahkan route. Parameter:

  • $method: Jenis metode HTTP (GET, POST, dll.)
  • $path: Pola URL, bisa berupa string biasa atau regex
  • $callback: Aksi yang dijalankan jika route cocok, bisa berupa:
    • Fungsi anonim (closure)
    • Array [NamaController::class, 'namaMethod']

Semua route akan disimpan ke dalam array $routes.

get(string $path, $callback)

Shortcut untuk menambahkan route dengan metode GET.

post(string $path, $callback)

Shortcut untuk menambahkan route dengan metode POST.

Metode untuk Menjalankan Routing

dispatch()

Digunakan untuk mencocokkan URL yang diminta oleh user dengan daftar route, lalu menjalankan callback yang sesuai.

Langkah-langkah dalam dispatch()

1. Ambil URI dan Method

$uri = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
$method = $_SERVER['REQUEST_METHOD'];
  • $uri: Mendapatkan path dari URL, misalnya http://localhost/produk/1 akan menjadi produk/1
  • $method: Mendapatkan metode HTTP dari request, misalnya GET atau POST

2. Loop Semua Route

foreach ($this->routes as $route) { ... }
  • Mengecek satu per satu route yang sudah didaftarkan

3. Pencocokan URL dan Method

if ($route['method'] === $method && preg_match(...))
  • Mengecek apakah metode cocok
  • Menggunakan regex untuk mencocokkan URL
  • Jika cocok, hasil pencocokan disimpan di $matches

4. Membersihkan Match

array_shift($matches);
  • Menghapus elemen pertama dari $matches karena itu adalah string penuh yang cocok dengan pola
  • Sisanya adalah parameter yang akan dikirim ke callback

Eksekusi Callback

Callback berupa Closure

if (is_callable($route['callback'])) {
    call_user_func_array($route['callback'], $matches);
}
  • Jika callback adalah fungsi anonim, langsung dipanggil dengan parameter dari URL

Callback berupa Controller Method

elseif (is_array($route['callback']) && count($route['callback']) === 2) {
    $controller = new $route['callback'][0]();
    call_user_func_array([$controller, $route['callback'][1]], $matches);
}
  • Jika callback berupa array [NamaController::class, 'method'], maka:
    • Buat objek controller
    • Jalankan method-nya dengan parameter dari URL

Stop Setelah Ketemu

return;
  • Setelah route ditemukan dan dijalankan, proses dihentikan agar tidak lanjut ke route lain

Penanganan Jika Tidak Ada yang Cocok

header("HTTP/1.0 404 Not Found");
echo "404 Not Found";

Jika tidak ada route yang cocok, sistem mengembalikan error 404

Membuat Controller Sederhana

Untuk mengilustrasikan bagaimana router bekerja dengan controller, kita akan membuat controller sederhana di app/Controllers/HomeController.php.

<?php

namespace App\Controllers;

class HomeController
{
    public function index()
    {
        echo "Selamat datang di halaman utama!";
    }

    public function about()
    {
        echo "Ini adalah halaman tentang kami.";
    }

    public function showProduct($id)
    {
        echo "Detail Produk dengan ID: " . htmlspecialchars($id);
    }
}

Dalam contoh ini:

  • Metode index() akan menampilkan pesan sambutan untuk halaman utama.
  • Metode about() untuk halaman “tentang kami”.
  • Metode showProduct($id) akan menerima parameter $id dari URL. Penting untuk menggunakan htmlspecialchars() saat menampilkan output dari input pengguna untuk mencegah serangan XSS.

Penjelasan Kode index.php

1. Load File Kelas Manual

require_once __DIR__ . '/../app/Router.php';
require_once __DIR__ . '/../app/Controllers/HomeController.php';
  • require_once: Memuat file Router.php dan HomeController.php secara manual.
  • __DIR__: Menunjuk direktori saat ini (public/), lalu naik ke folder app/.

2. Import Namespace

use App\Router;
use App\Controllers\HomeController;
  • Mempermudah akses kelas dengan namespace App.

3. Inisialisasi Router

$router = new Router();
  • Membuat objek Router untuk menangani HTTP request.

4. Definisi Route

a. Route Halaman Utama

$router->get('/', function() {
    echo "Halo, ini halaman utama menggunakan closure!";
});
  • Route ke /, ditangani langsung oleh fungsi anonim (closure).

b. Route ke HomeController@index

$router->get('/home', [HomeController::class, 'index']);
  • Memanggil method index() di HomeController.

c. Route ke HomeController@about

$router->get('/about', [HomeController::class, 'about']);
  • Menangani halaman /about.

d. Route dengan Parameter Dinamis

$router->get('/product/(\d+)', [HomeController::class, 'showProduct']);
  • Menangani URL seperti /product/123.
  • (\d+) adalah ekspresi reguler (regex) untuk menangkap angka.
  • Angka itu akan diteruskan sebagai parameter ke showProduct($id).

5. Jalankan Router

$router->dispatch();
  • Mengeksekusi route yang cocok berdasarkan URL yang diakses pengguna.

Kode ini bisa digunakan sebagai entry point sederhana untuk aplikasi PHP berbasis routing custom, mirip gaya routing di framework seperti Laravel. Cocok buat belajar konsep routing dari nol.

Mengimplementasikan Router di Public/index.php

Sekarang, mari kita sambungkan semuanya di public/index.php, yang akan menjadi entry point aplikasi kita.

<?php

require_once __DIR__ . '/../app/Router.php';
require_once __DIR__ . '/../app/Controllers/HomeController.php';

use App\Router;
use App\Controllers\HomeController;

$router = new Router();

// Define routes
$router->get('/', function() {
    echo "Halo, ini halaman utama menggunakan closure!";
});

$router->get('/home', [HomeController::class, 'index']);
$router->get('/about', [HomeController::class, 'about']);
$router->get('/product/(\d+)', [HomeController::class, 'showProduct']); // Using regex for ID

// Dispatch the request
$router->dispatch();

Menjalankan Aplikasi Web PHP Sederhana Kita

Setelah semua file siap, kamu bisa menjalankan aplikasi ini. Jika kamu menggunakan Apache, pastikan .htaccess sudah dikonfigurasi dengan benar. Jika kamu menggunakan built-in web server PHP (untuk pengembangan lokal), kamu bisa menjalankan perintah berikut dari direktori simple-router/:

php -S localhost:8000 -t public

Kemudian, buka browser dan coba akses URL berikut:

  • http://localhost:8000/ (akan menampilkan “Halo, ini halaman utama menggunakan closure!”)
  • http://localhost:8000/home (akan menampilkan “Selamat datang di halaman utama!”)
  • http://localhost:8000/about (akan menampilkan “Ini adalah halaman tentang kami.”)
  • http://localhost:8000/product/123 (akan menampilkan “Detail Produk dengan ID: 123”)
  • http://localhost:8000/nonexistent (akan menampilkan “404 Not Found”)

Selamat! Kamu telah berhasil membangun sistem routing sederhana dengan PHP OOP. Kamu bisa melihat bagaimana struktur yang bersih ini membuat aplikasi kamu lebih mudah untuk diatur dan dikembangkan.

Memahami Pentingnya URL Dinamis dan Parameter

Dalam aplikasi web modern, sangat umum untuk memiliki URL yang dinamis, artinya bagian dari URL dapat berubah tergantung pada data yang ingin kita tampilkan. Contoh yang paling jelas adalah /product/123 di mana 123 adalah ID produk yang ingin kita lihat.

Menggunakan Regular Expression untuk Parameter Routing

Dalam kelas Router kita, kita menggunakan preg_match untuk mencocokkan pola URL dengan ekspresi reguler. Ini adalah cara yang sangat fleksibel untuk menangani URL dinamis.

  • (\d+): Ini adalah ekspresi reguler yang berarti “tangkap satu atau lebih digit”. Jadi, (\d+) akan menangkap 123 dari /product/123.
  • ([a-zA-Z0-9_-]+): Kamu juga bisa menggunakan ekspresi reguler lain, misalnya untuk menangkap slug artikel yang berisi huruf, angka, underscore, dan dash. Contohnya: /artikel/([a-zA-Z0-9_-]+).

Ketika preg_match menemukan kecocokan, bagian yang ditangkap oleh tanda kurung () akan disimpan dalam array $matches. Kemudian, kita bisa meneruskan elemen-elemen ini sebagai argumen ke callback kita. Ini adalah kekuatan dari dynamic routing.

Penyempurnaan dan Ide Pengembangan Lebih Lanjut untuk Routing PHP OOP

Meskipun sistem routing kita sudah fungsional, ada banyak area di mana kita bisa menyempurnakannya. Ini adalah beberapa ide yang bisa kamu eksplorasi untuk mengembangkan router ini lebih jauh, seiring dengan perjalanan kamu dalam belajar PHP.

1. Penanganan Metode HTTP Lainnya

Saat ini kita hanya mendukung GET dan POST. Kamu bisa dengan mudah menambahkan metode lain seperti PUT, DELETE, PATCH, dan OPTIONS.

2. Grouping Route

Untuk aplikasi yang lebih besar, mengelompokkan route akan sangat membantu. Misalnya, semua route /admin/* bisa dikelompokkan di bawah satu prefix.

// Contoh ide grouping
$router->group('/admin', function($router) {
    $router->get('/dashboard', [AdminController::class, 'dashboard']);
    $router->post('/users/add', [AdminController::class, 'addUser']);
});

3. Middleware

Middleware adalah lapisan kode yang berjalan sebelum atau sesudah controller dieksekusi. Ini sangat berguna untuk otentikasi, otorisasi, logging, atau validasi input.

// Contoh ide middleware
$router->get('/admin/settings', [AdminController::class, 'settings'])
    ->middleware(AuthMiddleware::class);

4. Named Routes

Memberi nama pada setiap route memungkinkan kamu menghasilkan URL berdasarkan nama route tersebut, bukan berdasarkan string URL-nya. Ini membuat aplikasi lebih fleksibel jika kamu perlu mengubah struktur URL di masa mendatang.

// Contoh ide named routes
$router->get('/product/(\d+)', [HomeController::class, 'showProduct'])->name('product.detail');

// Kemudian di view atau controller:
// echo $router->url('product.detail', ['id' => 123]); // Output: /product/123

5. Validasi Input dan Keamanan

Selalu ingat untuk memvalidasi dan membersihkan semua input dari pengguna. Dalam contoh showProduct, kita menggunakan htmlspecialchars() untuk mencegah XSS. Untuk input yang lebih kompleks (misalnya dari formulir POST), kamu perlu validasi yang lebih kuat.

Kesimpulan: Fondasi Kuat untuk Aplikasi Web PHP Kamu

Membuat routing sederhana dengan PHP OOP adalah langkah fundamental dalam membangun aplikasi web yang bersih, terstruktur, dan mudah dikelola. Dengan memahami prinsip-prinsip yang telah kita bahas, kamu sekarang memiliki fondasi yang kuat untuk mengembangkan aplikasi web PHP yang lebih kompleks. Ingat, PHP OOP adalah alat yang sangat ampuh untuk mengorganisir kode dan membuat aplikasi kamu lebih modular.

Teruslah bereksperimen, tambahkan fitur-fitur baru, dan pelajari lebih dalam tentang berbagai pola desain yang digunakan dalam framework PHP modern. Dengan begitu, kamu akan semakin mahir dalam membangun aplikasi web yang tangguh dan efisien.

Leave a Comment