مناسبت ها
- معرفی
- ثبت رویدادها و شنوندگان
- تعریف رویدادها
- تعریف شنوندگان
- شنوندگان رویداد در صف
- اعزام رویدادها
- مشترکین رویداد
معرفی
رویدادهای لاراول یک پیادهسازی الگوی مشاهدهگر ساده را ارائه میکنند، که
به شما امکان میدهد مشترک شوید و به رویدادهای مختلفی که در برنامه شما رخ میدهد گوش دهید. کلاسهای رویداد
معمولاً در
app/Events
دایرکتوری ذخیره میشوند، در حالی که شنوندگان آنها در دایرکتوری ذخیره
میشوند
app/Listeners
. اگر این دایرکتوری ها را در برنامه خود نمی بینید، نگران نباشید، زیرا
هنگام ایجاد رویدادها و شنوندگان با استفاده از دستورات کنسول Artisan، برای شما ایجاد می شوند.
رویدادها راهی عالی برای جدا کردن جنبههای مختلف برنامه شما هستند، زیرا یک
رویداد میتواند چندین شنونده داشته باشد که به یکدیگر وابسته نیستند. به عنوان مثال، ممکن است بخواهید هر بار
که سفارش ارسال می شود، یک اعلان Slack برای کاربر خود ارسال کنید. به جای اینکه کد پردازش سفارش خود را به کد
اعلان Slack متصل کنید، می توانید
App\Events\OrderShipped
رویدادی را مطرح کنید که شنونده می تواند آن را دریافت کرده و از آن برای
ارسال اعلان Slack استفاده کند.
ثبت رویدادها و شنوندگان
همراه
App\Providers\EventServiceProvider
با برنامه لاراول شما مکانی مناسب برای ثبت نام تمام شنوندگان رویداد برنامه
شما فراهم می کند. این
listen
ویژگی شامل آرایه ای از همه رویدادها (کلیدها) و شنوندگان آنها (مقادیر)
است. می توانید هر تعداد رویداد که برنامه شما نیاز دارد به این آرایه اضافه کنید. به عنوان مثال، بیایید یک
OrderShipped
رویداد اضافه کنیم:
use App\Events\OrderShipped;use App\Listeners\SendShipmentNotification; /** * The event listener mappings for the application. * * @var array */protected $listen = [ OrderShipped::class => [ SendShipmentNotification::class, ],];
این
event:list
دستور ممکن است برای نمایش لیستی از تمام رویدادها و شنوندگان ثبت شده توسط برنامه شما استفاده شود.
ایجاد رویدادها و شنوندگان
البته ایجاد دستی فایل ها برای هر رویداد و شنونده دست و پا گیر است. در
عوض، شنوندگان و رویدادها را به خود اضافه کنید
EventServiceProvider
و از
event:generate
دستور Artisan استفاده کنید. این دستور هر رویداد یا شنونده ای را که در
لیست شما
EventServiceProvider
وجود ندارد ایجاد می کند:
php artisan event:generate
از طرف دیگر، می توانید از دستورات
make:event
و
make:listener
Artisan برای ایجاد رویدادها و شنوندگان فردی استفاده کنید:
php artisan make:event PodcastProcessed php artisan make:listener SendPodcastNotification --event=PodcastProcessed
ثبت دستی رویدادها
به طور معمول، رویدادها باید از طریق آرایه ثبت شوند
EventServiceProvider
$listen
. با این حال، شما همچنین می توانید شنوندگان رویداد مبتنی بر کلاس یا بسته
شدن را به صورت دستی در
boot
روش خود ثبت کنید
EventServiceProvider
:
use App\Events\PodcastProcessed;use App\Listeners\SendPodcastNotification;use Illuminate\Support\Facades\Event; /** * Register any other events for your application. * * @return void */public function boot(){ Event::listen( PodcastProcessed::class, [SendPodcastNotification::class, 'handle'] ); Event::listen(function (PodcastProcessed $event) { // });}
شنوندگان رویداد ناشناس در صف
هنگام ثبت دستی شنوندگان رویداد مبتنی بر بسته شدن، می توانید بسته شدن
شنونده را در
Illuminate\Events\queueable
تابع بپیچید تا به لاراول دستور دهید شنونده را با استفاده از
صف
اجرا کند :
use App\Events\PodcastProcessed;use function Illuminate\Events\queueable;use Illuminate\Support\Facades\Event; /** * Register any other events for your application. * * @return void */public function boot(){ Event::listen(queueable(function (PodcastProcessed $event) { // }));}
مانند کارهای در صف، می توانید از متدهای
onConnection
،
onQueue
و
delay
برای سفارشی کردن اجرای شنونده در صف استفاده کنید:
Event::listen(queueable(function (PodcastProcessed $event) { //})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));
catch
اگر میخواهید شکستهای شنونده در صف ناشناس را مدیریت کنید، ممکن است در
حین تعریف شنونده، روش
را ببندید
queueable
. این بسته، نمونه رویداد و
Throwable
نمونه ای را که باعث شکست شنونده شده است، دریافت می کند:
use App\Events\PodcastProcessed;use function Illuminate\Events\queueable;use Illuminate\Support\Facades\Event;use Throwable; Event::listen(queueable(function (PodcastProcessed $event) { //})->catch(function (PodcastProcessed $event, Throwable $e) { // The queued listener failed...}));
شنوندگان رویداد Wildcard
حتی ممکن است شنوندگان را با استفاده از
*
پارامتر به عنوان علامت عام ثبت کنید، که به شما امکان می دهد چندین رویداد
را در یک شنونده مشاهده کنید. شنوندگان Wildcard نام رویداد را به عنوان اولین آرگومان و کل آرایه داده رویداد
را به عنوان آرگومان دوم دریافت می کنند:
Event::listen('event.*', function ($eventName, array $data) { //});
کشف رویداد
به جای ثبت رویدادها و شنوندگان به صورت دستی در
$listen
آرایه
EventServiceProvider
، می توانید کشف خودکار رویداد را فعال کنید. هنگامی که کشف رویداد فعال
است، لاراول به طور خودکار رویدادها و شنوندگان شما را با اسکن دایرکتوری برنامه شما پیدا و ثبت می کند
Listeners
. بعلاوه، هر رویدادی که به صراحت تعریف شده باشد،
EventServiceProvider
همچنان ثبت خواهد شد.
لاراول شنوندگان رویداد را با اسکن کلاس های شنونده با استفاده از خدمات
بازتابی PHP پیدا می کند. وقتی لاراول هر متد کلاس شنونده ای را پیدا می کند که با
handle
یا شروع می شود
__invoke
، لاراول آن متدها را به عنوان شنونده رویداد برای رویدادی که به صورت تایپ
در امضای متد ذکر شده است، ثبت می کند:
use App\Events\PodcastProcessed; class SendPodcastNotification{ /** * Handle the given event. * * @param \App\Events\PodcastProcessed $event * @return void */ public function handle(PodcastProcessed $event) { // }}
کشف رویداد به طور پیشفرض غیرفعال است، اما میتوانید با نادیده گرفتن
shouldDiscoverEvents
روش برنامه خود، آن را فعال کنید
EventServiceProvider
:
/** * Determine if events and listeners should be automatically discovered. * * @return bool */public function shouldDiscoverEvents(){ return true;}
به طور پیش فرض، همه شنوندگان در فهرست برنامه شما
app/Listeners
اسکن می شوند. اگر میخواهید دایرکتوریهای دیگری را برای اسکن تعریف کنید،
میتوانید این
discoverEventsWithin
روش را در خود لغو کنید
EventServiceProvider
:
/** * Get the listener directories that should be used to discover events. * * @return array */protected function discoverEventsWithin(){ return [ $this->app->path('Listeners'), ];}
کشف رویداد در تولید
در تولید، این فریم ورک کارآمد نیست که همه شنوندگان شما را در هر درخواست
اسکن کند. بنابراین، در طول فرآیند استقرار خود، باید
event:cache
دستور Artisan را اجرا کنید تا مانیفست تمام رویدادها و شنوندگان برنامه خود
را در حافظه پنهان ذخیره کنید. این مانیفست توسط چارچوب برای سرعت بخشیدن به روند ثبت رویداد استفاده می شود.
این
event:clear
دستور ممکن است برای از بین بردن حافظه پنهان استفاده شود.
تعریف رویدادها
یک کلاس رویداد اساساً یک محفظه داده است که اطلاعات مربوط به رویداد را در
خود نگه می دارد. به عنوان مثال، فرض کنید یک
App\Events\OrderShipped
رویداد یک
شی
ORM Eloquent دریافت می کند:
<?php namespace App\Events; use App\Models\Order;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Foundation\Events\Dispatchable;use Illuminate\Queue\SerializesModels; class OrderShipped{ use Dispatchable, InteractsWithSockets, SerializesModels; /** * The order instance. * * @var \App\Models\Order */ public $order; /** * Create a new event instance. * * @param \App\Models\Order $order * @return void */ public function __construct(Order $order) { $this->order = $order; }}
همانطور که می بینید، این کلاس رویداد هیچ منطقی ندارد. این یک ظرف برای
App\Models\Order
نمونه ای است که خریداری شده است. در صورتی که
شی
SerializesModels
رویداد با استفاده از
serialize
تابع PHP، مانند زمانی که
از شنوندگان در صف
استفاده میشود، سریالسازی شود، ویژگی مورد استفاده رویداد، هر مدل
Eloquent را بهخوبی سریالسازی میکند .
تعریف شنوندگان
در مرحله بعد، بیایید نگاهی به شنونده رویداد نمونه خود بیاندازیم. شنوندگان
رویداد نمونه های رویداد را در
handle
روش خود دریافت می کنند. دستورات
event:generate
و
make:listener
Artisan به طور خودکار کلاس رویداد مناسب را وارد کرده و رویداد را در
handle
متد تایپ می کند. در
handle
روش، میتوانید هر اقدامی را که برای پاسخ دادن به رویداد لازم است انجام
دهید:
<?php namespace App\Listeners; use App\Events\OrderShipped; class SendShipmentNotification{ /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param \App\Events\OrderShipped $event * @return void */ public function handle(OrderShipped $event) { // Access the order using $event->order... }}
شنوندگان رویداد شما همچنین ممکن است هر گونه وابستگی را که به سازنده خود نیاز دارند تایپ کنند. همه شنوندگان رویداد از طریق ظرف سرویس لاراول حل می شوند ، بنابراین وابستگی ها به طور خودکار تزریق می شوند.
توقف انتشار یک رویداد
گاهی اوقات، ممکن است بخواهید انتشار یک رویداد را برای شنوندگان دیگر متوقف
کنید. شما می توانید این کار را با بازگشت
false
از روش شنونده خود انجام دهید
handle
.
شنوندگان رویداد در صف
اگر شنونده شما قرار است کارهای کندی مانند ارسال ایمیل یا درخواست HTTP انجام دهد، قرار دادن شنوندگان در صف می تواند مفید باشد. قبل از استفاده از شنوندگان در صف، مطمئن شوید که صف خود را پیکربندی کرده و یک queue worker در سرور یا محیط توسعه محلی خود راه اندازی کنید.
برای تعیین اینکه شنونده باید در صف قرار گیرد،
ShouldQueue
رابط را به کلاس listener اضافه کنید. شنوندگان تولید شده توسط دستورات
event:generate
و
make:listener
Artisan قبلاً این رابط را به فضای نام فعلی وارد کرده اند، بنابراین می
توانید بلافاصله از آن استفاده کنید:
<?php namespace App\Listeners; use App\Events\OrderShipped;use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue{ //}
خودشه! اکنون، هنگامی که رویدادی که توسط این شنونده مدیریت می شود ارسال می شود، شنونده به طور خودکار توسط توزیع کننده رویداد با استفاده از سیستم صف لاراول در صف قرار می گیرد . اگر هنگام اجرای شنونده توسط صف، هیچ استثنایی وجود نداشته باشد، کار در صف به طور خودکار پس از پایان پردازش حذف می شود.
سفارشی کردن اتصال صف و نام صف
اگر میخواهید اتصال صف، نام صف، یا زمان تأخیر صف شنونده رویداد را سفارشی
کنید، میتوانید
$connection
,
$queue
یا
$delay
ویژگیها را در کلاس شنونده خود تعریف کنید:
<?php namespace App\Listeners; use App\Events\OrderShipped;use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue{ /** * The name of the connection the job should be sent to. * * @var string|null */ public $connection = 'sqs'; /** * The name of the queue the job should be sent to. * * @var string|null */ public $queue = 'listeners'; /** * The time (seconds) before the job should be processed. * * @var int */ public $delay = 60;}
اگر می خواهید اتصال صف شنونده یا نام صف را در زمان اجرا تعریف کنید، می
توانید
viaConnection
یا
viaQueue
متدهایی را در شنونده تعریف کنید:
/** * Get the name of the listener's queue connection. * * @return string */public function viaConnection(){ return 'sqs';} /** * Get the name of the listener's queue. * * @return string */public function viaQueue(){ return 'listeners';}
شنوندگان در صف مشروط
گاهی اوقات، ممکن است لازم باشد تعیین کنید که آیا شنونده باید بر اساس برخی
از داده هایی که فقط در زمان اجرا در دسترس هستند در صف قرار گیرد یا خیر. برای انجام این کار،
shouldQueue
ممکن است روشی به شنونده اضافه شود تا مشخص شود آیا شنونده باید در صف قرار
گیرد یا خیر. اگر
shouldQueue
متد برگردد
false
، شنونده اجرا نخواهد شد:
<?php namespace App\Listeners; use App\Events\OrderCreated;use Illuminate\Contracts\Queue\ShouldQueue; class RewardGiftCard implements ShouldQueue{ /** * Reward a gift card to the customer. * * @param \App\Events\OrderCreated $event * @return void */ public function handle(OrderCreated $event) { // } /** * Determine whether the listener should be queued. * * @param \App\Events\OrderCreated $event * @return bool */ public function shouldQueue(OrderCreated $event) { return $event->order->subtotal >= 5000; }}
تعامل دستی با صف
delete
اگر نیاز دارید که به صورت دستی به کارها و روشهای
صف زیربنایی شنونده دسترسی داشته باشید
release
، ممکن است این کار را با استفاده از ویژگی انجام دهید
Illuminate\Queue\InteractsWithQueue
. این ویژگی به طور پیشفرض در شنوندگان تولید شده وارد میشود و دسترسی به
این روشها را فراهم میکند:
<?php namespace App\Listeners; use App\Events\OrderShipped;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue{ use InteractsWithQueue; /** * Handle the event. * * @param \App\Events\OrderShipped $event * @return void */ public function handle(OrderShipped $event) { if (true) { $this->release(30); } }}
شنوندگان رویداد در صف و معاملات پایگاه داده
هنگامی که شنوندگان صف در داخل تراکنش های پایگاه داده ارسال می شوند، ممکن است قبل از انجام تراکنش پایگاه داده توسط صف پردازش شوند. هنگامی که این اتفاق می افتد، هر به روز رسانی که در طول تراکنش پایگاه داده در مدل ها یا رکوردهای پایگاه داده انجام داده اید ممکن است هنوز در پایگاه داده منعکس نشود. علاوه بر این، هر مدل یا رکورد پایگاه داده ایجاد شده در تراکنش ممکن است در پایگاه داده وجود نداشته باشد. اگر شنونده شما به این مدل ها وابسته است، هنگام پردازش کاری که شنونده در صف را ارسال می کند، خطاهای غیرمنتظره ای رخ می دهد.
اگر گزینه پیکربندی اتصال صف شما
after_commit
روی تنظیم شده باشد ، همچنان ممکن است نشان دهید که یک شنونده در صف خاص
باید پس از انجام تمام تراکنش های پایگاه داده باز با تعریف یک
ویژگی در کلاس listener
false
ارسال شود :
$afterCommit
<?php namespace App\Listeners; use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue{ use InteractsWithQueue; public $afterCommit = true;}
برای کسب اطلاعات بیشتر در مورد کار در مورد این مسائل، لطفاً اسناد مربوط به مشاغل در صف و تراکنش های پایگاه داده را مرور کنید .
رسیدگی به مشاغل ناموفق
گاهی اوقات ممکن است شنوندگان رویداد در صف شما شکست بخورند. اگر شنونده در
صف از حداکثر تعداد تلاش های تعریف شده توسط کارگر صف شما بیشتر شود، متد
failed
در شنونده شما فراخوانی می شود. متد
failed
نمونه رویداد و مواردی
Throwable
که باعث شکست شده است را دریافت می کند:
<?php namespace App\Listeners; use App\Events\OrderShipped;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue{ use InteractsWithQueue; /** * Handle the event. * * @param \App\Events\OrderShipped $event * @return void */ public function handle(OrderShipped $event) { // } /** * Handle a job failure. * * @param \App\Events\OrderShipped $event * @param \Throwable $exception * @return void */ public function failed(OrderShipped $event, $exception) { // }}
تعیین حداکثر تلاش شنونده در صف
اگر یکی از شنوندگان در صف شما با خطا مواجه شد، احتمالاً نمیخواهید که به طور نامحدود به تلاش مجدد ادامه دهد. بنابراین، لاراول راه های مختلفی را برای تعیین چند بار یا مدت زمان تلاش برای شنونده ارائه می دهد.
شما می توانید یک
$tries
ویژگی را در کلاس listener خود تعریف کنید تا مشخص کنید چند بار ممکن است
شنونده قبل از اینکه شکست خورده در نظر گرفته شود تلاش شود:
<?php namespace App\Listeners; use App\Events\OrderShipped;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\InteractsWithQueue; class SendShipmentNotification implements ShouldQueue{ use InteractsWithQueue; /** * The number of times the queued listener may be attempted. * * @var int */ public $tries = 5;}
به عنوان جایگزینی برای تعریف اینکه چند بار ممکن است یک شنونده قبل از شکست
آن تلاش شود، ممکن است زمانی را تعریف کنید که در آن شنونده دیگر نباید تلاش کند. این به شنونده اجازه می دهد تا
هر تعداد بار در یک بازه زمانی معین تلاش کند. برای تعیین زمانی که در آن شنونده دیگر نباید تلاش کرد، یک
retryUntil
متد به کلاس شنونده خود اضافه کنید. این متد باید یک
DateTime
نمونه
برگرداند :
/** * Determine the time at which the listener should timeout. * * @return \DateTime */public function retryUntil(){ return now()->addMinutes(5);}
اعزام رویدادها
برای ارسال یک رویداد، می توانید
dispatch
متد استاتیک را در رویداد فراخوانی کنید. این روش در رویداد توسط
Illuminate\Foundation\Events\Dispatchable
صفت در دسترس قرار می گیرد. هر آرگومان ارسال شده به
dispatch
متد به سازنده رویداد ارسال می شود:
<?php namespace App\Http\Controllers; use App\Events\OrderShipped;use App\Http\Controllers\Controller;use App\Models\Order;use Illuminate\Http\Request; class OrderShipmentController extends Controller{ /** * Ship the given order. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $order = Order::findOrFail($request->order_id); // Order shipment logic... OrderShipped::dispatch($order); }}
اگر میخواهید رویدادی را به صورت مشروط ارسال کنید، میتوانید از روشهای
dispatchIf
و استفاده کنید
dispatchUnless
:
OrderShipped::dispatchIf($condition, $order); OrderShipped::dispatchUnless($condition, $order);
هنگام آزمایش، میتوان گفت که برخی رویدادها بدون تحریک شنوندگان ارسال شدهاند. کمککنندههای تست داخلی لاراول، آن را بسیار جذاب کرده است.
مشترکین رویداد
نوشتن مشترکین رویداد
مشترکین رویداد کلاس هایی هستند که ممکن است در چندین رویداد از درون خود
کلاس مشترک مشترک شوند و به شما امکان می دهند چندین کنترل کننده رویداد را در یک کلاس واحد تعریف کنید. مشترکین
باید
subscribe
روشی را تعریف کنند که به یک نمونه توزیع کننده رویداد ارسال می شود. برای
ثبت شنوندگان رویداد
می توانید
listen
متد موجود در توزیع کننده داده شده را فراخوانی کنید:
<?php namespace App\Listeners; use Illuminate\Auth\Events\Login;use Illuminate\Auth\Events\Logout; class UserEventSubscriber{ /** * Handle user login events. */ public function handleUserLogin($event) {} /** * Handle user logout events. */ public function handleUserLogout($event) {} /** * Register the listeners for the subscriber. * * @param \Illuminate\Events\Dispatcher $events * @return void */ public function subscribe($events) { $events->listen( Login::class, [UserEventSubscriber::class, 'handleUserLogin'] ); $events->listen( Logout::class, [UserEventSubscriber::class, 'handleUserLogout'] ); }}
اگر روشهای شنونده رویداد شما در خود مشترک تعریف شدهاند، ممکن است برای
شما راحتتر باشد که مجموعهای از رویدادها و نامهای روش را از متد مشترک برگردانید
subscribe
. لاراول به طور خودکار نام کلاس مشترک را هنگام ثبت شنوندگان رویداد تعیین
می کند:
<?php namespace App\Listeners; use Illuminate\Auth\Events\Login;use Illuminate\Auth\Events\Logout; class UserEventSubscriber{ /** * Handle user login events. */ public function handleUserLogin($event) {} /** * Handle user logout events. */ public function handleUserLogout($event) {} /** * Register the listeners for the subscriber. * * @param \Illuminate\Events\Dispatcher $events * @return array */ public function subscribe($events) { return [ Login::class => 'handleUserLogin', Logout::class => 'handleUserLogout', ]; }}
ثبت نام مشترکین رویداد
پس از نوشتن مشترک، آماده ثبت آن در دیسپچر رویداد هستید. شما می توانید
مشترکین را با استفاده از
$subscribe
ملک در
EventServiceProvider
. به عنوان مثال، بیایید
UserEventSubscriber
به لیست اضافه کنیم:
<?php namespace App\Providers; use App\Listeners\UserEventSubscriber;use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider{ /** * The event listener mappings for the application. * * @var array */ protected $listen = [ // ]; /** * The subscriber classes to register. * * @var array */ protected $subscribe = [ UserEventSubscriber::class, ];}