پیاده سازی نوتیفیکیشن ها در لاراول

میخوام مطلب کوتاهی رو در مورد پیاده سازی نوتیفیکیشن ها در فریم ورک لاراول براتون بنویسم. در بخش اول این مطلب در ابتدا خیلی کلی استفاده از روش های موجود در لارول برای ارسال نوتیفیکیشن رو بررسی میکنیم و در بخش دوم هم ایجاد روشی جدید و کاملا شخصی برای ارسال نوتیفیکیشن رو بررسی میکنیم.

این اولین باره که تصمیم به نوشتن گرفتم، البته این مطلب یه جورایی ترجمه مقاله ای در سایت مدیوم بوده که از اینجا میتونید اون رو مطالعه کنید. این ترجمه خیلی دقیق و درست نیست و بعضی موارد رو حذف کردم یا بعضی جاها سعی کردم یه کم توضیحات رو بیشتر کنم. بدون شک مالکیت اصلی محتوای این مطلب متعلق به نویسنده مقاله اصلی است و شما دوستان میتونید حتی بدون ذکر نام من از محتویات این صفحه به هر شکلی که میخواید استفاده کنید.

این مطلب برای افرادی نوشته شده که سابقه کار کردن با فریم ورک لاراول و زبان برنامه نویسی php رو داشته باشن پس اگه به تازگی با لاراول آشنا شدین هنوز وقتش نشده که سراغ این مطلب بیاین.

سطح فنی مقاله

استفاده از نوتیفیکیشن ها میتونه خیلی بدرد بخور باشه. مواقع زیادی در چرخه حیات یک برنامه هست که نیاز میشه یک یا چند نفر از کاربرها رو از رخداد خاصی مطلع کنید. مثلا ثبت نام کاربر تو وبسایت، ثبت سفارش، افزایش مصرف منابع و … رخدادهاییه که میتونیم از طریق ایمیل یا پیامک مدیر سیستم رو در جریان بزاریم. در مقابل دریافت پیام در سیستم، تکمیل سفارش، ارسال مطلب جدید و… هم رخدادهاییه که میتونیم برای کاربرانمون بفرستیم. در کنار این ها ممکنه حتی مخاطب نوتیفیکیشن ما یک کاربر نباشه، میتونیم یک نوتیفیکیشن برای اپ رانندمون در نرم افزار تاکسی اینترنتی ارسال کنیم و به اپ بفهمونیم که باید اطلاعات مربوط به مسافر جدید رو از سرور pull کنه و برای راننده نمایش بده. مثال های خیلی خیلی زیادی میشه از کاربرد نوتیفیکیشن ها زد که حتما تو ذهن خودتون هم همین الان کلی از اونها نقش بسته.

نوتیفیکیشن ها در لاراول

فریم ورک لاراول به طور پیشفرض روشهای مختلفی رو برای ارسال نوتیفیکیشن در اختیار ما میزاره. انواع این روش ها رو در اصطلاح کانال نام گزاری کردن و این کانال های پیشفرض Email, Database, Broadcast هستن.

البته به جز اینها میتونید به این وبسایت مراجعه کنید تا با بیشتر از ۵۰ کانال ارسال نوتیفیکیشن مخصوص لارول که توسط جامعه توسعه دهندگان ایجاد شده، آشنا بشین.

اول از همه در نظر بگیرید که ما برای ارسال نوتیفیکیشن برای کاربرامون باید این قابلیت رو در اختیار اونها بزاریم و این کار با استفاده از این trait امکان پذیره:

				
					<?php
//App/User.php
//...
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
    use Notifiable
}
				
			

حالا به سادگی و با استفاده از دستور جادویی artisan یک فایل نوتیفیکیشن ایجاد میکنیم:

				
					php artisan make:notification CustomerCreatedNotification
				
			

این دستور یک فایل کلاس php در دایرکتوری App/Notifications ایجاد میکنه که به شکل زیره:

				
					<?php
//App/Notifications/CustomerCreatedNotification.php
namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class CustomerCreatedNotification extends Notification
{
    use Queueable;
    public function __construct(){
        //
    }

    public function via($notifiable)
    {
        return ['mail'];
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('The introduction to the notification.')
                    ->action('Notification Action', url('/'))
                    ->line('Thank you for using our application!');
    }

    public function toArray($notifiable)
    {
        return [ ];
    }
}
				
			

خوب حالا فایل رو باز کنید که باهم بررسیش کنیم:

فایل یک متد via داره که در واقع مشخص میکنه این نوتیفیکیشن قراره از طریق کدوم کانال برای کاربر ارسال بشه. خروجی این تابع آرایه ای از کانال هاست که به طور پیشفرض این آرایه فقط یک عضو داره که اونم ایمیله ولی اگر ما کانال های دیگه ای رو برای ارسال نوتیفیکیشن در نظر داشته باشیم میتونیم جایگزین کنیم یا به آرایه اضافه کنیم. این رو در نظر داشته باشید که هر فایل نوتیفیکیشن با توجه به کانال ارسال باید یک متد برای ارسال نوتیفیکیشن داشته باشه برای مثال همین فایل که قراره از کانال mail استفاده کنه متد toMail داره.

در حال حاضر ما میخوایم یک کانال دیگه به این نوتیفیکیشن اظافه کنیم که در واقع هر بار که این کلاس رو فراخونی میکنیم نوتیفیکیشن از طریق دوتا کانال ارسال بشه. پس متد via به شکر زیر تغییر میکنه:

				
					public function via($notifiable)
{
    return ['mail' , 'broadcast'];
}
				
			

همونطور که گفتم باید یک متد برای ارسال نوتیفیکیشن متناسب با کانال انتخاب شده توی این کلاس وجود داشته باشه مثل همون toMail که مثال زدیم. ولی برای کانال های Broadcast و Database اگر این متدها وجود نداشته باشه، متد toArray فراخونی میشه که به عنوان خروجی یک آرایه برمیگردونه. در اینجا ما برای استاده از کانال Broadcast از این متد استفاده میکنیم به این شکل:

				
					public function toArray()
{
    return [
        'id'=>'identifier key',
        'name'=>'customer name'
    ];
}
				
			

قراره وقتی خواستیم نوتیفیکیشن رو ارسال کنیم این متد فراخونی بشه پس بهتره یه تغییرات کوچیکی تو کدهای این کلاس و البته این متد بدیم:

				
					<?php
//App/Notifications/CustomerCreatedNotification.php
namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class CustomerCreatedNotification extends Notification
{
    use Queueable;
    private $customer;

    public function __construct(Customer $customer)
    {
        $this->customer = $customer;
    }

    public function via($notifiable)
    {
        return ['mail', 'broadcast'];
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->subject('New customer is created')
            ->line('New customer is created at ' . $this->customer->created_at)
            ->action('View customer profile', route('view.customer', ['id' => $this->customer->id]))
            ->line('Thank you for using our application!');
    }

    public function toArray($notifiable)
    {
        return [
            'id' => $this->customer->id,
            'fullName' => $this->customer->first_name . ' ' . $this->customer->last_name,
            'registration_date' => $this->customer->created_at
        ];
    }
}
				
			

خوب از اونجایی که قراره وقتی مشتری جدید ثبت نام کرد این نوتیفیکیشن برای مدیر سیستم ارسال بشه پس یک نسخه از مشتری ثبت نام شده رو به عنوان آرگومان برای این کلاس میفرستیم که بتونم از اطلاعاتش استفاده کنیم. فکر میکنم بقیه چیزها کاملا مشخصه و وقتشه که نوتیفیکیشن رو برای کاربرمون ارسال کنیم. برای ارسال نوتیفیکیشن از این قطعه کد استفاده میکنیم:

				
					//CustomerController.php

