การใช้งาน Laravel Model Observers

Founder, MyCoding.Academy
วิศวกรไฟฟ้าและโทรคมนาที่หลงไหลการเขียนโปรแกรม เลยได้ทำงานประจำช่วงหนึ่งทางด้านการพัฒนาซอฟต์แวร์ ปัจจุบันก็ยังทำงานเป็นฟรีแลนซ์ทางด้านการเขียนโปรแกรมอยู่นะครับ

นอกจากในส่วนของโมเดล (Model) ของ Laravel ซึ่งเรียกว่า Eloquent Model นั้นมีการใช้งาน Active Record Pattern แล้วยังมีการใช้งาน Observer Pattern ด้วย โดยจะมีการยิง Event ออกมา แล้วโปรแกรมเมอร์สามารถเขียนตัวดักจับเหตุการณ์เพื่อการทำงานเพิ่มเติมได้ โดยในบทความนี้เราจะทำความรู้จักกับ Model Observers ที่ใช้งานใน Laravel กัน

Model Events

หากคุณเคยใช้ 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 ดังนี้ครับ

  • retrieved : หลังจากข้อมูลถูกอ่านมาจากฐานข้อมูล
  • creating : ก่อนที่ข้อมูลใหม่จะถูกสร้างขึ้นในฐานข้อมูล หรือก่อนข้อมูลใหม่จะถูกบันทึกลงในฐานข้อมูล
  • created : หลังจากข้อมูลใหม่ถูกบันทึกลงในฐานข้อมูลแล้ว
  • updating : ก่อนที่ข้อมูที่ถูกแก้ไขจะถูกบันทึก
  • updated : หลังจากข้อมูลที่ถูกแก้ไขถ.
  • saving : ก่อนที่ข้อมูลจะถูกบันทึก (ทั้งข้อมูลใหม่ หรือข้อมูลที่แก้ไข)
  • saved : หลังจากข้อมูลถูกบันทึก (ทั้งข้อมูลใหม่ หรือข้อมูลที่แก้ไข)
  • deleting : ก่อนที่ข้อมูจะถูกลบ หรือ ลบแบบ soft-delete
  • deleted : หลังจากข้อมูลถูกลบ หรือ ลบแบบ  soft-delete
  • restoring : ก่อนที่ข้อมูลจะถูกเรียกคืนจากการลบแบบ soft-delete
  • restored : หลังจากที่ข้อมูลจะถูกเรียกคืนจากการลบแบบ soft-delete

Model Observers

ลองจินตนาการว่า แอปพลิเคชันของคุณกำลังโตขึ้น และคุณต้องดักเหตุการณ์ส่วนใหญ่ในโมเดลของคุณ (ส่วนของ 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)
    {
        //
    }
}

ลงทะเบียน Observers

หลังจากนี้เราต้องลงทะเบียนเพื่อแจ้งให้ 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!!