2016-11-29 3 views
2

Ich habe eine Eigenschaft RecordsUserActivity genannt, die im Grunde einen Datensatz in einer Tabelle Aktivitäten erstellen, wenn ein Benutzer erstellt, aktualisiert oder löscht etwas, das dieses Merkmal verwendet. Hier ist der Code:Laravel mehrere Zuhörer für ein Modell Ereignis

trait RecordsUserActivity 
{ 
    protected static function boot() 
    { 
     parent::boot(); 
     foreach (static::getModelEvents() as $event) { 
      static::$event(function ($model) use ($event) { 
       $model->addActivity($event); 
      }); 
     } 
    } 

    protected function addActivity($event) 
    { 
     $newActivity = [ 
      'subject_id' => $this->id, 
      'subject_type' => get_class($this), 
      'action' => $event, 
      'user_id' => (Auth::id()) ?? null, 
     ]; 

     if ($event == 'updated') { 
      $newActivity['data'] = json_encode($this->getDirty()); 
     } 

     UserActivity::create($newActivity); 
    } 

    protected static function getModelEvents() 
    { 
     if (isset(static::$recordEvents)) { 
      return static::$recordEvents; 
     } 

     return ['created', 'deleted', 'updated']; 
    } 
} 

Dann habe ich eine andere Eigenschaft, die Eigenschaft Änderungen in Modellen, die es verwendet. Hier ist der Code:

trait RecordsPropertyChangelog 
{ 
    protected static function boot() 
    { 
     parent::boot(); 

     static::updated(function ($model){ 
      $model->addPropertiesChangelog(); 
     }); 
    } 

    protected function addPropertiesChangelog() 
    { 
     $dirty = $this->getDirty(); 
     foreach ($dirty as $field => $newData) { 
      $oldData = $this->getOriginal($field); 
      $this->addPropertyChangelog($field,$oldData,$newData); 
     } 
    } 

    protected function addPropertyChangelog($fieldName,$oldValue,$newValue) 
    { 
     PropertyChangelog::create([ 
      'resource_id' => $this->id, 
      'resource_type' => get_class($this), 
      'property' => $fieldName, 
      'from_value' => $oldValue, 
      'to_value' => $newValue, 
      'data' => '{}', 
     ]); 
    } 

} 

Das Problem erscheint, wenn ich beiden Züge in einem Modell enthalten und ein Update durchgeführt wird, gibt es eine Art von Kollision mit beiden aktualisierten Modellen Ereignissen. Gibt es einen Weg, das zu beheben, oder sollte ich eine andere Lösung finden?

Antwort

3

Wenn Sie versuchen, beide Merkmale auf demselben Modell zu verwenden, sollten Sie einen Fehler erhalten, der Trait method boot has not been applied, because there are collisions with other trait methods... angibt.

Auf jeden Fall wollen Sie nicht Ihre Züge die boot() Methode zu definieren. Laravel's Model hat eine spezielle Konvention, wenn Sie eine Eigenschaft haben, die in die boot Methode einhaken muss. Definieren Sie in Ihrem Merkmal eine Methode im Format boot{traitName}. Entfernen Sie außerdem den Aufruf an parent::boot() in beiden Methoden. Die boot() Verfahren auf der Basis Model werden Methoden aufrufen, die diesem Format entsprechen, wenn die Model gebootet wird.

Also, sollten Sie Ihre Züge wie folgt aussehen:

trait RecordsUserActivity 
{ 
    protected static function bootRecordsUserActivity() 
    { 
     foreach (static::getModelEvents() as $event) { 
      static::$event(function ($model) use ($event) { 
       $model->addActivity($event); 
      }); 
     } 
    } 

    //... 
} 

trait RecordsPropertyChangelog 
{ 
    protected static function bootRecordsPropertyChangelog() 
    { 
     static::updated(function ($model) { 
      $model->addPropertiesChangelog(); 
     }); 
    } 

    //... 
} 
+0

es funktioniert, danke! – Alan

1

Nach Laravel docs, für die Verwaltung von Modell Ereignisse sollten Sie Laravel Model Observers wie folgt verwenden,:

<?php 

namespace App\Observers; 

use App\User; 

class UserObserver 
{ 
    /** 
    * Listen to the User created event. 
    * 
    * @param User $user 
    * @return void 
    */ 
    public function created(User $user) 
    { 
     // 
    } 

    /** 
    * Listen to the User deleting event. 
    * 
    * @param User $user 
    * @return void 
    */ 
    public function deleting(User $user) 
    { 
     // 
    } 
} 

und Ihre Beobachter zu registrieren, wobei das Verfahren auf die Sie beobachten wollen Modell beobachten verwenden. Sie können Beobachter in der Boot-Methode eines Ihrer Dienstanbieter registrieren. In diesem Beispiel werden wir die Beobachter im AppServiceProvider registrieren:

<?php 

namespace App\Providers; 

use App\User; 
use App\Observers\UserObserver; 
use Illuminate\Support\ServiceProvider; 

class AppServiceProvider extends ServiceProvider 
{ 
    /** 
    * Bootstrap any application services. 
    * 
    * @return void 
    */ 
    public function boot() 
    { 
     User::observe(UserObserver::class); 
    } 

    /** 
    * Register the service provider. 
    * 
    * @return void 
    */ 
    public function register() 
    { 
     // 
    } 
} 

hoffe, das hilft!

+0

Diese Lösung nicht mein Problem nicht löst. An erster Stelle die Flexibilität beider Eigenschaften ist, dass, wenn ich die Erstellung, Aktualisierung und Löschung von einem Objekt verfolgen muss, ich einfach "Use RecordsUserActivity" hinzufügen und die Magie ist getan. Anyway Wenn ich zwei Beobachter habe, die im Beispiel das Ereignis aktualisieren und sie auf ein einzelnes Objekt anwenden, wird es keine Ereigniskollision geben? Vielen Dank für Ihre Zeit. – Alan

Verwandte Themen