Laravel Model Events – Ich bin etwas verwirrt darüber, wohin sie gehen sollen

Lesezeit: 11 Minuten

So wie ich es sehe, sollte eine gute Laravel-Anwendung sehr modell- und ereignisgesteuert sein.

Ich habe ein Model namens Article. Ich möchte E-Mail-Benachrichtigungen senden, wenn die folgenden Ereignisse eintreten:

  • Wenn ein Artikel erstellt wird
  • Wenn ein Artikel aktualisiert wird
  • Wenn ein Artikel gelöscht wird

Die Dokumente sagen, ich kann Modellereignisse verwenden und sie innerhalb der registrieren boot() Die Funktion von App\Providers\EventServiceProvider.

Aber das verwirrt mich, weil…

  • Was passiert, wenn ich weitere Modelle hinzufüge wie z Comment oder Author die vollständige Sätze aller ihrer eigenen Modellereignisse benötigen? Wird die Single boot() Die Funktion von EventServiceProvider einfach absolut riesig sein?
  • Was ist der Zweck von Laravels ‘andere’ Events? Warum sollte ich sie jemals verwenden müssen, wenn meine Ereignisse realistischerweise nur auf Modell-CRUD-Aktionen reagieren?

Ich bin ein Anfänger bei Laravel, nachdem ich von CodeIgniter gekommen bin, also versuche ich, mich mit der richtigen Vorgehensweise von Laravel vertraut zu machen. Danke für deinen Rat!

Benutzer-Avatar
Das Alpha

In Ihrem Fall können Sie auch den folgenden Ansatz verwenden:

// 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);
    });
}

Außerdem müssen Sie Zuhörer registrieren 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',
    ],
];

Stellen Sie außerdem sicher, dass Sie die Handler in erstellt haben App\Handlers\Events Ordner/Verzeichnis, um dieses Ereignis zu behandeln. Zum Beispiel, article.created Handler könnte so aussehen:

<?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...
}

  • Ich habe nach einer Möglichkeit gesucht, mein Boot-Modell aus irgendeinem Grund zu ändern. Unter Verwendung der Beispiele, die Sie zum Registrieren des Listeners angegeben haben, habe ich einfach den Listener für das erstellte Ereignis in EventServiceProvider wie folgt hinzugefügt $listen = [ 'eloquent.created: '.User::class => [ MyListener::class ] ]; Das war es, ich konnte das erstellte Ereignis im Benutzermodell anhören. Das ist Laravel 5.5

    – Oluwatobi Samuel Omisakin

    25. November 2019 um 13:49 Uhr


Benutzer-Avatar
rosa vansia

Vor kurzem bin ich in einem meiner Laravel 5-Projekte auf dasselbe Problem gestoßen, wo ich alle Modellereignisse protokollieren musste. Ich entschied mich zu verwenden Traits. ich erschuf ModelEventLogger Merkmal und einfach in allen Modellklassen verwendet, die geloggt werden mussten. Ich werde es nach Ihren Bedürfnissen ändern, die unten angegeben sind.

<?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',
        ];
    }
} 

Jetzt können Sie diese Eigenschaft in jedem Modell verwenden, für das Sie Ereignisse auslösen möchten. In Ihrem Fall in Article Modell.

<?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'];

}

Jetzt in Ihrem app/Providers/EventServiceProvider.phpin boot() Methode registrieren Event-Handler für Article.

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

Erstellen Sie nun eine Klasse ArticleEventHandler unter app/Handlers/Events Verzeichnis wie unten,

<?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');
 }

}

