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' => [
			'AppHandlersEventsRecordUserLoggedIn@handle',
		],
	];

Perubahan

'AppEventsUserLoggedIn' => [
	'AppHandlersEventsRecordUserLoggedIn@handle',
],

Kod di atas boleh diterjemahkan seperti berikut:

Jika ada mana-mana bahagian/fungsi/method yang trigger event AppEventsUserLoggedIn, Laravel, silalah execute AppHandlersEventsRecordUserLoggedIn@handle 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!