首先,我们为你展示如何通过模型观察者实现前面模式事件中的第一个例子。
在 app/Observers
文件夹中创建 WelcomeUserObserver.php
文件,并加入下面的代码:
<?php namespace App\Observers; class WelcomeUserObserver { public function created($user){ Mail::send('emails.welcome', ['user' => $user], function($message) use ($user) { $message->to($user->email, $user->first_name . ' ' . $user->last_name)->subject('Welcome to My Awesome App, '.$user->first_name.'!'); }); } }
然后在 EventServiceProvider
的 boot()
方法中注册该观察者:
/** * Register any other events for your application. * * @param \Illuminate\Contracts\Events\Dispatcher $events * @return void */ public function boot(DispatcherContract $events) { parent::boot($events); User::observe(new WelcomeUserObserver); }
这样就 OK 了!现在你的观察者已经与模型关联起来了。
下面我们假设另一种情况。图书管理员对代码提出了一些新的需求:
- 当添加一个新的作者的时候,每一个用户都收到一条通知
- 每次添加/删除作者的时候,都发送一封邮件
- 最后,每次删除一本书的时候,图书管理员都要知道数据库中有多少作者是没有与相关的图书的
好了,下面我们就开始吧。我们需要三个单独的类(请记住我们的单一职责原则):CustomerNewAuthorObserver
、LibrarianAuthorObserver
、AuthorsWithoutBooksObservers
。
注意:你可以按自己喜欢的方式命名这些类,我们这里只是选择比较容易与所选行为关联起来的名称。
下面我们分别来创建三个类:
<?php // file: app/Observers/CustomerNewAuthorObserver namespace App\Observers; class CustomerNewAuthorObserver { public function created($author) { } } <?php // file: app/Observers/LibrarianAuthorObserver namespace App\Observers; class LibrarianAuthorObserver { public function created($author) { } public function deleted($author) { } } <?php // file: app/Observers/AuthorsWithoutBooksObservers namespace App\Observers; class AuthorsWithoutBooksObservers { public function deleted($author) { } }
好了,现在应该添加一些逻辑了,首先为 CustomerNewAuthorObserver
添加:
<?php // file: app/Observers/CustomerNewAuthorObserver namespace App\Observers; class CustomerNewAuthorObserver { public function created($author) { // getting all users... $users = \App\User::all(); foreach($users as $user) { Mail::send('emails.created_author_customer', ['author' => $author], function($message) use ($user) { $message->to($user->email, $user->first_name . ' ' . $user->last_name)->subject('New Author Added!'); }); } } }
注意:我知道这是一种非常简单粗暴的方法,这里只是为了实现上面的目的。实际情况中可以使用邮件队列。
<?php // file: app/Observers/LibrarianAuthorObserver namespace App\Observers; class LibrarianAuthorObserver { public function created($author) { Mail::send('emails.created_author_librarian', ['author' => $author], function($message) use ($author) { $message->to('[email protected]', 'The Librarian')->subject('New Author: ' . $author->first_name . ' ' . $author->last_name); }); } public function deleted($author) { Mail::send('emails.deleted_author_librarian', ['author' => $author], function($message) use ($author) { $message->to('[email protected]', 'The Librarian')->subject('New Author: ' . $author->first_name . ' ' . $author->last_name); }); } }
最后:
<?php // file: app/Observers/AuthorsWithoutBooksObservers namespace App\Observers; class AuthorsWithoutBooksObservers { public function deleted($author) { $authorsWithoutBooks = \App\Author::has('books', '=', 0)->get(); if(count($authorsWithoutBooks) > 0){ Mail::send('emails.author_without_books_librarian', ['authorsWithoutBooks' => $authorsWithoutBooks], function($message) { $message->to('[email protected]', 'The Librarian')->subject('Authors without Books! A check is required!'); }); } } }
注意:就像前面提过的,我们假定你已经了解了 Laravel 发送邮件的基本知识,没有的话可以到官网学习下相关知识。
到这里并没有结束。你可以在大量的案例和场景中使用 Laravel 的模型事件和模型观察者。举个例子,假设你写博客,你希望每次发布一篇新文章或者更新一篇原有文章的时候,都更新一些站点地图,这时就可以用到观察者。再比如,当添加新书的时候,记录一些东西,也可以用到观察者。
初学者 2016/08/09 23:53
你好,我是初学者,请教一下本系列问战中的观察者模式和Laravel中的监听/事件区别在哪?我看了一下,Laravel的事件监听需要在代码中手动触发?
Specs 2016/08/14 18:20
@ 观察者相比事件的话更高级一些,并且可以提供一些更高级的方法,你可以百度一下“观察者模式”看看
kylesean 2018/12/06 00:45
@ laravel内置的模型事件是由于观察者模式封装产生的,内部模型已经在相应地方触发了,你可以定义你的观察者observer,重写你所有的模型事件,处理你的业务逻辑,也可以在observer上定义自己的事件方法,书写业务逻辑,然后在model里,定义好$this->$observables =['你的事件'],最后在model上手动触发, $this->fireModelEvent('xx', false);但是这么写model就会越来越大,所以从5.4版本以后,laravel 允许我们将 Eloquent 模型的生命周期的多个事件映射到专门的事件系统中的事件类(EventServiceProvider),当然你也可以自定义自己的事件类,统一在EventServiceProvider注册,这样处理更优雅,也支持异步队列处理事件了。所以归根结底的区别就是,事件更灵活,是观察者模式的实现原理,使用起来更友好,谢谢
孤城浪子 2017/12/05 14:51
我看到文档上面是在AppServiceProvider中注册观察者,而本文是在EventServiceProvider中注册,我想知道有什么区别呢?我怎么确定我应该在哪儿注册呢?