在使用 Eloquent 模型時,通常會利用通過模型生命周期調(diào)度的事件。有幾種不同的方法可以做到這一點,在本教程中,我將介紹它們并解釋每種方法的優(yōu)缺點。【相關(guān)推薦:laravel視頻教程】
我將為每種方法使用相同的示例,以便你可以直接進行比較。此示例將在創(chuàng)建模型本身的過程中將模型的 UUID 屬性分配給 UUID 。
我們的第一種方法使用模型的靜態(tài)引導(dǎo)方法來注冊行為。這使我們能夠直接在模型上工作,并在模型為 created 。
declare(strict_types=1); namespace?AppModels; use?IlluminateDatabaseEloquentModel; use?IlluminateSupportStr; class?Office?extends?Model { ????public?static?function?boot():?void ????{ ????????static::creating(fn?(Model?$model)?=> ????????????$model->uuid?=?Str::uuid(), ????????); ????} }
這種方法非常適合對模型事件的小而直接的反應(yīng),比如添加 UUID ,因為它非常容易理解,而且你可以準(zhǔn)確地看到模型上正在發(fā)生的事情。這種方法最大的問題是代碼重復(fù),如果你有多個模型需要分配 UUID ,你將重復(fù)做相同的事情。
這很好地引導(dǎo)我們進入第二種方法,使用一個特征。在 laravel 中,如果你在 trait 上創(chuàng)建一個以 boot 開頭并以 trait 名稱結(jié)尾的方法,你的模型可以繼承 trait 并自動啟動它們。這是一個例子:
declare(strict_types=1); namespace?AppModelsConcerns; use?IlluminateDatabaseEloquentModel; use?IlluminateSupportStr; trait?HasUuid { ????public?static?function?bootHasUuid():?void ????{ ????????static::creating(fn?(Model?$model)?=> ????????????$model->uuid?=?Str::uuid(), ????????); ????} }
使用特征允許你將此行為添加到需要它且易于實現(xiàn)的每個模型中。我最大的缺點是,當(dāng)多個特征想要利用同一個模型事件時,堆疊這些行為可能會導(dǎo)致問題。他們開始爭奪優(yōu)先權(quán),很快就會變得一團糟。
這將我們引向下一個選項,模型觀察者。模型觀察者是一種基于類的方法來響應(yīng)模型事件,其中方法對應(yīng)于被觸發(fā)的特定事件。
declare(strict_types=1); namespace?AppObservers; use?IlluminateDatabaseEloquentModel; use?IlluminateSupportStr; class?OfficeObserver { ????public?function?creating(Model?$model):?void ????{ ????????$model->uuid?=?Str::uuid(); ????} }
這個類需要在某個地方注冊,在服務(wù)提供者或模型本身(這是我推薦的地方)。在模型中注冊這個觀察者可以在模型級別上看到改變雄辯行為的副作用。將其隱藏在服務(wù)提供商中的問題在于,除非每個人都知道它的存在,否則很難知道。這種方法的最大缺點是它的可見性。在我看來,正確使用這種方法非常棒。
解決此問題的另一種方法是利用 Eloquent 模型本身的$dispatchesEvents 屬性。這是每個 Eloquent 模型上的一個屬性,它允許你列出要偵聽的事件以及為這些事件調(diào)用的類。
declare(strict_types=1); namespace?AppModels; use?IlluminateDatabaseEloquentModel; use?IlluminateSupportStr; class?Office?extends?Model { ????protected?$dispatchesEvents?=?[ ????????'creating'?=>?SetModelUuid::class, ????]; }
SetModelUuid 將在 Eloquent 模型的生命周期中被實例化,這是你向模型添加行為和屬性的機會。
declare(strict_types=1); namespace?AppModelsEvents; use?IlluminateDatabaseEloquentModel; use?IlluminateSupportStr; class?SetModelUuid { ????public?function?__construct(Model?$model) ????{ ????????$model->uuid?=?Str::uuid(); ????} }
這種方法是最簡潔和最容易理解的方法之一,因為模型有很多可見性,并且你可以輕松地在模型之間共享這個類。你將面臨的最大問題是是否需要在模型事件上觸發(fā)多個操作。
總之,老實說,沒有正確的方法可以做到這一點。你可以選擇上述任何一種方法,它們都會起作用,但你應(yīng)該選擇適合你和你的特定用例的方法。我希望看到有關(guān)此特定功能的更多選項。
例如,如果你需要在模型事件上向模型添加多個屬性,則觀察者是一個不錯的選擇。然而,這是最好的選擇嗎?如果我們使用 dispatch events 屬性為該模型運行自定義管道會怎樣?
declare(strict_types=1); namespace?AppModelsPipelines; use?AppModelsOffice class?OfficeCreatingPipeline { ????public?function?__construct(Office?$model) ????{ ????????app(Pipeline::class) ????????????->send($model) ????????????->through([ ????????????????ApplyUuidProperty::class, ????????????????TapCreatedBy::class, ????????????]); ????} }
如你所見,我們可以開始使用管道來為事件建模添加多個行為。現(xiàn)在,這還沒有經(jīng)過測試,所以我不知道 100% 是否可行 – 但作為一個概念,它可以開辟一種可組合的方法來對模型事件做出反應(yīng)。
你如何處理 Laravel 項目中的模型事件?在推特上告訴我們!
原文地址:https://laravel-news.com/working-with-laravel-model-events譯文地址:https://learnku.com/laravel/t/71183
更多編程相關(guān)知識,請訪問:laravel視頻教程!!