2016-06-03 17 views
9

Ich versuche meine Datenbank mit einem externen Dienst zu synchronisieren.Laravel Multiple Model Events

Ich benutze Algolia Suche an ein paar Orten über eine Webanwendung.

Es ist mit ein paar Modellen indiziert, aber ich muss es neu indizieren, falls Änderungen an der Datenbank vorgenommen werden, d. H. Wenn mehrere Modellereignisse ausgelöst werden.

Mein erster Ansatz zum Handeln alles im Boot Methode des AppServiceProvider war

public function boot() 
{ 
    $events = ['created', 'updated', 'deleted', 'restored']; 

    // reindex handlers for models relevant to Algolia search 
    foreach ($events as $evt) { 
     Order::registerModelEvent($evt, function() { 
      Order::reindex(); 
     }); 
     Product::registerModelEvent($evt, function() { 
      Product::reindex(); 
      Product::setSettings(); 
     }); 
    } 
} 

Das ist mein Ansatz mehr conditionals Funktionen unter Verwendung der Standard-Modells in den docs exampled zu vermeiden.

Allerdings gehe ich davon aus, dass es einen besseren Weg gibt, Laravel Event Listeners zu verwenden.

namespace App\Listeners; 

class OrderEventListener 
{ 
    // handlers 

    public function subscribe($events) 
    { 
     $events->listen(
      // model events 
     ); 
    } 
} 

Obwohl ich bin nicht sicher, wie in der in die Modell Ereignisse tippen hören Methode.

Antwort

7

Ich würde dringend empfehlen, Ihr eigenes Event und Handler für diese Situation hinzuzufügen.

In Ihren Product und Order Klassen können Sie die boot Methode des Modells außer Kraft setzen:

class Product extends Model 
{ 
    protected static function boot() 
    { 
     parent::boot(); 

     self::created(function($product) { 
      event(new ProductCreatedEvent($product)); 
     }); 
    } 
} 

Sie benötigen Ihr eigenes ProductCreatedEvent Objekt zu erstellen. Jetzt in der EventServiceProvider10 möchten Sie zum Listener-Array hinzufügen;

protected $listeners = [ 
    'App\Events\ProductCreatedEvent' => [ 
     'App\Listeners\UpdateAlgoliaProductIndex', 
    ] 
]; 

Sobald Sie dies eingerichtet haben können Sie tatsächlich php artisan event:generate laufen, und dies wird das Ereignisobjekt und Hörer für Sie erstellen. Ich überspringe das Event-Objekt, da es ziemlich einfach ist, nimmt es das Produkt, das erstellt wurde, und sendet es an den Listener UpdateAlgoliaProductIndex.

Jetzt in Ihrem Zuhörer haben Sie so etwas wie die folgende:

class UpdateAlgoliaProductIndex 
{ 
    public function handle($event) 
    { 
     Product::reindex(); 
     Product::setSettings(); 
    } 
} 

Der Grund, warum ich diesen Ansatz vorschlagen, ist, dass Sie dann den Hörer mit dem ShouldQueue Schnittstelle Warteschlange können bedeuten, dass Sie die Anforderung nicht blockieren während Sie darauf warten, dass Ihre App mit Algolia neu indiziert wird, was zu einer besseren Nutzererfahrung führt.

Sie können mehr über die Ereignisobjekte und Listener here lesen.

Eine alternative Option ist die Verwendung eines model observer.

+0

Ich habe so etwas für Benachrichtigungen getan, z. Ein Produkt wird aktualisiert, ein 'ProductCreatedEvent' wird ausgelöst. Ich bin damit einverstanden, weil ich es nur mit 'self :: updated()' in der Boot-Methode auslösen muss, wie Sie es anzeigen. Allerdings sollte etwas wie das erneute Indizieren hier ausgeführt werden, wann immer ein Modellereignis ausgelöst wird, und ich suchte nach einer Lösung, die nicht jedes Modellereignis mit nachfolgenden Ereignislistenern, Handlern usw. auflisten musste. Wenn ich mehr darüber in Betracht ziehe besser sein, einen Job zu erstellen und es im Boot zu versenden? Dann kann es zwar ShouldQueue implementieren, aber es wird immer ausgelöst. –

+1

Wenn Sie jedes Model Event haben möchten, haben Sie wahrscheinlich mehr Glück, wenn Sie nach 'save' anstatt nach' created' Ausschau halten. Die 'ShouldQueue' beseitigt die Notwendigkeit, ein zusätzliches Job-Objekt zu definieren. Wenn Sie es nicht sofort ausführen möchten, würde ich vorschlagen, nur ein 'requests_search_indexing' Feld zu Ihrem Produktobjekt hinzuzufügen. Dann könnten Sie regelmäßig einen Cron-Job ausführen, um die Updates zu gruppieren. –

+0

Das ist ein guter Punkt. Ich nehme es, wenn Sie einen Mittelweg wollten, befürworten Sie immer noch die Verwendung aller Event-Listener. Laravel 5.2 scheint Modellbeobachter aus den Dokumenten fallen gelassen zu haben, was mich dazu bringt, mich zu fragen, ob sie den Ansatz nicht mehr empfehlen. –

0

Mit etwas Graben bin ich auf Laravel-Ereignis subscribers gestoßen, das eher dem entspricht, nach was ich gesucht habe, also habe ich es als seine eigene Antwort vorgelegt.

Ich denke, das produziert mehr prägnanten Code als Hörer für jedes Ereignis zu haben.

namespace App\Listeners; 

use App\Events\OrderCreatedEvent; 
use App\Events\OrderUpdatedEvent; 
use Illuminate\Queue\InteractsWithQueue; 
use Illuminate\Contracts\Queue\ShouldQueue; 

class OrderEventListener 
{ 
    /** 
    * Handle order created events. 
    * 
    * @param OrderCreatedEvent $event 
    */ 
    public function onOrderCreation(OrderCreatedEvent $event) 
    { 
     // do something 
    } 

    /** 
    * Handle order updated events. 
    * 
    * @param OrderUpdatedEvent $event 
    */ 
    public function onOrderUpdate(OrderUpdatedEvent $event) 
    { 
     // do something 
    } 

    /** 
    * Register the listeners for the subscriber. 
    * 
    * @param $events 
    */ 
    public function subscribe($events) 
    { 
     $events->listen(
      'App\Events\OrderCreatedEvent', 
      'App\Listeners\[email protected]' 
     ); 

     $events->listen(
      'App\Events\OrderUpdatedEvent', 
      'App\Listeners\[email protected]' 
     ); 
    } 
} 

Ich werde marcus behalten.Ramsden Antwort wie markiert, aber das ist wahrscheinlich sehr relevant für Leute, die über diese Frage kommen.

Verwandte Themen