Belajar Symfony - Routing & Controllers
Episode 4 of 27

Belajar Symfony - Routing & Controllers

Menguasai routing berbasis attribute #[Route] dengan parameter path, requirement, dan pembatasan method, lalu mengenal controller berbasis AbstractController, tipe-tipe Response (JSON, redirect, file), serta dependency injection langsung ke method controller.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 3 kalian memiliki project Symfony pertama yang berjalan, episode ini adalah langkah pertama membangun perilaku aplikasi: routing (menghubungkan URL ke kode) dan controller (kode yang menghasilkan response).

Routing adalah "pintu depan" aplikasi web — tanpa memahami cara kerjanya, mustahil men-debug mengapa sebuah URL mengembalikan 404 atau 500. Lebih dari itu, pola yang dipelajari di sini (attribute, parameter, response types) adalah bahasa dasar yang dipakai seluruh episode berikutnya, dari render Twig di episode 5 sampai API Platform di episode 13.

Membuat Controller Pertama

Gunakan MakerBundle untuk boilerplate cepat, lalu kita bedah hasilnya:

Buat controller ArticleController
php bin/console make:controller ArticleController

Maker menghasilkan class di src/Controller/ArticleController.php. Perhatikan atribut #[Route] dan pewarisan AbstractController:

src/Controller/ArticleController.php
<?php
 
namespace App\Controller;
 
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
 
class ArticleController extends AbstractController
{
    #[Route('/articles', name: 'app_articles')]
    public function index(): Response
    {
        return $this->render('article/index.html.twig', [
            'articles' => [],
        ]);
    }
}

Dua elemen penting:

  1. #[Route('/articles', name: 'app_articles')] — memetakan URL /articles ke method index(), dengan nama app_articles sebagai identifier.
  2. AbstractController — memberi kalian helper seperti $this->render(), $this->redirectToRoute(), dan $this->json().

Verifikasi dengan php bin/console debug:router — daftar route sekarang berisi app_articles.

Parameter Path dan Requirement

Route statis jarang cukup. Tambahkan parameter dinamis:

Route dengan parameter
#[Route('/articles/{slug}', name: 'app_article_show', requirements: ['slug' => '[a-z0-9-]+'])]
public function show(string $slug): Response
{
    return $this->json(['slug' => $slug]);
}

{slug} adalah placeholder yang otomatis di-inject sebagai argument method $slug. Requirement [a-z0-9-]+ membatasi karakter yang diterima — tanpa requirement, {slug} menerima apa saja; dengan requirement, URL yang tidak cocok otomatis menjadi 404.

FiturContohEfek
Parameter{id}Nilai dari URL di-inject ke argumen method
Requirementrequirements: ['id' => '\d+']Hanya angka yang cocok
Default value{page} + defaults: ['page' => 1]Nilai default jika parameter tidak ada
Methodmethods: ['GET', 'POST']Batasi HTTP method

Untuk parameter opsional, gabungkan default value dengan nullable type:

Parameter opsional
#[Route('/blog/{page}', name: 'app_blog', defaults: ['page' => 1], requirements: ['page' => '\d+'])]
public function blog(int $page): Response
{
    return $this->json(['page' => $page]);
}

URL /blog akan memakai page=1; /blog/5 memakai page=5.

Prefix Route di Level Class

Untuk mengelompokkan URL, taruh #[Route] di level class:

Prefix route class
#[Route('/admin', name: 'app_admin_')]
class AdminController extends AbstractController
{
    #[Route('/users', name: 'users')]
    public function users(): Response
    {
        // menghasilkan route app_admin_users → URL /admin/users
    }
}

Ini menjaga konsistensi penamaan (app_admin_users) dan memudahkan pemindahan sekelompok endpoint nanti.

Tipe-tipe Response

Controller boleh mengembalikan berbagai bentuk response — semuanya subclass Response:

Berbagai tipe Response
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
 
// JSON untuk API
return $this->json(['status' => 'ok']);
 
// Redirect ke route lain (misal setelah form disubmit)
return $this->redirectToRoute('app_articles');
 
// Download file
return new BinaryFileResponse('/path/to/report.pdf');
 
// Response dengan status code khusus
return $this->json(['error' => 'not found'], Response::HTTP_NOT_FOUND);

Aturan praktis: gunakan $this->json() untuk API, $this->render() untuk HTML, redirectToRoute() untuk pola PRG (Post/Redirect/Get), dan BinaryFileResponse untuk unduhan.

Warning

Jangan mengembalikan null atau data non-Response dari controller — Symfony akan melempar exception saat kernel mencoba mengirim hasil. Selalu kembalikan objek Response (atau subclass-nya) dari setiap method controller.

Dependency Injection ke Controller

Controller bisa menerima service langsung sebagai argument method (bukan __construct):

DI ke method controller
use Psr\Log\LoggerInterface;
 
#[Route('/articles/{id}', name: 'app_article_show', requirements: ['id' => '\d+'])]
public function show(int $id, LoggerInterface $logger): Response
{
    $logger->info("Viewing article #{id}", ['id' => $id]);
 
    return $this->json(['id' => $id]);
}

LoggerInterface otomatis disuntikkan karena container tahu implementasinya (autowiring). Kita bedah mekanisme lengkapnya di episode 8 — untuk sekarang, ingat polanya: type-hint sebuah service, dan Symfony yang mencarikannya.

Route vs 404: Kenapa URL Tidak Ketemu?

Saat URL menghasilkan 404, prioritas pengecekan:

  1. Route tidak ada — URL tidak cocok pattern mana pun → 404 (cek dengan debug:router).
  2. Requirement gagal — misal /articles/abc dengan requirement \d+ → 404.
  3. Method tidak cocokPOST ke route GET-only → 405 Method Not Allowed.

php bin/console debug:router --show-controllers menampilkan route beserta controller yang dituju — senjata utama men-debug masalah routing.

Penutup

Pada episode 4 ini, kalian telah menguasai routing & controller dasar.

Inti yang harus dibawa pulang:

  • Route dideklarasikan dengan attribute #[Route]; name adalah identifier yang dipakai redirectToRoute().
  • {param} di URL ter-inject ke argumen method; requirements memfilter nilai yang diterima.
  • Prefix route bisa ditaruh di level class untuk mengelompokkan endpoint.
  • Selalu kembalikan Response atau subclass-nya; kenali json(), render(), redirectToRoute(), BinaryFileResponse.
  • Service di-inject langsung sebagai argument method lewat type-hint.

Di episode 5 selanjutnya, kita membangun templating dengan Twig: syntax {{ }}, {% %}, template inheritance dengan block dan extends, filter & function bawaan, partials, serta dasar UX Twig Components. Sampai jumpa di episode 5!

Belajar Symfony - Routing & Controllers | Belajar Symfony