Laravel模型事件 – 我对他们要去的地方有点困惑

所以我看到的方式是,一个好的Laravel应用程序应该是模型和事件驱动的。

我有一个叫做Article的模型。 我希望在下列事件发生时发送电子邮件提醒:

  • 当文章被创build
  • 当文章更新
  • 当文章被删除

该文档说我可以使用模型事件,并在App\Providers\EventServiceProviderboot()函数中注册它们。

但这让我感到困惑,因为…

  • 当我添加CommentAuthor需要全套模型事件的更多模型时会发生什么? EventServiceProvider的单一boot()函数会是绝对巨大的吗?
  • Laravel的“其他”活动的目的是什么? 为什么我需要使用它们,如果真实的话,我的事件只会响应模型CRUD操作?

我是来自CodeIgniter的Laravel的初学者,所以试图把我的头围绕在Laravel的方式上。 谢谢你的build议!

最近我遇到了同样的问题,在我的一个Laravel 5项目中,我不得不logging所有的模型事件。 我决定使用Traits 。 我创build了ModelEventLogger Trait,并简单地用于需要logging的所有Model类。 我将根据你的需要改变它下面给出。

 <?php namespace App\Traits; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Event; /** * Class ModelEventThrower * @package App\Traits * * Automatically throw Add, Update, Delete events of Model. */ trait ModelEventThrower { /** * Automatically boot with Model, and register Events handler. */ protected static function bootModelEventThrower() { foreach (static::getModelEvents() as $eventName) { static::$eventName(function (Model $model) use ($eventName) { try { $reflect = new \ReflectionClass($model); Event::fire(strtolower($reflect->getShortName()).'.'.$eventName, $model); } catch (\Exception $e) { return true; } }); } } /** * Set the default events to be recorded if the $recordEvents * property does not exist on the model. * * @return array */ protected static function getModelEvents() { if (isset(static::$recordEvents)) { return static::$recordEvents; } return [ 'created', 'updated', 'deleted', ]; } } 

现在,您可以在任何要为其引发活动的模型中使用此特征。 在你的案例在Article模型。

 <?php namespace App; use App\Traits\ModelEventThrower; use Illuminate\Database\Eloquent\Model; class Article extends Model { use ModelEventThrower; //Just in case you want specific events to be fired for Article model //uncomment following line of code // protected static $recordEvents = ['created']; } 

现在在你的app/Providers/EventServiceProvider.php ,在boot()方法中注册Event Handler for Article

  public function boot(DispatcherContract $events) { parent::boot($events); $events->subscribe('App\Handlers\Events\ArticleEventHandler'); } 

现在在app/Handlers/Events目录下创buildClass ArticleEventHandler

 <?php namespace App\Handlers\Events; use App\Article; class ArticleEventHandler{ /** * Create the event handler. * * @return \App\Handlers\Events\ArticleEventHandler */ public function __construct() { // } /** * Handle article.created event */ public function created(Article $article) { //Implement logic } /** * Handle article.updated event */ public function updated(Article $article) { //Implement logic } /** * Handle article.deleted event */ public function deleted(Article $article) { //Implement logic } /** * @param $events */ public function subscribe($events) { $events->listen('article.created', 'App\Handlers\Events\ArticleEventHandler@created'); $events->listen('article.updated', 'App\Handlers\Events\ArticleEventHandler@updated'); $events->listen('article.deleted', 'App\Handlers\Events\ArticleEventHandler@deleted'); } } 

正如您从不同用户的不同答案中看到的,处理模型事件的方式不止一种。 也有自定义事件,可以在事件文件夹中创build,可以在Handler文件夹中处理,并可以从不同的地方分派。 我希望它有帮助。

在你的情况下,你也可以使用下面的方法:

 // Put this code in your Article Model public static function boot() { parent::boot(); static::created(function($article) { Event::fire('article.created', $article); }); static::updated(function($article) { Event::fire('article.updated', $article); }); static::deleted(function($article) { Event::fire('article.deleted', $article); }); } 

另外,您需要在App\Providers\EventServiceProvider注册监听器:

 protected $listen = [ 'article.created' => [ 'App\Handlers\Events\ArticleEvents@articleCreated', ], 'article.updated' => [ 'App\Handlers\Events\ArticleEvents@articleUpdated', ], 'article.deleted' => [ 'App\Handlers\Events\ArticleEvents@articleDeleted', ], ]; 

另外请确保您已经在App\Handlers\Events文件夹/目录中创build了处理App\Handlers\Events来处理该事件。 例如, article.created处理程序可能是这样的:

 <?php namespace App\Handlers\Events; use App\Article; use App\Services\Email\Mailer; // This one I use to email as a service class class ArticleEvents { protected $mailer = null; public function __construct(Mailer $mailer) { $this->mailer = $mailer; } public function articleCreated(Article $article) { // Implement mailer or use laravel mailer directly $this->mailer->notifyArticleCreated($article); } // Other Handlers/Methods... } 

我发现这是最干净的方式来做你想做的事情。

1.-为模型创build观察者(ArticleObserver)

 use App\Article; class ArticleObserver{ public function __construct(Article $articles){ $this->articles = $articles } public function created(Article $article){ // Do anything you want to do, $article is the newly created article } } 

2.-创build一个新的ServiceProvider(ObserversServiceProvider),记得把它添加到你的config / app.php

 use App\Observers\ArticleObserver; use App\Article; use Illuminate\Support\ServiceProvider; class ObserversServiceProvider extends ServiceProvider { public function boot() { Article::observe($this->app->make(ArticleObserver::class)); } public function register() { $this->app->bindShared(ArticleObserver::class, function() { return new ArticleObserver(new Article()); }); } } 

您可以selectObserver方法来处理模型事件。 例如,这里是我的BaseObserver

 <?php namespace App\Observers; use Illuminate\Database\Eloquent\Model as Eloquent; class BaseObserver { public function saving(Eloquent $model) {} public function saved(Eloquent $model) {} public function updating(Eloquent $model) {} public function updated(Eloquent $model) {} public function creating(Eloquent $model) {} public function created(Eloquent $model) {} public function deleting(Eloquent $model) {} public function deleted(Eloquent $model) {} public function restoring(Eloquent $model) {} public function restored(Eloquent $model) {} } 

现在,如果我要创build一个产品模型,它的Observer将如下所示:

 <?php namespace App\Observers; use App\Observers\BaseObserver; class ProductObserver extends BaseObserver { public function creating(Eloquent $model) { $model->author_id = Sentry::getUser()->id; } public function created(Eloquent $model) { if(Input::hasFile('logo')) Image::make(Input::file('logo')->getRealPath())->save(public_path() ."/gfx/product/logo_{$model->id}.png"); } public function updating(Eloquent $model) { $model->author_id = Sentry::getUser()->id; } public function updated(Eloquent $model) { if(Input::has('payment_types')) $model->paymentTypes()->attach(Input::get('payment_types')); //Upload logo $this->created($model); } } 

关于监听器,我在Observers目录中创build了一个observers.php文件,并将其包含在AppServiceProvider 。 这是来自observers.php文件的一个片段:

 <?php \App\Models\Support\Ticket::observe(new \App\Observers\Support\TicketObserver); \App\Models\Support\TicketReply::observe(new \App\Observers\Support\TicketReplyObserver); 

所有这些都是关于Model Events

如果您需要在创buildlogging后发送电子邮件,那么使用Laravel的“其他”事件将会更清洁,因为您将有一个专门的课程来处理这个问题,并在您希望的时候从控制器。

“其他”事件将具有更多的目的,因为您的应用程序变得越自动化,想到在某些时候您需要的所有日常cronjob。 除了“其他”活动之外,再没有比这更清晰的方式来处理了。

你已经将这个问题标记为Laravel 5,所以我build议不要使用模型事件,因为最终会在模型中出现大量额外的代码,这可能会使事情难以pipe理。 相反,我的build议是使用命令总线和事件。

以下是这些function的文档:

http://laravel.com/docs/5.0/bus

http://laravel.com/docs/5.0/events

我的build议是使用以下模式。

  • 你创build一个表单提交给你的控制器。
  • 您的控制器将生成的请求中的数据分派给一个命令。
  • 你的命令做了繁重的工作 – 即在数据库中创build一个条目。
  • 然后你的命令触发一个可以被事件处理程序拾取的事件。
  • 您的事件处理程序可以发送电子邮件或更新其他内容。

为什么我喜欢这种模式有几个原因:从概念上讲,你的命令处理现在正在发生的事情,事件处理刚发生的事情。 而且,你可以很容易地把命令和事件处理程序放到一个队列中稍后处理 – 这对于发送电子邮件来说是非常好的,因为你不希望这样做,因为它们会把HTTP请求放慢一点点。 您还可以为单个事件分配多个事件处理程序,这对分离问题非常有用。

在这里提供任何实际的代码很难,因为你的问题更多的是关于Laravel的概念,所以我build议你观看一下这些video,以便了解这个模式的工作原理:

这一个描述命令总线:

https://laracasts.com/lessons/laravel-5-events

这一个描述事件如何工作:

https://laracasts.com/lessons/laravel-5-commands

1)您可以使用以下引导方法为每个新模型(ArticleEventSubscriber,CommentEventSubscriber)创build事件侦听器:

EventServiceProvider.php

 public function boot(DispatcherContract $events) { parent::boot($events); $events->subscribe('App\Listeners\ArticleEventListener'); $events->subscribe('App\Listeners\CommentEventListener'); } 

或者你也可以使用$subscribe属性

 protected $subscribe = [ 'App\Listeners\ArticleEventListener', 'App\Listeners\CommentEventListener', ]; 

有很多方法来听和处理事件。 看看当前的主文档发现更多的方式(如使用闭包)来做到这一点: Laravel文档(主)和这个其他的答案

2)模型事件只是由Eloquent默认提供的事件。

https://github.com/illuminate/database/blob/491d58b5cc4149fa73cf93d499efb292cd11c88d/Eloquent/Model.php#L1171

https://github.com/illuminate/database/blob/491d58b5cc4149fa73cf93d499efb292cd11c88d/Eloquent/Model.php#L1273

您可以在事件中拥有多个侦听器。 所以当一篇文章被更新时,你可能会有一个发送邮件的监听器,但是你可以有一个完全不同的监听器来做一些完全不同的事情 – 它们都会被执行。