Laravel Best Practices dan Design Patterns: Panduan Praktis Developer Modern
Laravel adalah framework PHP yang sangat populer karena sintaksnya yang bersih dan ekosistemnya yang lengkap. Namun, kemudahan yang ditawarkan Laravel bisa menjadi pedang bermata dua: tanpa disiplin arsitektur dan pemahaman keamanan yang baik, aplikasi Anda berisiko menjadi fat controller, sulit di-maintain, hingga rentan terhadap mass assignment vulnerability. Artikel ini membahas best practices, design patterns yang umum digunakan, serta analisis keamanan nyata yang wajib dipahami setiap developer Laravel — termasuk pemula.
Pembahasan: Design Patterns yang Wajib Dikuasai
Laravel menganut pola MVC (Model-View-Controller), tetapi untuk aplikasi berskala menengah ke atas, MVC saja tidak cukup. Beberapa design patterns yang sebaiknya Anda terapkan:
1. Repository Pattern — memisahkan logika akses data dari Controller. Ini memudahkan unit testing dan mengganti sumber data (misalnya dari Eloquent ke API eksternal) tanpa mengubah controller.
2. Service Layer Pattern — menempatkan business logic di kelas Service, sehingga Controller tetap tipis (thin controller). Service juga memudahkan penggunaan database transaction dan event dispatching.
3. Strategy Pattern — sangat berguna untuk logika yang bercabang, seperti multiple payment gateway atau driver notifikasi. Alih-alih `if-else` panjang, gunakan interface dan implementasi terpisah.
4. Form Request & Policy — bukan sekadar "pattern", tetapi fitur bawaan Laravel yang wajib dipakai untuk validation dan authorization. Ini komponen kunci untuk keamanan.
Best practices lain yang praktis langsung diterapkan: gunakan dependency injection lewat constructor (bukan `app()` atau Facade di dalam method), aktifkan strict typing (`declare(strict_types=1)`), manfaatkan route model binding, dan jalankan `php artisan config:cache` serta `route:cache` di production untuk meningkatkan performa.
Contoh Implementasi
Berikut implementasi Repository + Service Layer yang bersih dan mudah diuji:
// app/Services/RegisterUserService.php
namespace App\Services;
use App\Models\User;
use App\Repositories\UserRepository;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
class RegisterUserService
{
public function __construct(private UserRepository $repo) {}
public function handle(array $data): User
{
return DB::transaction(function () use ($data) {
$user = $this->repo->create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
event(new \Illuminate\Auth\Events\Registered($user));
return $user;
});
}
}
Controller cukup memanggil service dan tetap tipis:
// app/Http/Controllers/RegisterController.php
public function store(RegisterRequest $request, RegisterUserService $service)
{
$user = $service->handle($request->validated());
return response()->json(['user' => $user], 201);
}
Analisis Keamanan: Mass Assignment Vulnerability
Salah satu celah paling sering ditemukan di aplikasi Laravel adalah mass assignment. Celah ini terjadi ketika developer menggunakan `$request->all()` atau mendefinisikan `protected $guarded = []` pada model, sehingga semua kolom database dapat diisi langsung dari input user — termasuk kolom sensitif seperti `is_admin`, `role`, atau `balance`.
Cara kerja celah: Eloquent saat memanggil `create()` atau `update()` melakukan proses fill() terhadap atribut yang dikirim. Jika tidak ada whitelist (`$fillable`) yang membatasi atribut mana yang boleh diisi, maka payload kiriman user bisa menyuntikkan kolom yang seharusnya tidak boleh diubah.
Demonstrasi eksploitasi: Misalkan endpoint update profil menerima semua field:
// ❌ RENTAN
class User extends Authenticatable
{
protected $guarded = []; // semua kolom boleh diisi
}
// Controller profile update
public function update(Request $request, User $user)
{
$user->update($request->all());
}
Penyerang dapat mengirim request berikut untuk menaikkan hak aksesnya sendiri menjadi administrator:
curl -X PATCH https://app.example.com/api/profile \
-H "Authorization: Bearer <token_user_biasa>" \
-d "name=Budi&is_admin=1"
Setelah request berhasil, `is_admin` berubah menjadi `1` dan penyerang memiliki akses admin — eskalasi hak akses tanpa satu pun baris kode "login admin" yang dieksekusi.
Cara Pencegahan
1. Gunakan `$fillable` sebagai whitelist. Deklarasikan hanya kolom yang boleh diisi user:
// ✅ AMAN
class User extends Authenticatable
{
protected $fillable = ['name', 'email', 'password']; // is_admin TIDAK ada di sini
}
public function update(UpdateProfileRequest $request, User $user)
{
$data = $request->validate([
'name' => 'required|string|max:100',
'email' => 'required|email|unique:users,email,'.$user->id,
]);
$user->update($data); // hanya name & email yang bisa diproses
}
2. Wajib gunakan Form Request + `validated()`, bukan `$request->all()`. Hanya data yang lolos validasi yang boleh masuk ke model.
3. Gunakan `$request->only()` / `$request->safe()` jika memungkinkan, dan hindari `$guarded = []` di production.
4. Terapkan Policy & Gate untuk otorisasi berbasis peran, serta aktifkan middleware `auth` dan `verified` pada route sensitif.
5. Audit otomatis: gunakan tools seperti Larastan/PHPStan dan Laravel Security Checker di pipeline CI untuk mendeteksi pola berisiko sejak dini.
Kesimpulan
Membangun aplikasi Laravel yang berkualitas bukan hanya soal bisa "jalan", tetapi juga soal arsitektur yang bersih dan keamanan yang teruji. Terapkan design patterns seperti Repository dan Service Layer untuk menjaga controller tetap tipis dan business logic tetap terisolasi. Dari sisi keamanan, pahami bahwa `$guarded = []` dan `$request->all()` adalah dua pola paling berbahaya yang sering diabaikan. Selalu gunakan $fillable sebagai whitelist, validasi dengan Form Request, dan otorisasi dengan Policy. Dengan disiplin ini, aplikasi Laravel Anda akan lebih maintainable, scalable, dan jauh lebih aman dari serangan eskalasi hak akses.