Wie Sie aus verschiedenen Antworten von verschiedenen Benutzern sehen können, gibt es mehr als eine Möglichkeit, Modellereignisse zu handhaben. Es gibt auch benutzerdefinierte Ereignisse, die im Ordner “Ereignisse” erstellt und im Ordner “Handler” verarbeitet und von verschiedenen Orten aus versendet werden können. Ich hoffe, es hilft.

  • Ich denke, man kann das bedenkenlos verschieben $reflect = new \ReflectionClass($model); in bootModelEventThrower() außerhalb von foreach Vorbeigehen static::class Anstatt von $model. Sie könnten auch den Kurznamen mit erhalten substr(static::class, strrpos(static::class, '\\') + 1).

    – Parziphal

    24. Dezember 2015 um 6:57 Uhr

  • @pinkel-vansia elegante Möglichkeit, generische Modellereignisse zu generieren. Ich stimme auch @renocor zu, das ich verwendet habe function (Model $model) use ($reflect, $eventName) obwohl.

    – Raffael

    4. Mai 2016 um 13:33 Uhr

  • Dieser Thread ist ziemlich alt und die vorgeschlagene Lösung ist elegant 🙂 Aber für diejenigen, die alle Models-Ereignisse einfach protokollieren möchten, habe ich kürzlich dieses großartige Paket verwendet, das ich empfehle: github.com/spatie/laravel-activitylog

    – guck

    1. Juni 2018 um 11:42 Uhr


  • Um in Lara 6 einen Modellnamen zu erhalten, verwenden Sie einfach strtolower(class_basename(static::class)), es ist keine Reflektion erforderlich

    – ymakux

    7. März 2020 um 0:45 Uhr

Ich fand, dass dies der sauberste Weg ist, das zu tun, was Sie wollen.

1.- Erstellen Sie einen Beobachter für das Modell (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.- Erstellen Sie einen neuen ServiceProvider (ObserversServiceProvider), denken Sie daran, ihn zu Ihrer config/app.php hinzuzufügen

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());
        });
  }

}

  • Warum würden Sie dieser Antwort nach fast 3 Jahren eine -1 geben? Dies war damals der bevorzugte Weg, dies zu tun, und wurde den offiziellen Dokumenten entnommen.

    – Borjante

    31. März 2018 um 9:39 Uhr

Sie können sich für den Observer-Ansatz entscheiden, um mit Modellereignissen umzugehen. Hier ist zum Beispiel meine 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) {}
}

Wenn ich nun ein Produktmodell erstellen soll, würde sein Beobachter so aussehen:

<?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);
    }
}

In Bezug auf Zuhörer erstelle ich eine observers.php Datei drin Observers dir und ich schließe es aus dem ein AppServiceProvider. Hier ist ein Ausschnitt aus dem observers.php Datei:

<?php

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

All dies betrifft Model Events.

Wenn Sie eine E-Mail senden müssen, nachdem ein Datensatz erstellt wurde, wäre es sauberer, die „anderen“ Ereignisse von Laravel zu verwenden, da Sie eine dedizierte Klasse haben, die sich genau darum kümmert, und sie auslöst, wenn Sie dies wünschen Der Controller.

Die „anderen“ Events werden viel mehr Sinn haben, je automatisierter Ihre App wird, denken Sie an all die täglichen Cronjobs, die Sie irgendwann brauchen werden. Es wird keinen saubereren Weg geben, damit umzugehen, als mit „anderen“ Ereignissen.

Sie haben diese Frage als Laravel 5 markiert, daher würde ich vorschlagen, keine Modellereignisse zu verwenden, da Sie am Ende viel zusätzlichen Code in Ihren Modellen haben werden, was die Verwaltung in Zukunft erschweren kann. Stattdessen würde ich empfehlen, den Befehlsbus und Ereignisse zu verwenden.

Hier ist die Dokumentation für diese Funktionen:

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

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

Meine Empfehlung wäre, das folgende Muster zu verwenden.

  • Sie erstellen ein Formular, das an Ihren Controller gesendet wird.
  • Ihr Controller sendet die Daten aus der generierten Anfrage an einen Befehl.
  • Ihr Befehl erledigt die schwere Arbeit – dh erstellt einen Eintrag in der Datenbank.
  • Ihr Befehl löst dann ein Ereignis aus, das kann von einem Event-Handler abgeholt werden.
  • Ihr Ereignishandler tut so etwas wie das Senden einer E-Mail oder das Aktualisieren von etwas anderem.

Es gibt ein paar Gründe, warum ich dieses Muster mag: Konzeptionell behandeln Ihre Befehle Dinge, die gerade passieren, und Ereignisse behandeln Dinge, die gerade passiert sind. Außerdem können Sie Befehls- und Ereignishandler einfach in eine Warteschlange stellen, um sie später zu verarbeiten. Dies ist großartig, um E-Mails zu senden, da Sie dies normalerweise nicht in Echtzeit tun möchten, da dies die HTTP-Anfrage ziemlich verlangsamt. Sie können auch mehrere Ereignishandler für ein einzelnes Ereignis haben, was sich hervorragend zum Trennen von Bedenken eignet.

Es wäre schwierig, hier einen tatsächlichen Code als Ihre Frage zu den Konzepten von Laravel bereitzustellen, daher würde ich empfehlen, sich diese Videos anzusehen, damit Sie eine gute Vorstellung davon bekommen, wie dieses Muster funktioniert:

Dieser beschreibt den Befehlsbus:

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

Dieser beschreibt, wie Events funktionieren:

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

  • Bus existiert nicht mehr für 5.1. Laravel ändert sich zu sehr. Was wäre der Ansatz in 5.1 oder 5.2?

    – Parziphal

    24. Dezember 2015 um 6:16 Uhr

  • Es existiert immer noch, Befehle werden jetzt nur noch als Queue-Jobs bezeichnet. Sie müssen jedoch nicht in der Warteschlange ausgeführt werden, sie können einfach synchron ausgeführt werden.

    – edcs

    24. Dezember 2015 um 7:21 Uhr

  • Sie sprechen den guten Punkt von nicht blockierenden Ereignissen an, aber dies würde Ihre Einfügung auch nicht blockieren, wenn Sie sie in die Warteschlange stellen würden. Ereignisse selbst sollten nicht blockierend sein. Ich denke, jeder war für eine Sekunde mit Laravel etwas zu aufgeregt über Befehle und Dienste … sie sind nützlich, aber notwendigerweise nur zum Hinzufügen eines Ereignisses

    – Sabrina Leggett

    15. April 2016 um 15:27 Uhr


Benutzer-Avatar
Martin Bean

Sie können mehrere Zuhörer für ein Ereignis haben. Sie haben also vielleicht einen Listener, der eine E-Mail sendet, wenn ein Artikel aktualisiert wird, aber Sie könnten einen völlig anderen Listener haben, der etwas völlig anderes macht – sie werden beide ausgeführt.

  • Bus existiert nicht mehr für 5.1. Laravel ändert sich zu sehr. Was wäre der Ansatz in 5.1 oder 5.2?

    – Parziphal

    24. Dezember 2015 um 6:16 Uhr

  • Es existiert immer noch, Befehle werden jetzt nur noch als Queue-Jobs bezeichnet. Sie müssen jedoch nicht in der Warteschlange ausgeführt werden, sie können einfach synchron ausgeführt werden.

    – edcs

    24. Dezember 2015 um 7:21 Uhr

  • Sie sprechen den guten Punkt von nicht blockierenden Ereignissen an, aber dies würde Ihre Einfügung auch nicht blockieren, wenn Sie sie in die Warteschlange stellen würden. Ereignisse selbst sollten nicht blockierend sein. Ich denke, jeder war für eine Sekunde mit Laravel etwas zu aufgeregt über Befehle und Dienste … sie sind nützlich, aber notwendigerweise nur zum Hinzufügen eines Ereignisses

    – Sabrina Leggett

    15. April 2016 um 15:27 Uhr


Benutzer-Avatar
Gemeinschaft

1) Sie können einen Ereignis-Listener für jedes neue Modell (ArticleEventSubscriber,CommentEventSubscriber) bei der Boot-Methode erstellen:

EventServiceProvider.php

public function boot(DispatcherContract $events)
{
    parent::boot($events);

    $events->subscribe('App\Listeners\ArticleEventListener');
    $events->subscribe('App\Listeners\CommentEventListener');
}

oder Sie können auch verwenden $subscribe Eigentum

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

Es gibt viele Möglichkeiten, Ereignisse abzuhören und zu verarbeiten. Werfen Sie einen Blick auf die aktuelle Master-Dokumentation, um weitere Möglichkeiten (wie die Verwendung von Closures) zu entdecken: Laravel Docs (Meister) und diese andere Antwort

2) Modellereignisse sind nur Ereignisse, die standardmäßig von Eloquent bereitgestellt werden.

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

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

1334960cookie-checkLaravel Model Events – Ich bin etwas verwirrt darüber, wohin sie gehen sollen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy