Pada artikel ini kita akan belajar membuat kode project Laravel yang kita buat lebih bersih, kita pindahkan beberapa potongan kode yang ada di Controller.
Laravel menawarkan berbagai metode untuk menjaga agar controller tetap ramping. Pertanyaan umum yang muncul adalah, “Di mana lagi saya bisa menempatkan logika saya?” Berikut adalah beberapa alternatif tempat untuk memindahkan logika dari Controller kamu:
Mari kita mulai dengan menyederhanakan kode Controller kamu.
Pertama, mari kita lihat kode awal kamu:
public function store(Request $request)
{
$this->authorize('user_create');
$userData = $request->validate([
'name' => 'required',
'email' => 'required|unique:users',
'password' => 'required',
]);
$userData['start_at'] = Carbon::createFromFormat('m/d/Y', $request->start_at)->format('Y-m-d');
$userData['password'] = bcrypt($request->password);
$user = User::create($userData);
$user->roles()->sync($request->input('roles', []));
Project::create(['user_id' => $user->id, 'name' => 'Demo project 1']);
Category::create(['user_id' => $user->id, 'name' => 'Demo category 1']);
Category::create(['user_id' => $user->id, 'name' => 'Demo category 2']);
MonthlyReport::where('month', now()->format('Y-m'))->increment('users_count');
$user->sendEmailVerificationNotification();
$admins = User::where('is_admin', 1)->get();
Notification::send($admins, new AdminNewUserNotification($user));
return response()->json(['result' => 'success', 'data' => $user], 200);
}
Validasi adalah bagian penting dari setiap aplikasi Laravel. Terutama saat menangani banyak bidang, validasi dapat membuat kode kamu berantakan. Mari kita sederhanakan ini.
Pertama, kita akan memindahkan aturan validasi ke dalam Form Request. Ini tidak hanya berlaku untuk validasi data tetapi juga untuk izin.
Untuk membuat Form Request, jalankan perintah berikut:
php artisan make:request StoreUserRequest
Ini akan membuat file baru app\Http\Requests\StoreUserRequest.php
dengan dua metode penting: authorize()
untuk izin dan rules()
untuk validasi data.
Form Request kamu seharusnya terlihat seperti ini:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreUserRequest extends FormRequest
{
public function authorize()
{
return Gate::allows('user_create');
}
public function rules()
{
return [
'name' => 'required',
'email' => 'required|unique:users',
'password' => 'required',
];
}
}
Dalam Controller, gunakan StoreUserRequest
alih-alih Request
default. Kamu bisa mengakses data yang sudah divalidasi langsung dengan memanggil metode validated()
dari Request.
Misalnya, Controller kamu mungkin terlihat seperti ini:
public function store(StoreUserRequest $request)
{
$userData = $request->validated();
$userData['start_at'] = Carbon::createFromFormat('m/d/Y', $request->start_at)->format('Y-m-d');
$userData['password'] = bcrypt($request->password);
$user = User::create($userData);
$user->roles()->sync($request->input('roles', []));
// ...
}
Perubahan kecil ini secara signifikan mengurangi kerumitan Controller, membuat kode kamu lebih terorganisir dan mudah dikelola.
Bayangkan kamu perlu mengatur beberapa data sebelum disimpan di database, seperti format tanggal atau enkripsi kata sandi. Alih-alih melakukan ini di dalam Controller, Laravel’s Eloquent menyediakan alat yang efisien: Mutators dan Observers. Mari kita lihat cara kerjanya.
Mutators memungkinkan kamu untuk menangani nilai atribut model sebelum menyimpannya ke database. Ada dua pendekatan utama untuk mendefinisikan Mutators berdasarkan versi Laravel kamu:
public function setStartAtAttribute($value)
{
$this->attributes['start_at'] = Carbon::createFromFormat('m/d/Y', $value)->format('Y-m-d');
}
public function setPasswordAttribute($value)
{
$this->attributes['password'] = bcrypt($value);
}
protected function startAt(): Attribute
{
return Attribute::make(
set: fn ($value) => Carbon::createFromFormat('m/d/Y', $value)->format('Y-m-d')
);
}
protected function password(): Attribute
{
return Attribute::make(
set: fn ($value) => bcrypt($value)
);
}
Observers memberikan kamu metode yang dipicu selama siklus hidup model, seperti saat entri dibuat atau diperbarui.
Untuk menghasilkan Observer untuk model User, gunakan:
php artisan make:observer UserObserver --model=User
Berikut adalah contoh cara mengatur Observer untuk mengubah data sebelum catatan dibuat:
namespace App\Observers;
use App\Models\User;
use Carbon\Carbon;
class UserObserver
{
public function creating(User $user)
{
$user->start_at = Carbon::createFromFormat('m/d/Y', $user->start_at)->format('Y-m-d');
$user->password = bcrypt($user->password);
}
}
Catatan bahwa beberapa metode, seperti creating()
, mungkin tidak didokumentasikan secara resmi, menunjukkan bahwa mereka tidak selalu menjadi pendekatan yang direkomendasikan.
Sekarang, dengan modifikasi data yang ditangani di luar Controller, kode menjadi lebih bersih:
public function store(StoreUserRequest $request)
{
$user = User::create($request->validated());
$user->roles()->sync($request->input('roles', []));
// ...
}
Ini menunjukkan bagaimana dengan alat yang tepat, Laravel membantu dalam menghasilkan kode yang rapi dan dapat dikelola.
Selanjutnya, dalam perjalanan kita untuk merapikan Controller, kita akan menyelami logika inti yang bertanggung jawab untuk menyimpan data di database. Kelas Service khusus akan menjadi sekutu kita untuk tugas ini.
Kelas Service tidak memiliki perintah artisan khusus untuk pembuatannya, jadi kita akan membuatnya secara manual. Mari kita kembangkan file UserService.php
dalam direktori app/Services
, yang berisi logika untuk membuat pengguna:
namespace App\Services;
use App\Models\User;
class UserService
{
public function create(array $userData): User
{
$user = User::create($userData);
$user->roles()->sync($userData['roles']);
return $user;
}
}
Dalam UserService
, kita memperkenalkan metode create()
yang mengambil data yang sudah divalidasi sebagai inputnya, mengatur pembuatan pengguna, sinkronisasi peran, dan mengembalikan pengguna baru.
Sekarang, untuk menggunakan layanan ini dalam Controller kita, ada beberapa jalur yang bisa kita tempuh:
Langsung menginisiasi layanan di dalam Controller, dan mengoper data yang sudah divalidasi ke metode create()
.
$user = (new UserService())->create($request->validated());
Menggunakan dependency injection untuk memperkenalkan layanan ke dalam metode Controller, memungkinkan cara yang rapi dan efisien untuk mengakses fungsi layanan kita.
public function store(StoreUserRequest $request, UserService $userService)
{
$user = $userService->create($request->validated());
// ...
}
Menggunakan pendekatan kelas layanan meningkatkan organisasi kode kita, mendorong keterbacaan dan pemeliharaan dengan menjaga Controller tetap ramping dan fokus.
Dalam ekosistem Laravel yang luas, baik kelas Service maupun Action menawarkan cara terorganisir untuk mengelola logika. Mereka tampak mirip tetapi digunakan berdasarkan bagaimana kamu lebih suka menyusun logika aplikasi kamu. Mari kita uraikan konsep-konsep ini dengan sederhana.
Kelas Action bersifat presisi, biasanya didedikasikan untuk satu operasi. Tidak seperti kelas Service, tidak ada perintah Artisan bawaan untuk
membuat kelas Action. Namun, konvensi dalam penamaan kelas Action adalah dengan menggunakan akhiran Action
.
Mari kita buat CreateUserAction.php
di app/Actions
:
namespace App\Actions;
use App\Models\User;
class CreateUserAction
{
public function execute(array $data): User
{
$user = User::create($data);
$user->roles()->sync($data['roles']);
return $user;
}
}
Berikut adalah cara kita menggunakannya dalam Controller kita, menggunakan dependency injection:
public function store(StoreUserRequest $request, CreateUserAction $createUserAction)
{
$user = $createUserAction->execute($request->validated());
// ...
}
Seperti yang terlihat, kelas Action juga mendorong logika bisnis yang terpisah, tetapi biasanya lebih terfokus pada tugas spesifik.
Melanjutkan dengan menyiapkan Observer, kita akan memperkenalkan logika untuk mengirim pemberitahuan admin saat pengguna baru dibuat. Di Laravel, kamu dapat memanfaatkan metode created()
dalam Observer untuk mencapai ini.
namespace App\Observers;
use App\Models\User;
use App\Notifications\AdminNewUserNotification;
use Illuminate\Support\Facades\Notification;
class UserObserver
{
public function created(User $user)
{
$admins = User::where('is_admin', 1)->get();
Notification::send($admins, new AdminNewUserNotification($user));
}
}
Observer membantu kamu mengelola logika pemberitahuan tanpa menambahkan beban ke Controller kamu. Berikut adalah contoh cara mendaftarkan Observer di AppServiceProvider
:
use App\Models\User;
use App\Observers\UserObserver;
public function boot()
{
User::observe(UserObserver::class);
}
Dengan ini, Controller kamu tetap bersih dan tanggung jawab pemberitahuan ditangani dengan rapi oleh Observer.
Untuk menangani pembaruan laporan bulanan, kamu bisa memanfaatkan pekerjaan latar belakang (Job) di Laravel. Jobs memungkinkan kamu untuk menangani tugas asinkron yang memerlukan waktu lebih lama untuk diproses, memastikan aplikasi kamu tetap responsif.
Untuk membuat Job yang memperbarui laporan bulanan:
php artisan make:job UpdateMonthlyReport
Kemudian, di dalam Job, kita dapat mendefinisikan logika untuk memperbarui laporan:
namespace App\Jobs;
use App\Models\MonthlyReport;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class UpdateMonthlyReport implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
MonthlyReport::where('month', now()->format('Y-m'))->increment('users_count');
}
}
Kemudian, di dalam Controller kamu, cukup panggil pekerjaan ini:
use App\Jobs\UpdateMonthlyReport;
public function store(StoreUserRequest $request, CreateUserAction $createUserAction)
{
$user = $createUserAction->execute($request->validated());
// Mengirimkan pekerjaan ke antrian
UpdateMonthlyReport::dispatch();
return response()->json(['result' => 'success', 'data' => $user], 200);
}
Dengan penggunaan Jobs, kamu memastikan tugas berat ditangani secara efisien di latar belakang, memberikan respons cepat kepada pengguna.
Dengan menerapkan praktik-praktik ini, kamu akan menemukan bahwa Controller kamu menjadi lebih ramping, logika lebih terorganisir, dan aplikasi lebih dapat dikelola. Laravel memberikan berbagai alat dan metode untuk memisahkan berbagai logika, dan dengan memanfaatkannya, kamu dapat menjaga kode tetap bersih, terstruktur, dan efisien.
Penulis dari artikel ini.