События модели Laravel – я немного смущен тем, где они предназначены

Таким образом, я вижу, что хорошее приложение Laravel должно быть очень ориентировано на модели и события.

У меня есть модель под названием « Article . Я хочу отправить уведомления по электронной почте, когда произойдут следующие события:

  • Когда создается статья
  • Когда статья обновляется
  • Когда статья удаляется

Документы говорят, что я могу использовать события модели и регистрировать их в функции boot() App\Providers\EventServiceProvider .

Но это меня смущает, потому что …

  • Что происходит, когда я добавляю дополнительные модели, такие как Comment или Author которые нуждаются в полных наборах всех своих собственных событий модели? Будет ли единственная функция boot() EventServiceProvider просто огромной?
  • Какова цель других «событий» Ларавеля ? Почему мне когда-либо понадобится их использовать, если реально мои события будут реагировать только на действия Model CRUD?

Я новичок в Laravel, приехав из CodeIgniter, поэтому, пытаясь обернуть голову вокруг правильного способа Laravel делать вещи. Спасибо за ваш совет!

Solutions Collecting From Web of "События модели Laravel – я немного смущен тем, где они предназначены"

Недавно я столкнулся с той же проблемой в одном из моих проектов Laravel 5, где мне пришлось регистрировать все события модели. Я решил использовать Traits . Я создал ModelEventLogger Trait и просто использовался во всех классах 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() метод register Event Handler для Article .

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

Теперь создайте класс ArticleEventHandler app/Handlers/Events как 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'); } } 

Как вы можете видеть из разных ответов, у разных пользователей существует более одного способа обработки событий модели. Существуют также пользовательские события, которые могут быть созданы в папке «События» и могут обрабатываться в папке «Обработчик» и могут отправляться из разных мест. Я надеюсь, что это помогает.

В вашем случае вы также можете использовать следующий подход:

 // 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 для обработки этого события. Например, обработчик 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. Создайте наблюдателя для модели (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. Создайте новый 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()); }); } } 

Вы можете выбрать подход Observer для работы с Model Events. Например, вот мой 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) {} } 

Теперь, если я создаю модель продукта, ее наблюдатель будет выглядеть так:

 <?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.php каталоге Observers и я включаю его из 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 .

Если вам нужно отправить электронное письмо после создания записи, было бы более чистым использовать «другие» события Laravel, так как у вас будет выделенный класс, чтобы справиться с этим, и запустите его, когда хотите, из Контроллер.

«Другие» события будут иметь гораздо большую цель, так как чем больше автоматизация вашего приложения станет, подумайте обо всех ежедневных cronjobs, которые вам понадобятся в какой-то момент. Не будет более чистого способа справиться с другими, чем «другими» событиями.

Вы отметили этот вопрос как Laravel 5, поэтому я бы предложил не использовать модельные события, так как у вас будет много дополнительного кода в ваших моделях, что может затруднить управление в будущем. Вместо этого моя рекомендация состояла бы в том, чтобы использовать командную шину и события.

Вот документы для этих функций:

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

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

Моя рекомендация заключалась бы в использовании следующего шаблона.

  • Вы создаете форму, которая отправляется на ваш контроллер.
  • Контроллер отправляет данные из запроса, сгенерированного в команду.
  • Ваша команда делает тяжелую работу – т. Е. Создает запись в базе данных.
  • Затем ваша команда запускает событие, которое может быть обработано обработчиком события.
  • Ваш обработчик событий делает что-то вроде отправки электронной почты или обновления чего-то еще.

Есть несколько причин, почему мне нравится этот шаблон: Концептуально ваши команды обрабатывают вещи, которые происходят прямо сейчас, и события обрабатывают вещи, которые только что произошли. Кроме того, вы можете легко поместить обработчики команд и событий в очередь для последующей обработки – это отлично подходит для отправки электронных писем, поскольку вы, как правило, не хотите делать это в режиме реального времени, поскольку они замедляют HTTP-запрос по справедливому биту. Вы также можете иметь несколько обработчиков событий для одного события, которое отлично подходит для разделения проблем.

Было бы сложно представить какой-либо фактический код здесь, так как ваш вопрос больше о концепциях Laravel, поэтому я бы рекомендовал просматривать эти видеоролики, чтобы вы получили представление о том, как работает этот шаблон:

Здесь описывается командная шина:

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

В этом рассказывается, как работают события:

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

1) Вы можете создать прослушиватель событий для каждой новой модели (ArticleEventSubscriber, CommentEventSubscriber) при загрузке:

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 Docs (мастер) и этот другой ответ

2) Модельные события – это события, предоставленные по умолчанию Eloquent.

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

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

Вы можете иметь несколько слушателей в событии. Таким образом, у вас может быть слушатель, который отправляет электронное письмо при обновлении статьи, но у вас может быть совершенно другой слушатель, который делает что-то совершенно другое – они оба будут выполнены.