2016-11-29 19 views
2

我有一个名为RecordsUserActivity的特性,它基本上在用户创建,更新或删除使用此特征的某些内容时在活动表中创建一条记录。这里是代码:Laravel模型事件的多个侦听器

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

然后,我有另一个特性,记录使用它的模型的属性更改。下面是代码:

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

} 

当我包括模型两个性状出现的问题和更新而成,有某种既更新模型事件发生碰撞。有没有办法解决这个问题,或者我应该找出另一种解决方案?

回答

3

如果您尝试在同一模型上使用这两个特征,则应该会出现错误,指出Trait method boot has not been applied, because there are collisions with other trait methods...

无论如何,你不希望你的特质定义boot()方法。 Laravel的Model有一个特殊的惯例,如果你有一个特征需要钩入boot方法。基本上,在你的特质中,定义一个格式为boot{traitName}的方法。此外,用两种方法删除对parent::boot()的呼叫。在Model引导时,基于Modelboot()方法将调用符合此格式的方法。

所以,你的特质应该是这样的:

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

它的工作原理,谢谢! – Alan

1

据laravel文档,管理模型事件,你应该使用,Laravel Model Observers这样的:

<?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) 
    { 
     // 
    } 
} 

,并注册您的观察员,使用上要观察模型的观察方法。您可以将观察员注册到您的某个服务提供商的启动方法中。在这个例子中,我们将在AppServiceProvider中注册观察者:

<?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() 
    { 
     // 
    } 
} 

希望这有助于!

+0

此解决方案不解决我的问题。首先,这两种特性的灵活性是,如果我需要跟踪创建,更新和从某个对象中删除,我只需添加“使用RecordsUserActivity”并完成魔术。无论如何,如果我有两个观察者在观察示例更新事件并将它们应用于单个对象,那么会发生事件冲突?谢谢你的时间。 – Alan