Artikel ini akan meneroka peristiwa model apa dan bagaimana menggunakannya dalam aplikasi Laravel. Kami juga akan meneroka bagaimana untuk menguji peristiwa model dan beberapa isu yang perlu diperhatikan apabila menggunakannya. Akhirnya, kami akan merangkumi beberapa alternatif untuk memodelkan peristiwa yang boleh anda pertimbangkan.
Apakah peristiwa dan pendengar?
#Event
Biasanya, dalam Laravel, peristiwa adalah kelas PHP. Sebagai tambahan kepada peristiwa yang disediakan oleh rangka kerja atau pakej pihak ketiga, mereka biasanya disimpan dalam direktori
.
app/Events
Berikut adalah contoh kelas acara mudah yang mungkin anda mahu jadual apabila pengguna mendaftar ke laman web anda:
Dalam contoh asas di atas, kita mempunyai kelas acara
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
dalam pembangunnya. Kelas acara ini adalah bekas mudah untuk menyimpan contoh pengguna berdaftar. AppEventsUserRegistered
Apabila dihantar, acara itu akan mencetuskan mana -mana pendengar yang mendengarnya. User
Dalam contoh di atas, kami membuat pengguna baru dan kemudian menjadualkan acara
menggunakan contoh pengguna. Dengan mengandaikan pendengar didaftarkan dengan betul, ini akan mencetuskan mana -mana pendengar yang mendengar pada acarause App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
AppEventsUserRegistered
#Listener AppEventsUserRegistered
dan menghantar e -mel selamat datang.
Di Laravel, pendengar biasanya (tetapi tidak selalu) kelas yang terdapat dalam direktori AppEventsUserRegistered
.
Contoh pendengar menghantar e -mel selamat datang kepada pengguna apabila daftar pengguna mungkin kelihatan seperti ini: app/Listeners
seperti yang kita lihat dalam contoh kod di atas, kelas pendengar
mempunyai kaedahdeclare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
. Kaedah ini bertanggungjawab untuk menghantar e -mel selamat datang kepada pengguna. AppListenersSendWelcomeEmail
Untuk lebih banyak arahan yang mendalam mengenai peristiwa dan pendengar, anda mungkin ingin menyemak dokumentasi rasmi: https://www.php.cn/link/d9a8c56824cfbe66f28f85edbbe83e09
Apakah acara model?
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
Senarai berikut menunjukkan peristiwa dan pencetus secara automatik dijadualkan oleh model yang fasih:
Diperolehi - Ambil dari pangkalan data.
dilaksanakan selepas operasi berlaku, dan perubahannya berterusan ke pangkalan data. creating
created
mari kita lihat cara menggunakan peristiwa model ini dalam aplikasi Laravel. ing
ed
Gunakan
dispatchesEvents
pada model anda.
dispatchesEvents
Untuk memberikan lebih banyak konteks, mari kita lihat contoh.
Katakan kami sedang membina aplikasi blog dengan dua model:
dan. Kami akan mengatakan bahawa kedua -dua model menyokong pemadaman lembut. Apabila kita menyimpan
baru, kita ingin mengira masa bacaan artikel berdasarkan panjang kandungan. Apabila kami dengan perlahan memadam penulis, kami mahu penulis dengan perlahan memadam semua artikel.
AppModelsPost
#Set model AppModelsAuthor
AppModelsPost
kita mungkin mempunyai model
Dalam model di atas, kita ada: AppModelsAuthor
dispatchesEvents
ke kelas acara deleted
. Ini bermakna apabila model dipadam, acara AppEventsAuthorDeleted
baru akan dijadualkan. Kami akan membuat kelas acara ini kemudian. AppEventsAuthorDeleted
posts
IlluminateDatabaseEloquentSoftDeletes
kami: AppModelsPost
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
di atas, kita ada: AppModelsPost
dispatchesEvents
. Ini bermakna apabila model dibuat atau dikemas kini, acara saving
baru akan dijadualkan. Kami akan membuat kelas acara ini kemudian. AppEventsPostSaving
AppEventsPostSaving
mentakrifkan hubungan author
Pemadaman lembut diaktifkan pada model dengan menggunakan ciri IlluminateDatabaseEloquentSoftDeletes
kami. AppEventsAuthorDeleted
AppEventsPostSaving
#create class event
AppEventsPostSaving
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
dalam pembangunnya. Kelas acara ini adalah bekas mudah untuk menyimpan contoh artikel yang disimpan. AppEventsPostSaving
AppModelsPost
Begitu juga, kita boleh membuat kelas acara
AppEventsAuthorDeleted
declare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
. AppEventsAuthorDeleted
AppModelsAuthor
Sekarang kita boleh terus membuat pendengar.
#create pendengar
kami akan membuat kelas pendengar
baru:
AppListenersCalculateReadTime
UserRegistered::dispatch($user);
. Ia menerima contoh kelas acara handle
yang mengandungi artikel yang disimpan. AppEventsPostSaving
AppEventsPostSaving
Dalam kaedah
pada model artikel. handle
Oleh kerana pendengar ini akan dipanggil apabila peristiwa model saving
dicetuskan, ini bermakna bahawa atribut read_time_in_seconds
dikira setiap kali artikel itu berterusan ke pangkalan data sebelum membuat atau mengemas kini.
kita juga boleh membuat pendengar yang perlahan memadam semua artikel yang berkaitan apabila lembut memadam penulis.
kita boleh membuat kelas pendengar AppListenersSoftDeleteAuthorRelationships
baru:
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
Dalam pendengar di atas, kaedah handle
menerima contoh kelas acara AppEventsAuthorDeleted
. Kelas acara ini mengandungi penulis yang dipadam. Kemudian, kami menggunakan hubungan posts
untuk memadamkan artikel penulis. delete
Oleh itu, apabila model
AppModelsAuthor
Dengan cara ini, perlu diperhatikan bahawa anda mungkin mahu menggunakan penyelesaian yang lebih kuat dan boleh diguna semula untuk mencapai matlamat ini. Tetapi untuk tujuan artikel ini, kami tetap mudah.
Gunakan penutupan untuk mendengar peristiwa model
Mari kita lihat contoh artikel pemadam lembut apabila kita dengan lembut menghapus pengarang. Kami boleh mengemas kini model
kami untuk mengandungi penutupan yang mendengar untuk peristiwa model: AppModelsAuthor
deleted
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
, jadi kami menggunakan booted
. Begitu juga, jika kita mahu membuat pendengar untuk acara model deleted
, kita boleh menggunakan self::deleted
dan sebagainya. Kaedah created
menerima penutupan yang menerima self::created
yang dipadam. Penutupan ini akan dilaksanakan apabila model dipadamkan, jadi semua artikel pengarang akan dipadam. self::deleted
AppModelsAuthor
Saya sangat suka cara ini untuk menentukan logik pendengar kerana ia dapat melihat dengan segera jika ia mendaftarkan pemerhati ketika membuka kelas model. Oleh itu, sementara logik masih "tersembunyi" dalam fail yang berasingan, kita dapat mengetahui bahawa kita telah mendaftarkan pendengar untuk sekurang -kurangnya satu peristiwa model. Walau bagaimanapun, jika kod dalam penutupan ini menjadi lebih kompleks, ia mungkin bernilai mengekstrak logik ke dalam kelas pendengar yang berasingan.
Trik yang berguna ialah anda juga boleh menggunakan fungsi
untuk membuat penutupan beratur. Ini bermakna bahawa kod pendengar akan ditolak ke dalam barisan untuk berjalan di latar belakang, dan bukannya dalam kitaran hayat permintaan yang sama. Kami boleh mengemas kini pendengar untuk berehat seperti berikut:
IlluminateEventsqueueable
declare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
Cara lain yang boleh anda ambil untuk mendengar acara model adalah menggunakan pemerhati model. Pemerhati model membolehkan anda menentukan semua pendengar untuk model dalam satu kelas.
Biasanya, mereka adalah kelas yang wujud dalam direktori app/Observers
, dan mereka mempunyai kaedah yang sepadan dengan peristiwa model yang ingin anda dengar. Sebagai contoh, jika anda ingin mendengar acara model deleted
, anda akan menentukan kaedah deleted
dalam kelas pemerhati. Jika anda ingin mendengar acara model created
, anda akan menentukan kaedah created
dalam kelas pemerhati, dan sebagainya.
mari kita lihat cara membuat pemerhati model untuk Model AppModelsAuthor
Mendengar Model untuk deleted
peristiwa model:
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
Seperti yang kita lihat dalam kod di atas, kita membuat pemerhati dengan kaedah deleted
. Kaedah ini menerima contoh model AppModelsAuthor
yang dipadam. Kemudian, kami menggunakan hubungan posts
untuk memadamkan artikel penulis. delete
dan created
. Kami boleh mengemas kini pemerhati kami seperti ini: updated
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
, kita perlu mengarahkan Laravel untuk menggunakannya. Untuk melakukan ini, kita boleh menggunakan atribut AppObserversAuthorObserver
. Ini membolehkan kita mengaitkan pemerhati dengan model, sama seperti bagaimana kita mendaftarkan skop pertanyaan global menggunakan atribut #[IlluminateDatabaseEloquentAttributesObservedBy]
(seperti yang ditunjukkan dalam memahami bagaimana menguasai skop pertanyaan di Laravel). Kami boleh mengemas kini model #[ScopedBy]
kami seperti ini untuk menggunakan pemerhati: AppModelsAuthor
declare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
menguji acara model anda
Mari lihat bagaimana untuk menguji peristiwa model yang kami buat dalam contoh di atas.
Kami mula -mula menulis ujian untuk memastikan artikel penulis dipadamkan dengan lembut apabila penulis dipadamkan dengan lembut. Ujian mungkin kelihatan seperti ini:
UserRegistered::dispatch($user);
Ini adalah ujian yang sangat mudah tetapi berkesan yang boleh kita gunakan untuk memastikan logik kami berfungsi seperti yang diharapkan. Kelebihan ujian ini ialah ia harus berfungsi dengan setiap kaedah yang kita bincangkan dalam artikel ini. Oleh itu, jika anda beralih antara mana -mana kaedah yang dibincangkan dalam artikel ini, ujian anda masih perlu lulus.
Begitu juga, kita boleh menulis beberapa ujian untuk memastikan bahawa masa bacaan artikel dikira apabila membuat atau mengemas kini. Ujian mungkin kelihatan seperti ini:
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
kami mempunyai dua ujian di atasnya:
Walaupun peristiwa model sangat mudah, terdapat beberapa isu yang perlu diperhatikan ketika menggunakannya.
peristiwa model dijadualkan dari model fasih sahaja. Ini bermakna jika anda menggunakan fasad IlluminateSupportFacadesDB
untuk berinteraksi dengan data asas model dalam pangkalan data, peristiwa -peristiwa itu tidak akan dijadualkan.
untuk memadamkan pengarang: IlluminateSupportFacadesDB
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
dan deleting
tidak dijadualkan. Jadi jika anda menentukan mana -mana pendengar untuk peristiwa model ini apabila memadam penulis, mereka tidak akan dijalankan. deleted
, saved
, updated
, dan deleting
peristiwa model tidak dijadualkan untuk model yang terjejas. Ini kerana peristiwa dijadualkan dari model itu sendiri. Walau bagaimanapun, apabila kemas kini dan penghapusan batch dikemas kini, model itu sebenarnya tidak diambil dari pangkalan data, jadi peristiwa tidak dijadualkan. deleted
declare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
dipanggil secara langsung pada pembina pertanyaan, peristiwa model delete
dan deleting
tidak dijadualkan untuk penulis itu. deleted
Untuk menerangkan ini, mari kita lihat contoh asas di mana kita mungkin ingin mengelakkan menggunakan peristiwa model. Memperluas contoh aplikasi blog kami yang terdahulu, dengan mengandaikan kami ingin menjalankan perkara berikut semasa membuat catatan baru:
Kirakan masa bacaan artikel.
AppModelsPost
Tetapi sekarang mari kita semak salah satu ujian sebelumnya:
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }
Jika kita menjalankan ujian di atas, ia juga akan mencetuskan ketiga -tiga operasi ini apabila model AppModelsPost
dibuat melalui kilangnya. Sudah tentu, mengira masa bacaan adalah tugas sekunder, jadi tidak penting. Tetapi kami tidak mahu membuat panggilan API atau menghantar pemberitahuan semasa ujian. Ini adalah kesan sampingan yang tidak dijangka. Sekiranya pemaju menulis ujian tidak menyedari kesan sampingan ini, mungkin sukar untuk menjejaki mengapa operasi ini berlaku.
kami juga ingin mengelakkan menulis sebarang logik khusus ujian dalam pendengar, yang menghalang operasi ini daripada berjalan semasa ujian. Ini akan menjadikan kod aplikasi lebih kompleks dan lebih sukar untuk dikekalkan.
Ini adalah salah satu kes di mana anda mungkin ingin mempertimbangkan pendekatan yang lebih jelas dan bukannya bergantung pada peristiwa model automatik.
Salah satu cara boleh mengekstrak kod penciptaan AppModelsPost
anda ke dalam kelas perkhidmatan atau tindakan. Sebagai contoh, kelas perkhidmatan mudah mungkin kelihatan seperti ini:
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
Di kelas di atas, kami secara manual memanggil kod yang mengira masa membaca, menghantar pemberitahuan, dan jawatan ke Twitter. Ini bermakna kita mempunyai kawalan yang lebih baik apabila operasi ini dijalankan. Kami juga boleh mengolok -olok kaedah ini dengan mudah dalam ujian untuk menghalang mereka daripada berjalan. Kita masih boleh mengutamakan operasi ini jika diperlukan (dalam kes ini kita kemungkinan besar akan berbuat demikian).
Oleh itu, kita boleh memadamkan peristiwa model dan pendengar untuk operasi ini. Ini bermakna kita boleh menggunakan kelas baru ini dalam kod aplikasi kami dan menggunakan kilang model dengan selamat dalam kod ujian kami. AppServicesPostService
di atas dalam contoh
kami untuk menjadualkan peristiwa:
AppServicesPostService
createPost
Dengan menggunakan kaedah di atas, kita masih boleh mempunyai pendengar yang berasingan untuk membuat permintaan API dan menghantar pemberitahuan ke Twitter. Tetapi kami mempunyai kawalan yang lebih baik apabila operasi ini dijalankan, jadi mereka tidak dijalankan semasa ujian menggunakan kilang model.
declare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
dengan cepat merumuskan apa yang telah kami diperkenalkan dalam artikel ini, berikut adalah beberapa kelebihan dan kekurangan menggunakan peristiwa model:
Harap artikel ini memberikan gambaran keseluruhan tentang peristiwa model dan pelbagai cara untuk menggunakannya. Ia juga harus menunjukkan kepada anda bagaimana untuk menguji kod acara model dan beberapa isu yang perlu diperhatikan apabila menggunakannya.
Anda kini harus mempunyai keyakinan yang cukup untuk menggunakan peristiwa model dalam aplikasi Laravel anda.
Atas ialah kandungan terperinci Panduan untuk acara model Laravel ' s. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!