Daniel-Handsome
  • NEW!
    NEW!  Connect Ideas Across Notes
    Save time and share insights. With Paragraph Citation, you can quote others’ work with source info built in. If someone cites your note, you’ll see a card showing where it’s used—bringing notes closer together.
    Got it
      • Create new note
      • Create a note from template
        • Sharing URL Link copied
        • /edit
        • View mode
          • Edit mode
          • View mode
          • Book mode
          • Slide mode
          Edit mode View mode Book mode Slide mode
        • Customize slides
        • Note Permission
        • Read
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Write
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invite by email
        Invitee

        This note has no invitees

      • Publish Note

        Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

        Your note will be visible on your profile and discoverable by anyone.
        Your note is now live.
        This note is visible on your profile and discoverable online.
        Everyone on the web can find and read all notes of this public team.

        Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Explore these features while you wait
        Complete general settings
        Bookmark and like published notes
        Write a few more notes
        Complete general settings
        Write a few more notes
        See published notes
        Unpublish note
        Please check the box to agree to the Community Guidelines.
        View profile
      • Commenting
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Suggest edit
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
      • Emoji Reply
      • Enable
      • Versions and GitHub Sync
      • Note settings
      • Note Insights New
      • Engagement control
      • Make a copy
      • Transfer ownership
      • Delete this note
      • Save as template
      • Insert from template
      • Import from
        • Dropbox
        • Google Drive
        • Gist
        • Clipboard
      • Export to
        • Dropbox
        • Google Drive
        • Gist
      • Download
        • Markdown
        • HTML
        • Raw HTML
    Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Engagement control Make a copy Transfer ownership Delete this note
    Import from
    Dropbox Google Drive Gist Clipboard
    Export to
    Dropbox Google Drive Gist
    Download
    Markdown HTML Raw HTML
    Back
    Sharing URL Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Customize slides
    Note Permission
    Read
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Write
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # laravel 觀察者模式 事件和偵聽器 https://code.tutsplus.com/tutorials/custom-events-in-laravel--cms-30331 必看 https://learnku.com/articles/20712 必看 https://www.bilibili.com/video/BV1nQ4y1N7QW/?spm_id_from=333.788.recommend_more_video.2 laravel中事件和观察者 https://www.jianshu.com/p/b258926011df ## 觀念重點區 Laravel 實現了服務提供者的概念,允許你將不同的服務注入到應用程序中 所以第一步驟要去Provider **你在用 artisan 命令生成 Event 的时候,对应的 Listner 也一并生成好了** 單個事件註冊多個偵聽器 事件助手會將事件分派給所有註冊的偵聽器,而無需我們顯式調用它們 事件(event)里没有任何业务逻辑,就是一个数据传输层 DTL(Data Transpotation Layer), 记住这个概念,在很多设计模式中都需要涉及到。 定义事件的侦听和处理器(Listener and Handler) ## 不觸發 sync 过程中确实是会有删除 question_topic 表的情况,不触发事件是因为在删除中间表的时候调用的是 Builder 这个类上面的 delete 方法,而不是 QuestionTopic 你这个模型上面的 delete 这个和 DB::table('question_topic')->delete(1) 不触发事件是同样的道理 ## Laravel 模型事件实现原理 非常重要 https://learnku.com/articles/5465/event-realization-principle-of-laravel-model ## queue 排隊事件偵聽器 如果您的偵聽器要執行緩慢的任務(例如發送電子郵件或發出 HTTP 請求),則排隊偵聽器會很有用。在使用排隊偵聽器之前,請確保配置您的隊列並在您的服務器或本地開發環境上啟動隊列工作器。 要指定偵聽器應排隊,請將ShouldQueue接口添加到偵聽器類。event:generate和make:listenerArtisan 命令生成的偵聽器已經將這個接口導入到當前命名空間中,因此您可以立即使用它: ``` <?php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue { // } ``` 就是這樣!現在,當這個監聽器處理的事件被調度時,監聽器將使用 Laravel 的隊列系統由事件調度器自動排隊。如果隊列執行監聽器時沒有拋出異常,則排隊的作業在處理完成後會自動刪除。 ## event vs observer vs通知 event能有條件去觸發 ![](https://i.imgur.com/ODt4QUv.png) 你可以看auth 中的 regies的trait 觀察是不能只能全部 ex 使用者全部 但可能管理員不要 通知也是 要用event去篩選 除非你是都要通知 ## Observers 事件需要与监听器关联来,当监听器变多了我们还需进行注册实现,这样会比较麻烦,这时我们可以考虑使用观察者。如果在一个模型上监听了多个事件,可以使用观察者来将这些监听器组织到一个单独的类中。 ## model的事件 (這種是用event 你也可以單純的用observers) 模型事件是专门针对模型而额外添加的功能。其给我们创建了对应的事件与监听。在使用模型事件事,我们需要遵守模型给我们的规则: retrieved當從數據庫中檢索到現有模型時,將調度該事件。第一次保存新模型時,將調度creating和created事件。在updating/updated在現有模型進行修改和事件將派遣save方法被調用。該saving/saved事件將派遣一個模型創建或更新時-即使模型的屬性沒有改變。以 結尾的事件名稱-ing在對模型的任何更改被持久化之前被調度,而以 結尾的事件-ed在對模型的更改被持久化之後被調度。 要開始監聽模型事件,請$dispatchesEvents在 Eloquent 模型上定義一個屬性。該屬性將 Eloquent 模型生命週期的各個點映射到您自己的事件類。每個模型事件類應該期望通過其構造函數接收受影響模型的實例: 在当模型的生命周期中,当发生一些事的时候,Eloquent 会触发一些事件: * creating - 对象已经 ready 但未写入数据库 * created - 对象已经写入数据库 * updating - 对象已经修改但未写入数据库 * updated - 修改已经写入数据库 * saving - 对象创建或者已更新但未写入数据库 * saved - 对象创建或者更新已经写入数据库 * deleting - 删除前 * deleted - 删除后 * restoring - 恢复软删除前 * restored - 恢复软删除后 对于每一个操作,都对应两个独立的事件。正如你可能想象的,它们指的是单独的时刻。我们已创建操作作为实例: 你有一个 creating 事件,可以理解为“创建操作即将发生”,而 created 表示“事件已经发生了”。 需要在模型处绑定 ``` protected $dispatchesEvents = [ 'saving' => \App\Events\TestEvent::class, // 'updated' => \App\Events\TestEvent::class, ]; ``` 在定義和映射 Eloquent 事件之後,您可以使用事件偵聽器來處理事件。 這樣綁定 你可以對應觸發相對的監聽器 這樣可以不用event() help 在你觸發的地方 但一樣要去povider註冊喔 ### model observer 生命週期的來源 https://learnku.com/articles/6657/model-events-and-observer-in-laravel `Illuminate\Database\Eloquent\Model` , 找到位于 517 行的 save 方法 可以看到首先触发的是 saving: `$this->fireModelEvent('saving')` ## (model events) 記住如果你在裏面有調用方法只能調用靜態的 因為你是靜態方法 沒有實例化 所以調用的也要靜態方法 ![](https://i.imgur.com/bliGYPg.png) 你可以看一下框架代码,里面是如何使用 boot() 方法的。举个例子: (當然你可以用 booted function 這樣就不用 在parent::boot(); 但不推薦) ``` public static function boot() { parent::boot(); static::updating(function (Balance $model) { // ... }); static::updated(function (Balance $model) { // ... }); } ``` 在我们的模型类里重写 static 的 boot 方法,能够给每个实例化的模型都挂载上特定事件。 另外,Eloquent 的 boot 方法(也就是以上例子中调用的 parent::boot())还会调用 bootTraits() 方法,该方法使用 class_uses_recursive() 函数来遍历某个类加载的所有 Trait,并调用每个 Trait 各自的 bootTraitName() 方法,因此可以实现一个模型引用多个不同的 Trait,每个 Trait 又挂载了不同的事件,从而实现给模型添加不同的「能力」(你可以注意到很多 Eloquent 扩展提供的 Trait 都使用 -able 词缀命名)。 可以用event去送事件 ## model 監聽多個事件 (observer) 如果你想在一个模型中监听多个事件,那么你可以把它写成一个类,类中的方法名称即是你想要监听的事件名称 ``` class UserObserver { /** * 监听数据即将创建的事件。 * * @param User $user * @return void */ public function creating(User $user) { } /** * 监听数据创建后的事件。 * * @param User $user * @return void */ public function created(User $user) { } /** * 监听数据即将更新的事件。 * * @param User $user * @return void */ public function updating(User $user) { } /** * 监听数据更新后的事件。 * * @param User $user * @return void */ public function updated(User $user) { } /** * 监听数据即将保存的事件。 * * @param User $user * @return void */ public function saving(User $user) { } /** * 监听数据保存后的事件。 * * @param User $user * @return void */ public function saved(User $user) { } /** * 监听数据即将删除的事件。 * * @param User $user * @return void */ public function deleting(User $user) { } /** * 监听数据删除后的事件。 * * @param User $user * @return void */ public function deleted(User $user) { } /** * 监听数据即将从软删除状态恢复的事件。 * * @param User $user * @return void */ public function restoring(User $user) { } /** * 监听数据从软删除状态恢复后的事件。 * * @param User $user * @return void */ public function restored(User $user) { } } ``` 然后在 AppServiceProvider 中注册此观察者 ``` <?php namespace App\Providers; use App\User; use App\Observers\UserObserver; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * 运行所有应用. * * @return void */ public function boot() { // 为 User 模型注册观察者 User::observe(UserObserver::class); } /** * 注册服务提供. * * @return void */ public function register() { // } } ``` ## 基本流程 可以用event:list去看所有的event 註冊在 app/Providers/EventServiceProvider.php $listen數組鍵對應系統中的事件,它們的值對應於系統中引發相應事件時將觸發的偵聽器 像下面的 監聽登入 然後發送訊息 ``` protected $listen = [ 'Illuminate\Auth\Events\Login' => [ 'App\Listeners\SendEmailNotification', ], ]; ``` Illuminate\Auth\Events\Login是Auth當有人登錄應用程序時插件會引發的事件。我們已將該事件綁定到App\Listeners\SendEmailNotification偵聽器,因此它將在登錄事件上觸發。 **第一步驟** 首先需要定義App\Listeners\SendEmailNotification監聽器類。與往常一樣,Laravel 允許您使用 artisan 命令創建偵聽器的模板代碼 `php artisan event:generate` event(new PodcastWasPurchased($podcast)); 或用 ::dispatch() 這是調用trait裡面的 等於上面的 此命令生成$listen屬性下列出的事件和偵聽器類 **兩個都要** **先創事件在創監聽器** 使用可以用event() helper涵式 Event::fire () 有个辅助函数可以简写: **基本樣子** ``` <?php namespace App\Listeners; use Illuminate\Auth\Events\Login; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class SendEmailNotification { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param Login $event * @return void */ public function handle(Login $event) { } } ``` handle每當觸發偵聽器時,都會使用適當的依賴項調用該方法。在我們的例子中,$event參數應該包含關於登錄事件的上下文信息——登錄的用戶信息。 當調用偵聽器時,該handle方法與關聯事件的**實例**一起傳遞 並且我們可以使用對$event像在handle方法中進行進一步的處理。在我們的例子中,我們希望向登錄用戶發送電子郵件通知。 修改後的handle方法可能類似於: ``` public function handle(Login $event) { // get logged in user's email and username $email = $event->user->email; $username = $event->user->name; // send email notification about login } ``` ## 創建自定義事件 看第一篇連結 先去povider註冊 然後創立事件 跟監聽器 ``` <?php namespace App\Providers; use Illuminate\Support\Facades\Event; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'App\Events\ClearCache' => [ 'App\Listeners\WarmUpCache', ], ]; /** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); // } } ``` 註冊 但這樣要一直寫很麻煩 可以用 ![](https://i.imgur.com/xbet7zT.png) 複寫底層 直接變成true就不用寫了 就會自動依賴注入了 不用註冊了 ## 多個event 将事件加入队列 如果要处理的事件很多,那么会影响当前进程的执行效率,这时我们需要把事件加入队列,让它延迟异步执行。 **定义队列执行是在 Listener 那里定义的:** ## Event Subscriber(事件訂閱者) Event Subscribers 是一种特殊的 Listener, 前面讲的是一个 listener 里只能放一个 hander(),事件订阅可以把很多处理器(handler)放到一个类里面,然后用一个 listner 把它们集合起来,这样不同的事件只要对应一个 listner 就可以了。 一個地方訂閱多個事件監聽器 ``` <?php // app/Listeners/ExampleEventSubscriber.php namespace App\Listeners; class ExampleEventSubscriber { /** * Handle user login events. */ public function sendEmailNotification($event) { // get logged in username $email = $event->user->email; $username = $event->user->name; // send email notification about login... } /** * Handle user logout events. */ public function warmUpCache($event) { if (isset($event->cache_keys) && count($event->cache_keys)) { foreach ($event->cache_keys as $cache_key) { // generate cache for this key // warm_up_cache($cache_key) } } } /** * Register the listeners for the subscriber. * * @param Illuminate\Events\Dispatcher $events */ public function subscribe($events) { $events->listen( 'Illuminate\Auth\Events\Login', 'App\Listeners\ExampleEventSubscriber@sendEmailNotification' ); $events->listen( 'App\Events\ClearCache', 'App\Listeners\ExampleEventSubscriber@warmUpCache' ); } } ``` 看后面的 subscribe (),每个事件和处理器是一一对应的。 绑定 Event Subscriber 到 Service Provider 它subscribe是負責註冊偵聽器的方法。該subscribe方法的第一個參數是Illuminate\Events\Dispatcher您可以使用該listen方法將事件與偵聽器綁定的類的實例 。 (感覺像單利模式那樣 laravel kenerl那種註冊的設計模式) 該listen方法的第一個參數是您要偵聽的事件,第二個參數是引發事件時將調用的偵聽器。 **寫好一樣要註冊喔** ``` <?php namespace App\Providers; use Illuminate\Support\Facades\Event; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The subscriber classes to register. * * @var array */ protected $subscribe = [ 'App\Listeners\ExampleEventSubscriber', ]; /** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); // } } ``` ## 不同時區 在正確的時間發送事件提醒 https://www.youtube.com/watch?v=2Eb0_lIQZk0 ## Listenser指定queue ``` <?php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue { public $queue = 'listeners'; } ``` Answer: 在 listener class 中使用 $queue 指定該 listener 使用的 queue ###### tags: `Laravel`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully