Sejauh ini, route dan controller yang kita tulis selalu mengembalikan string mentah atau array JSON. Aplikasi nyata tentu butuh lebih dari itu: halaman HTML yang rapi, konsisten, dan mudah dirawat. Di sinilah layer view masuk — bagian MVC yang bertanggung jawab menyajikan data kepada pengguna. Chapter ini membahas cara Laravel mencari berkas view, bagaimana controller mengirim data ke dalamnya, sampai trik membagikan satu data ke semua view sekaligus. Seluruh konsep di sini adalah fondasi untuk seluruh materi Blade pada section ini.

Posisi View dalam Arsitektur MVC #

Dalam pola MVC , tiga lapisan bekerja dengan tanggung jawab yang terpisah: model mengurus data, controller mengurus alur request, dan view mengurus tampilan. Controller boleh mengambil data dari model, tetapi controller sebaiknya tidak menyusun tag HTML dengan menggabungkan string — tugas penyusunan tampilan diserahkan ke view. Pemisahan seperti ini menjaga kode tetap terorganisir: logika aplikasi bisa berubah tanpa kita menyentuh berkas tampilan, dan sebaliknya.

Laravel menyimpan semua berkas view di direktori resources/views. Nama view ditulis dalam dot notation: view('tugas.index') dipetakan ke berkas resources/views/tugas/index.blade.php. Ekstensi .blade.php menandakan berkas tersebut diproses oleh template engine Blade, sedangkan berkas .php biasa juga dikenali bila ekstensi Blade tidak dipakai. Detail lengkap mekanisme view tersedia di dokumentasi Views .

Memanggil View dari Route atau Controller #

Kita mulai dengan contoh paling sederhana. Buat berkas resources/views/halo.blade.php berisi:

blade
<h1>Halo, Laravel!</h1>
<p>Ini view pertama kita.</p>

Lalu daftarkan route yang mengembalikan view tersebut di routes/web.php:

php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/halo', function () {
    return view('halo');
});

Argumen 'halo' pada helper view() adalah nama view, bukan nama berkas lengkap. Laravel menerjemahkan nama tersebut menjadi path resources/views/halo.blade.php, lalu merender isinya dan mengirimkannya sebagai response HTTP. Kita uji dengan kernel runner:

text
=== GET /halo → HTTP 200 ===
<h1>Halo, Laravel!</h1>
<p>Ini view pertama kita.</p>

Mengirim Data ke View #

View menjadi berguna ketika controller mengirim data untuk ditampilkan. Data dikirim sebagai array argumen kedua helper view() — setiap key menjadi nama variabel di dalam berkas view. Perhatikan contoh berikut:

php
Route::get('/tugas', function () {
    $tugas = [
        ['judul' => 'Belajar Blade', 'status' => 'selesai'],
        ['judul' => 'Menulis migration', 'status' => 'proses'],
    ];

    return view('tugas.index', ['tugas' => $tugas]);
});

Route di atas memanggil view resources/views/tugas/index.blade.php dengan variabel $tugas. Di dalam berkas view, array tersebut kita ulang dengan directive @foreach dan tampilkan tiap elemennya:

blade
<h1>Daftar Tugas</h1>
<ul>
@foreach ($tugas as $item)
    <li>{{ $item['judul'] }} — {{ $item['status'] }}</li>
@endforeach
</ul>
<p>Total: {{ count($tugas) }} tugas</p>

Output yang Dihasilkan:

text
=== GET /tugas → HTTP 200 ===
<h1>Daftar Tugas</h1>
<ul>
    <li>Belajar Blade — selesai</li>
    <li>Menulis migration — proses</li>
</ul>
<p>Total: 2 tugas</p>

Cara alternatifnya adalah method with(): view('tugas.index')->with('tugas', $tugas) menghasilkan hasil yang sama. Cara kedua ini berguna ketika kita ingin merangkai beberapa pemanggilan berantai, misalnya ->with('tugas', $tugas)->with('judul', 'Daftar').

Tampilan di atas juga bisa diverifikasi lewat feature test. Laravel menyediakan assertion assertSee() yang memeriksa apakah sebuah teks hadir di response:

php
public function test_halaman_tugas_menampilkan_daftar(): void
{
    $response = $this->get('/tugas');

    $response->assertStatus(200);
    $response->assertSee('Belajar Blade — selesai');
    $response->assertSee('Total: 2 tugas');
}

Output yang Dihasilkan:

text
PASS  Tests\Feature\PengenalanViewTest
✓ halaman tugas menampilkan daftar                    0.10s

Tests:    1 passed (4 assertions)
Duration: 0.18s

Membagikan Data ke Semua View #

Kadang satu data perlu tersedia di semua halaman — misalnya nama aplikasi untuk header. Mengirim data tersebut di setiap route jelas merepotkan. Fungsi share() menyelesaikannya: panggil sekali, dan variabelnya tersedia di view mana pun:

php
view()->share('namaAplikasi', 'TugasKu');
echo view('halo-pembuka')->render();

Output yang Dihasilkan:

text
<p>Selamat datang di TugasKu.</p>

Berkas halo-pembuka.blade.php hanya berisi {{ $namaAplikasi }} dan tidak menerima data apa pun dari pemanggilnya. Dalam proyek nyata, pemanggilan share() diletakkan di method boot() app/Providers/AppServiceProvider.php agar berjalan setiap kali aplikasi start.

Memeriksa Keberadaan View #

Sebelum merender view yang datanya dinamis — misalnya nama halaman dari input pengguna — kita perlu memastikan berkasnya ada. Fungsi exists() memeriksa keberadaan view tanpa merendernya:

php
view()->exists('halo');            // true
view()->exists('tugas.index');     // true
view()->exists('tugas.tidak-ada'); // false

Output yang Dihasilkan:

text
exists('halo'): true
exists('tugas.index'): true
exists('tugas.tidak-ada'): false

Sekarang kita sudah bisa mengirim data ke view dan menampilkannya dengan {{ }}. Mesin yang mengubah {{ }} menjadi output HTML aman bernama Blade — cara kerja kompilasinya, perbedaan escaping, dan cara menyertakan sub-view akan kita bahas pada chapter Blade Template.