public function store(Request $request){
   $customer=new \App\Customer::created(request->all());
   $admin=User::find(1);
    //Method #1   
    $admin->notify(new CustomerCreatedNotification($customer));
    //Method #2
    $admin->notifyNow(new CustomerCreatedNotification($customer));
    //Method #3
    \Illuminate\Support\Facades\Notification::send($user,new CustomerCreatedNotification($customer));
    //Method #4
    \Illuminate\Support\Facades\Notification::sendNow($user,new CustomerCreatedNotification($customer));
}
				
			

حالا تفاوت این روش ها چیه:

در دو روش اول شما از همون trait که به مدل اضافه کردیم استفاده میکنید و بنابراین باید قبل از این، کاربر نوتیف شونده (D:) رو مشخص کنید. تفاوتشون هم در اینه که در اولی ارسال نوتیفیکیشن در صف قرار میگیره و در دومی همونطور که از اسمش مشخصه در همون لحظه ارسال میشه. فقط در جریان باشید که اگر قراره نوتیفیکیشن برای ارسال در صف قرار بگیره حتما باید کلاس نوتیفیکیشنتون اینترفیس ShouldQueue رو پیاده سازی کرده باشه.

یه تفاوت مهم بین این دو روش اینه که در روش اول (متد ۱ و ۲) شما نوتیفیکیشن رو میتونید برای یک مدل یا کاربر ارسال کنید ولی در روش دوم (متد ۳ و۴) میتونید به عنوان اولین آرگومان یک شی از کلاس مورد نظر یا یک آرایه و یا طبق سُنَت لاراول یک کالکشن از مدلها رو ارسال کنید.

خوب بقیه کارها رو میسپاریم به لاراول. وقتی یکی از این متدها رو فراخونی کنید باید یک ایمیل ارسال بشه و تو فایل لاگ هم مقدار خروجی تابع toArray ذخیره بشه.

چه کارهای دیگه ای میشه کرد؟

  • اگر نمیخواید یک کلاس نوتیفیکیشن رو ارسال کنه میتونید تو متد via یک آرایه خالی برگردونید.
  • مدل هایی که از trait مربوط به notifiable استفاده میکنن میتونن متدهای routeNotificationForMail، routeNotificationForDatabase، receivesBroadcastNotificationsOn رو پیاده سازی کنن. این متدهای برای این استفاده میشن که کانال بدونه چطوری میتونه نوتیفیکیشن رو برای کاربر ارسال کنه. به زبان ساده میتونید در نظر بگیرید مثلا برای کانال Email چطوری فیلد ایمیل کاربر رو بدست بیاره. البته وقتی از trait استفاده میکنید خودش ترتیب دوتا متد اول رو میده ولی شما میتونید در صورت نیاز اونها رو دوباره نویسی کنید.
  • کلاس های نوتیفیکیشنی که اینترفیس ShouldQueue رو پیاده سازی کرده باشن مثل job ها میتونن از فیلدهای connection, queue, delay استفاده کنند و البته از متدهای onConnection, onQueue, delay.
  • میتونید یه متد failed توی کلاس نوتیفیکیشنتون پیاده سازی کنید تا اگر به هر دلیلی ارسال نوتیفیکیشن با مشکل مواجه شد یه Exception براتون پرتاب بشه.
  • همچنین مثل job ها از متدهای retryAfter و retryUntil برای سازوکار تلاش های مجددتون استفاده کنید.
  • حتی بعد از این که نوتیفیکیشن رو در صف ارسال گذاشتین میتونید ارسال اون رو متوقف کنید. دقیقا لحظه ارسال یک event به اسم NotificationSending فراخونی میشه. فقط کافیه یک Listener برای اون درنظر بگیرید. این event یک شی از نوع notifiable ، یک شی از نوع notification و اسم کانالی که نوتیفیکیشن میخواد از اون ارسال بشه رو به عنوان آرگومان در یافت میکنه. فقط کافیه برای جلوگیری از ارسال نوتیفیکیشن در این event مقدار false رو برگردونین.

فهرست مطالب