นอกจากในส่วนของโมเดล (Model) ของ Laravel ซึ่งเรียกว่า Eloquent Model นั้นมีการใช้งาน Active Record Pattern แล้วยังมีการใช้งาน Observer Pattern ด้วย โดยจะมีการยิง Event ออกมา แล้วโปรแกรมเมอร์สามารถเขียนตัวดักจับเหตุการณ์เพื่อการทำงานเพิ่มเติมได้ โดยในบทความนี้เราจะทำความรู้จักกับ Model Observers ที่ใช้งานใน Laravel กัน
หากคุณเคยใช้ Laravel สำหรับโครงการขนาดกลางถึงขนาดใหญ่ คุณอาจเคยพบสถานการณ์ที่คุณต้องการดำเนินการบางอย่างในขณะที่โมเดล Eloquent ของคุณกำลังประมวลผล Laravel ให้วิธีการที่สะดวกในการเพิ่มการดำเนินการของคุณเองในขณะที่โมเดลกำลังดำเนินการ หรือเสร็จสิ้นบางการดำเนินการ ตัวอย่างเช่น หากคุณมีโมเดล Post และคุณต้องการตั้งค่า Slug ของโพสต์โดยอัตโนมัติเมื่อสร้างโพสต์ คุณสามารถดักเหตุการณ์ saving และตั้งค่า Slug ของโพสต์ดังนี้
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class Post extends Model
{
protected $table = 'posts';
protected $fillable = ['title', 'slug', 'content'];
protected static function boot()
{
parent::boot();
static::saving(function ($model) {
$model->slug = Str::slug($model->title);
});
}
}
โดย Laravel Eloquent มีการสร้างเหตุการณ์สำหรับการเปลี่ยนแปลงของ Model ดังนี้ครับ
ลองจินตนาการว่า แอปพลิเคชันของคุณกำลังโตขึ้น และคุณต้องดักเหตุการณ์ส่วนใหญ่ในโมเดลของคุณ (ส่วนของ boot()) การดักเหตุการณ์ภายในโมเดลจะทำให้โมเดลของคุณใหญ่และยุ่งเหยิงอย่างแน่นอน การใช้ model observers คุณสามารถรวบรวมเหตุการณ์ทั้งหมดของคุณไว้ในคลาสเดียว (ไฟล์เดียว) ได้ ชื่อ method ทั้งหมดในคลาส observer จะสะท้อนถึงเหตุการณ์ที่คุณกำลังดักฟัง คุณสามารถสร้างคลาส observer โมเดลโดยใช้คำสั่ง artisan ดังนี้
php artisan make:oberserver PostObserver --model=Post
คำสั่งด้านบนจะสร้างคลาสใหม่ซึ่งอยู่ภายในโฟลเดอร์ app/Observers โดยคลาส observer ที่สร้างใหม่ของคุณจะดูเป็นดังตัวอย่างด้านล่างนี้
namespace App\Observers;
use App\Models\Post;
class PostObserver
{
/**
* Handle the post "created" event.
*
* @param \App\Post $post
* @return void
*/
public function created(Post $post)
{
//
}
/**
* Handle the post "updated" event.
*
* @param \App\Post $post
* @return void
*/
public function updated(Post $post)
{
//
}
/**
* Handle the post "deleted" event.
*
* @param \App\Post $post
* @return void
*/
public function deleted(Post $post)
{
//
}
/**
* Handle the post "restored" event.
*
* @param \App\Post $post
* @return void
*/
public function restored(Post $post)
{
//
}
/**
* Handle the post "force deleted" event.
*
* @param \App\Post $post
* @return void
*/
public function forceDeleted(Post $post)
{
//
}
}
หลังจากนี้เราต้องลงทะเบียนเพื่อแจ้งให้ Laravel ทราบโดยวิธีแรกจะทำการเพิ่มเข้าไปใน method ชื่อ boot() ของ EventServiceProvider
namespace App\Providers;
use App\Models\Post;
use App\Observers\PostObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Post::observe(PostObserver::class);
}
}
หรือใส่ไว้ใน protected property ชือ $observers ของ EventServiceProvider แบบนี้ก็ได้ครับ
/**
* The model observers for your application.
*
* @var array
*/
protected $observers = [
Post::class => [PostObserver::class],
];
สำหรับการใช้งานในรายละเอียด ต้องไปศึกษาในส่วนของ Model State เพิ่มเติมนะครับ จึงจะได้ประโยชน์สูงสุด จำพวก isDirty() เพื่อใช้ตรวจสอบว่าข้อมูลมีการแก้ไขหรือไม่ ถ้ามีท่านใดสนใจก็แจ้งไว้ได้นะครับ
สิ่งต้องระวังอย่างยิ่ง คือการเรียกใช้คำสั่งของ Model ที่อาจจะทำให้เกิดการวน Loop ที่ไม่รู้จบ เช่นในกรณีของเหตุการณ์ saving และ saved คุณไม่ควรเรียก save() บนตัว Model ที่เป็นส่วนหนึ่งของเหตุการณ์ นี่เป็นสิ่งที่ควรหลีกเลี่ยง หากจำเป็นคุณสามารถใช้ saveQuietly() เพื่อไม่ให้ตัว Model สร้างเหตุการณ์ Saved ขึ้นมาใหม่ นอกจากนี้อาจใช้ withoutEvents ดังตัวอย่างข้างล่าง
use App\Models\User;
$user = User::withoutEvents(function () {
User::findOrFail(1)->delete();
return User::find(2);
});
Eloquent Model เป็นเครื่องมือที่มีประสิทธิภาพมาก อย่างไรก็ตามการใช้งานก็จำเป็นต้องอ่านคู่มือ ศึกษาการใช้งานที่ถูกต้อง ซึ่งจะมีประโยชน์ในแง่ของการ Upgrade ตัว Laravel เวอร์ชันใหม่ๆ การเขียน Code ที่อ่านง่าย การเขียนโปรแกรมแนะนำให้เรียนทีละนิด แล้วลงมือทำ เป็นรอบๆ ไป ไม่แนะนำให้เรียนอย่างเดียวแล้วไม่ลงมือทำนะครับ มันลืม
Happy Coding!!