Salah satu perkara yang menarik pada rangkakerja Laravel ialah ciri Event. Penggunaan event pada Laravel membolehkan programmer untuk trigger sesuatu kod yang mempunyai keperluan tertentu.
Sebagai contoh, setiap kali pengguna log masuk ke dalam sistem, kita ingin merekodkan tarikh dan masa ke dalam pangkalan data. Dengan penggunaan event, kita boleh mengasingkan fungsi ini di luar AuthController. Dengan cara ini, controller kita lebih mudah untuk diuruskan pada kemudian hari.
Persediaan
Laravel 5 didatangkan dengan pelbagai artisan command untuk kegunaan kita. Jadi untuk menjana event yang baru, contoh UserLoggedIn, kita boleh gunakan command berikut:
php artisan make:event UserLoggedIn
Laravel akan mencipta fail /app/Events/UserLoggedIn.php
secara automatik. Jika dilihat, isi kandungannya sangat ringkas.
<?php namespace AppEvents; use AppEventsEvent; use IlluminateQueueSerializesModels; class UserLoggedIn extends Event { use SerializesModels; /** * Create a new event instance. * * @return void */ public function __construct() { // } }
Seterusnya, kita memerlukan handler untuk menjalankan operasi-operasi kita. Satu event boleh mempunyai banyak handler. Sebaiknya setiap satu operasi kita pecahkan kepada handler tertentu.
Sebagai contoh, kita ingin merekodkan tarikh dan masa pengguna log masuk, jadi amat sesuai untuk kita berikan nama RecordUserLoggedInTimestamp
untuk handler ini.
php artisan handler:event RecordUserLoggedInTimestamp --event=UserLoggedIn
Perhatikan pada bahagian --event=UserLoggedIn
. Di sini kita akan merujuk kepada event yang baru kita hasilkan tadi.
<?php namespace AppHandlersEvents; use AppEventsUserLoggedIn; use IlluminateQueueInteractsWithQueue; use IlluminateContractsQueueShouldBeQueued; class RecordUserLoggedIn { /** * Create the event handler. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param UserLoggedIn $event * @return void */ public function handle(UserLoggedIn $event) { // } }
Kod yang dijana seperti contoh di atas tiada sebarang operasi yang berlaku. Laravel akan menggunakan fungsi handle()
secara automatik setiap kali event UserLoggedIn
dijalankan.
Memandangkan tiada column khusus untuk merekodkan tarikh pengguna log masuk yang terdapat di dalam table users
, jadi kita perlu menambah satu column baru menggunakan Migration.
php artisan make:migration add_last_logged_in_column_in_users_table --table=users
Tambah kod yang ditandakan pada fail migration yang baru dicipta yang berada di database/migrations/XXXX_XX_XX_XXXXXX_add_last_logged_in_column_in_users_table
.
.php
public function up() { Schema::table('users', function(Blueprint $table) { $table->timestamp('last_logged_in'); }); }
Kemudian kita run migration ini:
php artisan migrate
Selesai bahagian persediaan sebelum kita mula dengan event dan handler.
Langkah 1
Sekarang kita boleh ubahsuai kod-kod yang berada di dalam fail /app/Events/UserLoggedIn.php
untuk kita gunakan. Gantikan kod yang sedia ada dengan kod berikut:
<?php namespace AppEvents; use AppEventsEvent; use AppUser; use IlluminateQueueSerializesModels; class UserLoggedIn extends Event { use SerializesModels; /** * @var User */ public $user; /** * Create a new event instance. * * @param User $user */ public function __construct(User $user) { $this->user = $user; } }
Perubahan
Kita lihat perubahan yang kita buat.
use AppUser;
Kod pada baris ke 5 bertujuan untuk menggunakan User model di dalam fail ini.
/** * @var User */ public $user;
Kemudian, kita perlukan satu public property yang akan memegang User object.
/** * Create a new event instance. * * @param User $user */ public function __construct(User $user) { $this->user = $user; }
Seterusnya kita akan menerima User object melalui constructor. Cara ini dipanggil type-hinting.
Langkah 2
Langkah seterusnya, kita akan tambahkan kod untuk menyimpan tarikh dan masa pengguna log masuk di dalam table users
.
Gantikan kod pada fail app/Hendlers/Events/RecordUserLoggedIn.php
dengan kod di bawah.
<?php namespace AppHandlersEvents; use AppEventsUserLoggedIn; use CarbonCarbon; use IlluminateQueueInteractsWithQueue; use IlluminateContractsQueueShouldBeQueued; class RecordUserLoggedIn { /** * Create the event handler. */ public function __construct() { // } /** * Handle the event. * * @param UserLoggedIn $event * @return void */ public function handle(UserLoggedIn $event) { $event->user->update([ 'last_logged_in' => Carbon::now() ]); } }
Perubahan
use CarbonCarbon;
Pertama sekali, kita memerlukan rujukan kepada pakej Carbon yang digunakan untuk memanipulasi tarikh dan masa dengan lebih baik.
$event->user->update([ 'last_logged_in' => Carbon::now() ]);
Kemudian, kita akan gunakan method update()
pada Eloquent untuk merekodkan tarikh dan masa pengguna log masuk.
Langkah 3
Seterusnya, kita perlu memberitahu Laravel semua handler untuk event yang kita hasilkan. Buka fail app/Providers/EventServiceProvider.php
dan tambahkan kod seperti di bawah ini:
protected $listen = [ 'event.name' => [ 'EventListener', ], 'AppEventsUserLoggedIn' => [ '[email protected]', ], ];
Perubahan
'AppEventsUserLoggedIn' => [ '[email protected]', ],
Kod di atas boleh diterjemahkan seperti berikut:
Jika ada mana-mana bahagian/fungsi/method yang trigger event AppEventsUserLoggedIn
, Laravel, silalah execute [email protected]
tanpa segan silu.
Langkah 4
Tambahkan reference berikut:
<?php namespace AppHttpControllersAuth; use AppEventsUserLoggedIn; use AppHttpControllersController; use IlluminateContractsAuthGuard; use IlluminateContractsAuthRegistrar; use IlluminateHttpRequest; use IlluminateSupportFacadesAuth; use IlluminateSupportFacadesEvent; use IlluminateFoundationAuthAuthenticatesAndRegistersUsers;
Sekarang adalah masanya untuk kita trigger event ini. Pada app/Http/Controllers/Auth/AuthController.php
, kita tambahkan fungsi ini:
/** * Handle a login request to the application. * * @param IlluminateHttpRequest $request * @return IlluminateHttpResponse */ public function postLogin(Request $request) { $this->validate($request, [ 'email' => 'required|email', 'password' => 'required', ]); $credentials = $request->only('email', 'password'); if ($this->auth->attempt($credentials, $request->has('remember'))) { Event::fire(new UserLoggedIn(Auth::user())); return redirect()->intended($this->redirectPath()); } return redirect($this->loginPath()) ->withInput($request->only('email', 'remember')) ->withErrors([ 'email' => $this->getFailedLoginMesssage(), ]); }
Lihat pada baris ke 17, kod tersebut yang akan trigger event yang kita hasilkan tadi. Kita panggil Event::fire()
yang mana ia menerima satu instance baru bagi event UserLoggedIn
kita, dan kita hantarkan object Auth::user()
kepada event tadi.
Nota:
Kod di atas sebenarnya disalin tanpa segan silu daripada traits yang terdapat di /vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesAndRegistersUsers.php
. Pada pemasangan Laravel 5 yang baru, fungsi log masuk telahpun disediakan, tetapi disebabkan kita ingin execute event kita semasa user log masuk, kita override method yang berada di dalam traits AuthenticatesAndRegistersUsers
pada AuthController kita.
Ada cara yang lebih baik? Share pada comment ye.
Kesimpulan
Memenatkan! Banyak kerja yang perlu dilakukan untuk menghasilkan event pada Laravel 5 berbanding pada Laravel 4.2. Walaupun ramai yang claim ianya lebih bagus, terpulanglah pada anda untuk menilainya.
Selamat mencuba.
Nota Kaki
Tuan Zulfa Juniadi highlight event ‘auth.login’ automatically triggered masa log masuk, jadi sebenarnya boleh guna event tu daripada create yang baru. Good point!