โ† Semua pembelajaran / Laravel Nol โ†’ Enterprise
Fase 1 ยท Request, Routing & Blade

Controller & response

Controller yang baik itu tipis: ia menerjemahkan HTTP jadi panggilan ke domain, lalu menerjemahkan hasilnya kembali jadi HTTP. Semua kecacatan arsitektur aplikasi Laravel bermula dari controller yang gemuk.

Sumber asli laravel.com Resmi Rangkuman ~7 menit baca

Intisari

  • Controller resource punya tujuh method dengan nama baku. Ikuti namanya โ€” seluruh ekosistem mengandalkannya.
  • Nilai kembalian otomatis dikonversi: array dan model jadi JSON, string jadi HTML, view() jadi halaman.
  • Single action controller (__invoke) untuk aksi yang tidak punya saudara.
  • Dependensi diketik di parameter method โ€” container yang menyuntikkannya (Fase 3).
  • Aturan sehat: controller tidak menyentuh query kompleks, tidak mengirim email, tidak menghitung harga.

Controller resource

class ProdukController extends Controller
{
    public function index(): View
    {
        return view('produk.index', [
            'produk' => Produk::query()
                ->with('kategori')          // cegah N+1 โ€” Fase 2
                ->latest()
                ->paginate(20),
        ]);
    }

    public function show(Produk $produk): View          // route model binding
    {
        return view('produk.show', compact('produk'));
    }

    public function store(SimpanProdukRequest $request): RedirectResponse
    {
        // Sudah tervalidasi DAN sudah terotorisasi sebelum baris ini berjalan.
        $produk = Produk::create($request->validated());

        return redirect()
            ->route('produk.show', $produk)
            ->with('sukses', 'Produk tersimpan.');
    }

    public function destroy(Produk $produk): RedirectResponse
    {
        $this->authorize('delete', $produk);            // Fase 4
        $produk->delete();

        return back()->with('sukses', 'Produk dihapus.');
    }
}

Perhatikan yang tidak ada di sana. Tidak ada if ($request->name == '') โ€” itu tugas Form Request. Tidak ada if ($user->id != $produk->user_id) โ€” itu tugas policy. Tidak ada perhitungan harga โ€” itu tugas kelas domain. Controller tipis bukan gaya penulisan, melainkan hasil dari memindahkan setiap urusan ke tempat yang sudah disediakan Laravel.

Apa pun yang kamu kembalikan, jadi respons

KembalikanHasilnya
view('produk.index', [...])HTML 200
['nama' => 'Ani']JSON 200, Content-Type otomatis
Model atau Collection EloquentJSON โ€” hati-hati, semua kolom ikut terbawa
redirect()->route('produk.index')302
back()->withErrors($e)302 ke halaman sebelumnya
response()->json($data, 201)JSON dengan status pilihanmu
response()->noContent()204 โ€” untuk destroy di API
abort(404) / abort(403, 'pesan')Hentikan dan lempar error
Storage::download($path)Unduhan berkas

Mengembalikan model langsung itu kebocoran data yang menunggu terjadi. return $user; mengirim semua kolom yang tidak ada di $hidden โ€” termasuk email, remember_token, atau kolom internal yang baru saja ditambahkan rekanmu lewat migrasi. Untuk API, pakai API Resource (Fase 5) supaya bentuk keluaran menjadi keputusan sadar.

Single action controller

// php artisan make:controller UnduhInvoice --invokable
class UnduhInvoice extends Controller
{
    public function __invoke(Invoice $invoice)
    {
        $this->authorize('view', $invoice);

        return Storage::download($invoice->path, "invoice-{$invoice->nomor}.pdf");
    }
}
Route::get('/invoice/{invoice}/unduh', UnduhInvoice::class)->name('invoice.unduh');

Pola ini menyelamatkanmu dari controller bernama MiscController berisi dua belas method yang tidak saling berhubungan. Kalau sebuah aksi tidak punya saudara yang jelas, ia layak punya kelas sendiri.

Injeksi dependensi di method

public function store(
    SimpanPesananRequest $request,     // form request โ€” divalidasi otomatis
    Pesanan $pesanan,                  // route model binding
    GerbangPembayaran $gerbang,        // di-resolve dari container (Fase 3)
): RedirectResponse {
    $gerbang->tagih($pesanan, $request->integer('jumlah'));

    return back();
}

Laravel membaca tipe setiap parameter dan mengisinya sendiri. Inilah alasan menulis tipe di Laravel bukan sekadar dokumentasi โ€” tipe adalah instruksi untuk container.

Tanda controller sudah terlalu gemuk

  1. Satu method lebih dari sekitar 20 baris.
  2. Ada DB:: atau query builder panjang di dalamnya.
  3. Ada perhitungan bisnis โ€” pajak, diskon, ongkir.
  4. Method-nya sulit dijelaskan tanpa kata "dan": "menyimpan pesanan dan mengirim email dan memotong stok".
  5. Logika yang sama muncul lagi di perintah Artisan atau job.

Setiap butir di atas punya obat yang sudah disediakan framework: query scope (Fase 2), event dan job (Fase 3), policy (Fase 4), atau sekadar satu kelas action di app/Actions.

Latihan: buat ProdukController --resource, isi index dan show, lalu tambahkan satu single action controller EksporProduk yang mengembalikan CSV lewat response()->streamDownload(...). Cek hasilnya dengan curl -i dan pastikan header Content-Type-nya benar.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.