Blade adalah mesin template bawaan Laravel yang mengolah berkas templat berakhiran .blade.php menjadi HTML. Topik ini membahas direktif dasar Blade, cara kerja escape pada penulisan {{ }}, serta pewarisan template untuk membangun layout yang digunakan bersama. Setiap contoh render diverifikasi dengan mengeksekusi template yang sebenarnya pada proyek contoh.
Direktif kontrol dan penampilan data#
Template Blade adalah berkas HTML biasa yang diberi tambahan berupa direktif berawalan tanda @ dan ekspresi pencetak yang diapit kurung kurawal ganda. Direktif @if, @foreach, dan @endif mengatur percabangan serta perulangan pada sisi template, sedangkan {{ $variabel }} mencetak nilai variabel yang dikirim controller. Contoh berikut adalah template uji yang menggunakan keduanya.
@if ($pengumuman != '')
<p>Pengumuman: {{ $pengumuman }}</p>
@else
<p>Tidak ada pengumuman.</p>
@endif
<ul>
@foreach ($daftar as $item)
<li>{{ $item }}</li>
@endforeach
</ul>Template tersebut dirender dengan dua variabel data agar strukturnya dapat diamati pada keluarannya. Perintah berikut menyalin template uji ke proyek contoh, me-render-nya, lalu menghapusnya kembali.
# pasang template uji, layout, dan halaman turunan pada proyek contoh
cp uji-direktif.blade.php ~/aplikasi-catatan/resources/views/uji-direktif.blade.php
mkdir -p ~/aplikasi-catatan/resources/views/layouts ~/aplikasi-catatan/resources/views/halaman
cp app.blade.php ~/aplikasi-catatan/resources/views/layouts/app.blade.php
cp tentang.blade.php ~/aplikasi-catatan/resources/views/halaman/tentang.blade.php
cd ~/aplikasi-catatan
# render template uji dengan data pengumuman dan daftar
php artisan tinker --execute='echo view("uji-direktif", ["pengumuman" => "Rapat piket hari Senin", "daftar" => ["Belajar routing", "Menulis controller"]])->render();'
# hapus template uji
rm resources/views/uji-direktif.blade.php<p>Pengumuman: Rapat piket hari Senin</p>
<ul>
<li>Belajar routing</li>
<li>Menulis controller</li>
</ul>Karena variabel $pengumuman tidak kosong, cabang @if yang dirender, dan @foreach mengulang elemen li sebanyak dua kali sesuai isi $daftar. Apabila $pengumuman berupa string kosong, cabang @else yang dirender. Simulasi interaktif berikut memperlihatkan mekanisme yang sama dengan data yang dapat diubah.
Direktif lain yang serupa meliputi @unless untuk kondisi terbalik, @isset untuk menguji apakah sebuah variabel terisi, dan @foreach yang menyediakan variabel $loop berisi informasi iterasi seperti $loop->first dan $loop->last.
Escape pada penulisan {{ }}#
Kurung kurawal ganda {{ $variabel }} tidak mencetak nilai apa adanya, melainkan menjalankan htmlspecialchars pada nilainya terlebih dahulu. Karakter seperti < dan & diubah menjadi entitas HTML, sehingga teks yang dimasukkan pengguna tidak pernah dieksekusi sebagai markup. Perilaku ini merupakan proteksi dasar terhadap cross-site scripting (XSS), yaitu serangan yang menyelipkan skrip melalui data yang dirender ulang.
Apabila suatu nilai memang berisi HTML yang sengaja diperlakukan sebagai markup, Blade menyediakan sintaks {!! $variabel !!}. Sintaks ini melewati escape sepenuhnya, sehingga nilainya wajib bersumber dari kode yang sepenuhnya terkendali, bukan dari masukan pengguna. Kebutuhan semacam ini lazimnya digantikan dengan pustaka pemformatan markdown yang menghasilkan HTML yang telah disaring.
Komentar Blade ditulis dengan {{-- teks --}} dan tidak ikut tercetak pada HTML keluaran, berbeda dengan komentar HTML <!-- --> yang tetap terkirim ke browser.
Pewarisan template dan layout#
Halaman aplikasi umumnya berbagi kerangka yang sama berupa header, navigasi, dan footer. Blade menyediakan pewarisan template untuk kebutuhan itu. Satu berkas layout mendefinisikan kerangkanya, dan setiap halaman turunan mengisi bagian yang didefinisikan induknya. Layout proyek contoh didefinisikan seperti berikut.
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>@yield('judul', 'Aplikasi Catatan')</title>
</head>
<body>
<header><strong>Aplikasi Catatan</strong></header>
<main>
@yield('konten')
</main>
</body>
</html>Direktif @yield('judul', 'Aplikasi Catatan') menandai titik yang diisi halaman anaknya, dengan nilai baku apabila halaman anak tidak mengisinya. Halaman turunan menyatakan layout induknya melalui @extends dan mengisi setiap bagian melalui @section.
@extends('layouts.app')
@section('judul', 'Tentang')
@section('konten')
<p>Halaman tentang aplikasi catatan.</p>
@endsectionBentuk @section('judul', 'Tentang') digunakan untuk isi satu baris, sedangkan @section ... @endsection digunakan untuk isi yang lebih panjang. Halaman turunan itu dirender pada proyek contoh untuk melihat gabungan keduanya.
cd ~/aplikasi-catatan
# render halaman tentang dari layout dan child yang sudah terpasang
php artisan tinker --execute='echo view("halaman.tentang")->render();'<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>Tentang</title>
</head>
<body>
<header><strong>Aplikasi Catatan</strong></header>
<main>
<p>Halaman tentang aplikasi catatan.</p>
</main>
</body>
</html>Keluaran menunjukkan bagian @yield yang telah terisi, yaitu judul menggantikan isi tag title, sedangkan konten menempati bagian main. Halaman turunan tidak pernah menyentuh bagian lain dari kerangka, sehingga perubahan header cukup dilakukan pada layout saja.
Untuk potongan templat yang digunakan berulang tanpa membentuk halaman penuh, misalnya kartu atau baris tabel, direktif @include memasukkan satu view ke dalam view lain. Potongan yang dimasukkan dapat menerima variabel melalui argumen array pada @include, dan variabel yang sudah ada pada view induknya ikut tersedia di dalamnya. Pemisahan semacam ini menjaga satu tempat definisi untuk tampilan yang muncul di banyak halaman, sehingga perbaikan cukup dilakukan sekali pada berkas potongannya.
Kesalahan umum#
Kesalahan pertama adalah melupakan penutup direktif. Setiap @section yang dibuka tanpa @endsection atau setiap @if tanpa @endif menghasilkan error saat template dikompilasi, dan pesannya menunjuk nomor baris pada berkas templat, bukan pada controller.
Kesalahan kedua adalah salah nama view saat memanggil view(). Nama halaman.tentang dipetakan ke resources/views/halaman/tentang.blade.php, dan satu karakter saja yang berbeda melempar exception InvalidArgumentException dengan pesan View [halaman.tentng] not found.. Perbaikannya adalah menyamakan nama pemanggilan dengan struktur direktori dan nama berkasnya.
Kesalahan ketiga adalah menyimpan templat dengan ekstensi yang salah. Berkas yang disimpan sebagai app.php tanpa .blade tidak diolah Blade sama sekali, sehingga direktif @yield tercetak mentah pada HTML. Pastikan setiap templat berakhiran .blade.php.
Kesalahan keempat adalah melakukan escape dua kali, misalnya menjalankan htmlspecialchars($judul) pada controller lalu mencetaknya kembali dengan {{ $judul }}. Kurung kurawal ganda sudah menjalankan escape secara otomatis, sehingga entitas HTML yang dibentuk controller dikenai escape sekali lagi dan tanda seperti & ditampilkan sebagai teks & pada halaman. Serahkan escape sepenuhnya pada templat, dan kirimkan nilai mentah dari controller.
Ringkasan#
- Template Blade berakhiran
.blade.phpdan memadukan HTML dengan direktif@if,@foreach, dan sejenisnya untuk percabangan serta perulangan di sisi template. - Penulisan
{{ $variabel }}menjalankan escape HTML atas nilainya, sedangkan{!! !!}melewati escape dan hanya aman untuk nilai yang terkendali. - Pewarisan melalui
@extends,@section, dan@yieldmemisahkan kerangka layout dari isi tiap halaman, sehingga kerangka cukup diubah di satu berkas. - Template dikompilasi ke PHP biasa dan hasilnya di-cache otomatis, sehingga render ulang tidak memproses ulang direktifnya.
Referensi#
- Blade Templates — Laravel — Dokumentasi resmi Blade yang menjadi dasar pembahasan direktif, escape, pewarisan, dan layout pada topik ini.