Mempelajari bagaimana Yii menerjemahkan URL menjadi action: URL rules dan pretty URLs, lifecycle controller dari action sampai render, konsep layout dan view yang dipakai bersama, module routing, serta peran widgets sebagai blok tampilan yang bisa dipakai ulang.

Di episode 3 kalian sudah melihat halaman selamat datang Yii muncul lewat URL ?r=site/index. Pertanyaan besarnya: bagaimana URL itu sampai ke SiteController::actionIndex()? Jawabannya adalah routing — mekanisme paling fundamental dari framework web mana pun.
Memahami routing di Yii berarti memahami satu hal sederhana: URL adalah peta menuju controller dan action. Begitu kalian paham petanya, semuanya — pretty URLs, module, REST API — menjadi variasi dari satu konsep. Di episode ini kita bedah routing, controller, dan view sekaligus, karena ketiganya bekerja sebagai satu alur: URL masuk, controller memproses, view merender.
Secara default, Yii memetakan URL ke format ?r=module/controller/action. Jika tidak ditulis lengkap, action diisi default index:
| URL | Controller::Action |
|---|---|
?r=site/index | SiteController::actionIndex() |
?r=post/view | PostController::actionView() |
?r=post | PostController::actionIndex() |
?r=blog/post/view | PostController::actionView() dalam module blog |
Satu aturan penamaan: nama controller berakhiran kata Controller, dan action berawalan action. Yii mengubah huruf besar pada URL menjadi tanda hubung — BlogPostController diakses sebagai blog-post.
<?php
namespace app\controllers;
use yii\web\Controller;
class BlogPostController extends Controller
{
public function actionIndex(): string
{
return $this->render('index');
}
public function actionView(int $id): string
{
return $this->render('view', [
'id' => $id,
]);
}
}URL ?r=blog-post/view&id=5 akan memanggil actionView(5) — Yii secara otomatis meng-bind parameter query id ke argument method $id (type-hint int bahkan membuat Yii menolak nilai non-numerik dengan 400 Bad Request).
URL ?r=... berfungsi, tapi tidak cantik dan tidak SEO-friendly. Yii menyediakan urlManager untuk membuat URL bersih:
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'post/<id:\d+>' => 'post/view',
'kategori/<slug>' => 'kategori/index',
],
],
],Dengan konfigurasi ini, ?r=post/view&id=5 berubah menjadi /post/5 (perhatikan pola <id:\d+> yang hanya menerima angka), dan route internal kategori/index bisa dipanggil lewat /kategori/{slug}. Satu hal yang perlu diingat: untuk showScriptName => false di production, web server harus mengarahkan semua request ke web/index.php — kita konfigurasikan di episode 22.
Tip
Jangan pernah menulis URL route secara manual di dalam view. Gunakan helper Yii::$app->urlManager->createUrl(['post/view', 'id' => 5]) atau pada Yii2, Url::to(['post/view', 'id' => 5]). Dengan begitu, saat rules kalian berubah, semua tautan di aplikasi otomatis ikut berubah.
Controller tidak menampilkan HTML langsung — ia me-render view. Saat $this->render('index') dipanggil, Yii mencari file views/blog-post/index.php, merendernya, lalu menyuntikkannya ke dalam layout views/layouts/main.php. Inilah alur render yang penting dipahami:
Sebuah view hanyalah file PHP yang menerima variabel dari controller:
<?php
/** @var $this \yii\web\View */
/** @var int $id */
?>
<h1>Detail Post</h1>
<p>Kalian sedang melihat post dengan ID <?= $id ?></p>Perhatikan dua hal: pertama, shortcut <?= adalah singkatan <?php echo — dipakai untuk mencetak, dan Yii meng-escape otomatis? Tidak. Mencetak variabel mentah dengan <?= $id ?> aman jika nilai dijamin angka, tapi untuk teks dari user, wajib memakai Html::encode() — ini topik XSS yang kita bedah di episode 17. Kedua, deklarasi /** @var */ bukan sekadar komentar — ia membantu IDE memahami tipe variabel sehingga autocomplete bekerja.
Layout adalah kerangka yang dipakai semua halaman. Di views/layouts/main.php, variabel $content berisi hasil render view:
<?php
/** @var \yii\web\View $this */
/** @var string $content */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<title><?= $this->title ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<nav class="navbar navbar-dark"><?= $this->name ?></nav>
<main class="container">
<?= $content ?>
</main>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>beginPage()/endPage() dan head()/beginBody()/endBody() adalah kontrak yang memberi tahu Yii di mana menyuntikkan aset (CSS/JS) dan kode terdaftar lain. Jika kalian lupa salah satu, assets tidak akan muncul. Untuk layout khusus (misal halaman cetak atau halaman login yang berbeda), controller bisa menimpa properti layout:
public function actionLogin()
{
$this->layout = 'login'; // memakai views/layouts/login.php
return $this->render('login');
}Saat aplikasi membesar, kode dikelompokkan ke module — aplikasi mini di dalam aplikasi. Module punya controllers/, views/, models/ sendiri, dan routenya diawali nama module:
'modules' => [
'blog' => [
'class' => 'app\modules\blog\Module',
],
],<?php
namespace app\modules\blog;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'app\modules\blog\controllers';
}URL ?r=blog/post/view&id=1 sekarang memanggil app\modules\blog\controllers\PostController::actionView(). Module menjadi tulang punggung aplikasi besar — kita bedah strategi modularisasi lengkap di episode 20.
Widget adalah blok tampilan yang bisa dipakai ulang — ringkasnya, "mini-view dengan logika". Bedanya dari view biasa, widget punya class PHP sendiri (widgets/ atau app\widgets) sehingga bisa dipanggil di mana saja:
<?= \yii\widgets\Breadcrumbs::widget([
'links' => [
['label' => 'Home', 'url' => ['site/index']],
'Detail Post',
],
]) ?>
<?= \yii\bootstrap5\Alert::widget([
'options' => ['class' => 'alert-info'],
'body' => 'Berhasil disimpan!',
]) ?>Yii2 menyediakan ratusan widget siap pakai: GridView, DetailView, ActiveForm, Breadcrumbs, Pjax — yang paling sering kita pakai ada di episode 7. Kalian juga bisa membuat widget sendiri dengan mewarisi yii\base\Widget dan menimpa method run().
Inti yang harus dibawa pulang:
?r=post/view → PostController::actionView().urlManager; gunakan Url::to() untuk membuat tautan.render menghasilkan view lalu membungkusnya dengan layout; jangan lupa kontrak beginPage/endPage.Di episode 5 selanjutnya, kita masuk ke lapisan data: Active Record dan Query Builder — bagaimana Yii memetakan tabel database menjadi object PHP, menulis query dengan cara aman dan ekspresif, mendefinisikan relasi antar tabel, dan membangun CRUD lengkap dengan Active Record. Sampai jumpa di episode 5!