Belajar Laravel #4: Controller Lebih Dalam — Resource Controller & Dependency Injection

Masih ingat di episode kedua waktu pertama kali bikin controller? Waktu itu saya cuma sekadar “biar routenya rapi”. Belakangan, setelah mulai menulis logika yang lebih panjang, baru terasa bedanya: controller itu bukan sekadar tempat numpang kode, tapi otak dari aplikasi. Hari ini saya bedah lebih dalam: cara membuat controller dengan Artisan, resource controller yang menghasilkan tujuh method sekaligus, dan sedikit tentang dependency injection yang awalnya bikin saya bingung.

Tabel tujuh method resource controller Laravel beserta HTTP verb dan URI-nya
Satu baris Route::resource menghasilkan tujuh route dengan konvensi nama method yang tetap.

Kapan closure di route tidak cukup

Di episode ketiga saya sempat menulis beberapa route dengan closure langsung. Untuk halaman sederhana memang enak: satu file, satu fungsi, selesai. Tapi begitu logikanya lebih dari tiga atau empat baris — misalnya ambil data, validasi, lalu return view — route web.php cepat berubah jadi kuburan kode. Ini berarti bagi saya: closure cocok untuk halaman statis kecil, sisanya wajib pindah ke controller. Analoginya seperti dapur rumah: masak mie instan boleh di kamar pakai ketel listrik, tapi kalau sudah masak hidangan utuh, ya harus di dapur yang tertata.

Membuat controller dengan Artisan

Cara paling bersih membuat controller adalah lewat perintah Artisan. Saya suka bagian ini karena Laravel yang menyusun kerangka filenya, jadi tinggal isi logika:

php artisan make:controller TaskController

# Versi lengkap: tujuh method CRUD sekaligus
php artisan make:controller TaskController --resource

File hasilnya muncul di app/Http/Controllers/. Kebiasaan saya sekarang: setiap kali mau bikin controller, selalu lewat Artisan, bukan buat file manual. Selain konsisten dengan konvensi framework, nama class dan namespace-nya pasti benar.

Resource controller: satu route, tujuh method

Ini fitur yang paling saya suka minggu ini. Dengan satu baris Route::resource, Laravel otomatis memetakan tujuh route ke tujuh method dengan nama yang sudah dibakukan:

use App\Http\Controllers\TaskController;

Route::resource('tasks', TaskController::class);

// Setara dengan menulis manual:
// GET    /tasks            TaskController@index   - daftar data
// GET    /tasks/create     TaskController@create  - form tambah
// POST   /tasks            TaskController@store   - simpan baru
// GET    /tasks/{task}     TaskController@show    - detail satu data
// GET    /tasks/{task}/edit  TaskController@edit  - form ubah
// PUT    /tasks/{task}     TaskController@update  - simpan perubahan
// DELETE /tasks/{task}     TaskController@destroy - hapus

Yang penting dicatat: urutan pendefinisian di tabel di atas bukan asal-asalan. Route /tasks/create harus terdaftar sebelum /tasks/{task}, karena kalau tidak, kata “create” bisa tertelan sebagai nilai parameter {task}. Untung Route::resource sudah menata urutannya secara otomatis — salah satu alasan kenapa saya makin jarang mendefinisikan route CRUD secara manual.

Contoh nyata: controller daftar tugas

Saya praktikkan langsung dengan studi kasus kecil: manajemen tugas. Ini isi controller versi minimal saya:

namespace App\Http\Controllers;

use App\Models\Task;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class TaskController extends Controller
{
    public function index(): View
    {
        return view('tasks.index', [
            'tasks' => Task::latest()->get(),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'title' => ['required', 'max:255'],
        ]);

        Task::create($validated);

        return redirect()->route('tasks.index');
    }

    public function destroy(Task $task): RedirectResponse
    {
        $task->delete();

        return redirect()->route('tasks.index');
    }
}

Dua hal yang membuat saya berdecak saat membaca ulang kode di atas. Pertama, route model binding: type-hint Task $task di method destroy membuat Laravel otomatis mencari data berdasarkan ID di URL — kalau tidak ketemu, langsung 404 tanpa saya menulis satu baris pengecekan pun. Kedua, validasi $request->validate() gagal otomatis melempar pengguna balik ke form beserta errornya. Kerja yang biasanya saya tulis manual bertahun lalu di PHP native, sekarang dua baris.

Dependency injection: minta, jangan dicari sendiri

Istilah ini dulu terdengar menakutkan, padahal idenya sederhana. Alih-alih sebuah class membuat sendiri kebutuhannya (misalnya new Request() di dalam method), kita cukup memintanya lewat parameter, dan container Laravel yang menyediakan. Contohnya type-hint Request $request di atas — saya tidak pernah membuat objek itu, Laravel yang menyuntikkannya. Ini analogi yang saya pegang: di restoran kita tidak masuk ke dapur lalu memasak sendiri; kita cukup memesan lewat pelayan. Container itulah sang pelayan.

// Constructor injection: kebutuhan disuntik sekali di konstruktor
public function __construct(protected LoggerInterface $logger)
{
    //
}

public function index(): View
{
    $this->logger->info('Halaman tugas dibuka');

    return view('tasks.index', ['tasks' => Task::all()]);
}

Manfaat terbesarnya ada di testing: karena dependensi disuntik, saya bisa menggantinya dengan versi palsu (mock) saat uji coba. Catatan untuk diri sendiri: jangan sampai memanggil helper seperti app(LoggerInterface::class) di tengah method hanya karena lebih singkat — itu menyalahi keuntungan DI-nya sendiri.

Kesimpulan

  • Controller = rumah bagi logika aplikasi; closure di route hanya untuk hal-hal sekecil mungkin.
  • php artisan make:controller Nama --resource menghasilkan tujuh method CRUD dengan konvensi baku.
  • Route::resource hemat banyak baris dan urutan routenya sudah aman.
  • Type-hint parameter (Request, Model) = dependency injection + route model binding bekerja diam-diam untuk kita.

Berikutnya episode lima saya akan masuk ke Blade templating yang lebih serius: layout master-child dan komponen. Sampai jumpa di catatan belajar berikutnya.


Sumber

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses