2016-06-03 31 views
9

Sto tentando di sincronizzare il mio database con un servizio esterno.Eventi a più modelli di Laravel

Sto utilizzando la ricerca Algolia in un paio di posti in un'applicazione web.

È indicizzato con un paio di modelli, ma è necessario indicizzarlo nuovamente nel caso in cui vengano apportate modifiche al database, ad esempio quando vengono generati più eventi del modello.

Il mio primo approccio è stato quello di azione tutto all'interno del avvio metodo AppServiceProvider

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

Questo è il mio approccio al fine di evitare più condizionali utilizzando le funzioni del modello standard exampled nel docs.

Tuttavia, suppongo che ci sia un modo migliore di utilizzare gli ascoltatori di eventi di Laravel.

namespace App\Listeners; 

class OrderEventListener 
{ 
    // handlers 

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

Anche se io sono sicuro come sfruttare gli eventi del modello nel ascoltare metodo.

risposta

7

Consiglio vivamente di aggiungere il proprio evento e gestore per questa situazione.

Nei tuoi Product e Order classi è possibile ignorare il metodo boot del modello:

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

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

Avrai bisogno di creare il proprio ProductCreatedEvent oggetto. Ora nello EventServiceProvider si vorrà aggiungere all'array degli ascoltatori;

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

Una volta impostata questa funzione si può effettivamente eseguire php artisan event:generate e questo creerà l'oggetto evento e chi ascolta per voi. Salterò l'oggetto evento in quanto è piuttosto semplice che preleva il prodotto che è stato creato e lo invia al listener UpdateAlgoliaProductIndex.

Ora nel vostro ascoltatore si avrà qualcosa di simile al seguente:

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

La ragione per cui vi consiglio di questo approccio è che si può poi fare la fila l'ascoltatore utilizzando l'interfaccia ShouldQueue, il che significa che non bloccare la richiesta in attesa che la tua app venga reindirizzata con Algolia e che porti a un'esperienza migliore per i tuoi utenti.

È possibile leggere ulteriori informazioni sugli oggetti evento e sugli ascoltatori here.

Un'opzione alternativa è utilizzare un model observer.

+0

Ho fatto questo genere di cose per le notifiche, ad es. un prodotto viene aggiornato viene lanciato un 'ProductCreatedEvent'. Sto bene con questo perché ho bisogno solo di attivarlo con 'self :: updated()' nel metodo di avvio come si mostra. Tuttavia qualcosa come la reindicizzazione qui dovrebbe essere eseguito ogni volta che viene sparato un evento modello e stavo cercando una soluzione che non richiedesse di elencare ogni evento del modello con ascoltatori, gestori, ecc. Successivi essere migliore per creare un lavoro e inviarlo in avvio? Quindi può ancora implementare ShouldQueue ma verrà sempre attivato. –

+1

Se vuoi che ogni evento del modello tu abbia più fortuna se guardi per 'saved' piuttosto che' created'. 'ShouldQueue' rimuove la necessità di definire un oggetto Job aggiuntivo. Se non vuoi eseguirlo istantaneamente suggerirei semplicemente di aggiungere un campo 'requires_search_indexing' al tuo oggetto prodotto. Quindi è possibile che un cron job esegua una scansione periodicamente, al fine di raggruppare gli aggiornamenti. –

+0

Questo è un buon punto. Lo prendo se vuoi una via di mezzo che stai ancora sostenendo per l'utilizzo di tutti gli ascoltatori di eventi. Laravel 5.2 sembra aver abbandonato gli osservatori modello dai documenti, il che mi fa pensare se non stiano più raccomandando l'approccio. –

0

Con alcuni scavi ho trovato l'evento Laravel subscribers che è più simile a quello che stavo cercando, quindi l'ho inviato come risposta.

Penso che questo produca un codice più conciso rispetto agli ascoltatori per ogni evento.

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

Conserverò marcus.risposta di Ramsden come indicato ma questo è probabilmente molto rilevante per le persone che si imbattono in questa domanda.