Таким образом, я вижу, что хорошее приложение Laravel должно быть очень ориентировано на модели и события.
У меня есть модель под названием « Article
. Я хочу отправить уведомления по электронной почте, когда произойдут следующие события:
Документы говорят, что я могу использовать события модели и регистрировать их в функции boot()
App\Providers\EventServiceProvider
.
Но это меня смущает, потому что …
Comment
или Author
которые нуждаются в полных наборах всех своих собственных событий модели? Будет ли единственная функция boot()
EventServiceProvider
просто огромной? Я новичок в Laravel, приехав из CodeIgniter, поэтому, пытаясь обернуть голову вокруг правильного способа 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
В этом рассказывается, как работают события:
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.
Вы можете иметь несколько слушателей в событии. Таким образом, у вас может быть слушатель, который отправляет электронное письмо при обновлении статьи, но у вас может быть совершенно другой слушатель, который делает что-то совершенно другое – они оба будут выполнены.