Tutorial Laravel 5.8 — Event dengan Automatic Discovery
Bermain dengan fungsi Event di Laravel, buat MVC menjadi less code!
Halo semua, pada kesempatan kali ini gue mau berbagi insight tentang Laravel Event.
Tutorial ini ditujukan bagi level intermediate, kalau kamu newbie dan baru belajar Laravel, apabila anda bingung dengan isi artikel maka kebingungan ditanggung pemenang.
Mungkin bagi yang make Laravel udah advanced ngga akan asing sama fitur Event. Nah bagi yang baru pake laravel kemarin sore (hihihi) mungkin akan asing sama fitur event. Nah gue kasitau dulu deh apa itu menurut docs-nya Laravel.
Laravel’s events provide a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application. Event classes are typically stored in the
app/Events
directory, while their listeners are stored inapp/Listeners
. Don't worry if you don't see these directories in your application, since they will be created for you as you generate events and listeners using Artisan console commands.
Baca ngga kalimat yang saya tebelin? Yep, intinya adalah Laravel menyediakan fitur semacam trigger kalau ada suatu aksi berjalan. Sama ibaratkan trigger pada database, bedanya ini ngga on update, on delete dkknya xixixi 😆.
Event di Laravel memungkinkan kita mentrigger sebuah event apabila kita telah menjalankan sebuah method di controller. Temen-temen kan tau Laravel itu pattern-nya MVC (Model View Controller). Nah kenapa harus pake event?
Oke saya kasih analoginya. Tapi sebelum saya lanjut jangan lupa agan atau kasitau temen agan yang suka belajar ngoding untuk follow, like, komen en sabskreb Medium saya, yuk kita sama-sama buat Medium ini jadi tempat positif berbagi ilmu secara gretong.
Ngga deng saya bercanda aja, sebenernya saya mau kasitau satu hal dulu kalau fungsi ini hanya berjalan di Laravel versi ≥ 5.8.9, kenapa gitu? Jangan tanya saya, saya mah maba alias mahasiswa baru, tanya aja docs Laravel kenapa gitu.
Lalu apa bedanya gan sama versi sebelumnya? Sebenernya yang bikin beda adalah method event discovery-nya gan.
Pada versi sebelum 5.8.9, semua event masih diregistrasi secara manual. Coba bayangkan kalo agan ada 100 evenr? Gempor dah tuh tangan, ntar bukannya ngoding, eh malah rebahan hahaha, siapa tuh? Jelas saya hehe.
Pada kasus koding kali ini akan membuat hal sederhana. Yaitu setelah menginput produk kita akan menulis Log singkat. Ya sebenernya kalo dalam kasus nyata sih akan lebih panjang, cuma saja kan ini belajar, jadi jangan minta lebih yak 😝
Tapi sebelumnya mungkin agan-agan masih bingung kenapa harus pake event sih? Oke jadi gini, mungkin kalo cuma nulis Log singkat agan akan membuat seperti ini.
Bener ngga? Tapi coba sekarang agan bayangkan kalo agan harus membuat sejumlah algoritma mulai dari mengirimkan notifikasi berupa email, mungkin juga menulis log offline ke file, lalu merubah data di table transaksi, atau membuat log yang diinput kedalam database, atau harus mengubah berbagai banyak data setelah satu produk dimasukkan.
Bisa dibayangkan akan memakan berapa banyak baris code didalamnya? Mungkin satu method store saja bisa ≥ 80 baris kode. Gimana kalo kita normalisasi codenya? Jadi yang agan buat cukup berdasarkan event atau kejadian saja, misalnya event setelah produk dibuat dan setelah user melakukan pendaftaran tentu saja berbeda kan? Inilah gunanya event!
Pada tutorial ini saya menggunakan Laravel 6.0. Kalau kalian menggunakan 5.8 ngga apa, pastiin aja pokoknya versi Laravel kalian ≥ 5.8.9.
Oke sekarang karena udah tau kegunaannya, silahkan buat projek baru aja, atau kalo mau make projek yang udah ada pastiin Laravel versinya ≥ 5.8.9 ya!
Bagi yang menggunakan projek lama dan malas mengikuti dasarnya ya di skip aja dulu sampai saya kasitau untuk lanjut ya.
Sekarang saya sarankan membuat model sederhana bernama Product.
php artisan make:model Product -m
Nah kalo sudah kan akan muncul tuh migration baru, isi saja seperti ini.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('description')->nullable();
$table->integer('stock');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
}
Udah? Jalanin migration dulu.
php artisan migrate
Udah? Oke sekarang kita buat controllernya
php artisan make:controller ProductController --resource
Oke di skip aja dulu isi controllernya, bagi yang tadi menggunakan projek lama silahkan mulai ikuti bagian ini.
Kita akan membuat event-nya terlebih dahulu, event yang dibuat adalah event ketika sebuah produk telah dimasukkan kedalam database.
php artisan make:event ProductWasCreated
Sekarang cek App/Events maka akan ada satu event disana yaitu ProductWasCreated. Isi bagian constructor seperti kode saya dibawah ini.
<?php
namespace App\Events;
use App\Product;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ProductWasCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* @var Product
*/
public $product;
/**
* Create a new event instance.
*
* @param Product $product
*/
public function __construct(Product $product)
{
$this->product = $product;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
Kita akan memasukkan model Product sebagai constructor, jadi setiap event ini dipanggil, kita wajib memasukkan object model Product sebagai constructor.
php artisan make:listener SendToLog
Sekarang kamu cek di App/Listeners bakalan ada SendToLog.php, nah sekarang buat folder didalam Listeners itu dengan nama ProductWasCreated dan pindahkan SendToLog.php kedalam folder tersebut sehingga strukturnya menjadi seperti ini.
Sekarang buka SendToLog.php dan ikuti kode saya dibawah ini:
<?php
namespace App\Listeners\ProductWasCreated;
use App\Events\ProductWasCreated;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
class SendToLog
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param ProductWasCreated $event
* @return void
*/
public function handle(ProductWasCreated $event)
{
$product = $event->product;
Log::info("Product was Created, product name: $product->name");
}
}
Nah sekarang kita udah buat Listenernya, sekarang kita masuk ke App/Providers/EventServiceProvider dan liat kodenya.
Disana kamu akan menemukan satu method, yaitu boot. Boot adalah method yang digunakan untuk mendaftarkan event, sedangkan variable $listen digunakan untuk mapping seperti yang kita lakukan saat ini, bedanya itu manual dan kita otomatis.
Nah sekarang kita baca di Laravel Docs.
Instead of registering events and listeners manually in the
$listen
array of theEventServiceProvider
, you can enable automatic event discovery. When event discovery is enabled, Laravel will automatically find and register your events and listeners by scanning your application'sListeners
directory. In addition, any explicitly defined events listed in theEventServiceProvider
will still be registered.
Kata Laravel: Daripada daftarin event dan listenernya manual pada $listen dan array EventServiceProvider, lu bisa bikin otomatis pencarian event kok. Kalo pencarian event otomatis ini dinyalain, Laravle bakalan otomatis nyariin dan daftarin event dan listener dengan membaca folder Listener. Kalo ada tambahan, event yang didefinisikan secara terpisah di EventServiceProvider bakalan tetep didaftarin kok.
Enak banget ya Laravel Zaman Now? Ngga kaya dulu pas saya nulis 5.4 masih banyak manual xixixixi.
Sekarang tambahin kode ini dipangil bawah EventServiceProvider.
/**
* Determine if events and listeners should be automatically discovered.
*
* @return bool
*/
public function shouldDiscoverEvents()
{
return true;
}
Ntar jadinya gini ya.
Sekarang buat dulu views baru bernama create.php dan ikuti kode dibawah.
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
font-family: 'Nunito', sans-serif;
font-weight: 200;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 13px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
<div class="container">
<div class="row">
<div class="col-sm-6 offset-md-3 mb-3">
<h3 class="text-uppercase">Create Product</h3>
</div>
<div class="col-sm-6 offset-md-3">
<form action="{{ route('product.store') }}" method="post">
@csrf
<div class="form-group">
<label>Name:</label>
<input class="form-control" type="text" name="name" placeholder="Product Name" />
</div>
<div class="form-group">
<label>Description:</label>
<textarea class="form-control" name="description" placeholder="Product Description"></textarea>
</div>
<div class="form-group">
<label>Stock:</label>
<input class="form-control" type="number" name="stock" placeholder="Product Description" />
</div>
<div class="form-group">
<button class="btn btn-primary mt-3" type="submit">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>s
</body>
</html>
Views sudah, berarti sekarang controllernya. Buka ProductController.php dan ikuti code bagian create dan store dibawah ini.
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$product = new Product();
$product->name = $request->name;
$product->description = $request->description;
$product->stock = $request->stock;
$product->save();
//Memanggil Event
event(new ProductWasCreated($product));
return redirect()->back();
}
Jangan lupa import eventnya ya di paling atas.
use App\Events\ProductWasCreated;
Eits belom selesai, tambahin dulu routesnya.
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/create', 'ProductController@create');
Route::post('/store', 'ProductController@store')->name('product.store');
Oke sekarang coba kita jalanin dan hasilnya akan seperti ini.
Gimana udah berhasil belom? High-five kalo berhasil!
Sekarang udah ngga ada alasan lagi codenya terlalu banyak dengan pattern MVC, cukup pake Event dan sesuaikan kode kamu sesuai kebutuhan.
Q: Kalo saya ada berbagai Listener tapi beda file bisa ngga?
A: Tentu saja bisa, cukup buat pada satu folder sesuai event dan otomatis dipanggil semua seperti gambar dibawah, jangan lupa sesuaikan namespacenya ya biar kepanggil hihihi.
Ohiya saya mau promosi juga, kalo mau belajar mobile development dengan Flutter bisa kesini loh kebetulan saya asisten pembina sekaligus editor di Mediumnya!
Oke kalo gitu sekian dari saya, semoga ilmunya bermanfaat~