dongsaohu6429 2018-03-30 20:04
浏览 272
已采纳

Laravel 5.5 - 事件上的SerializesModels导致ModelIdentifier错误?

I have a laravel event with a few listeners. Some listeners or their notifications (depending if they are time consuming) are implementing the ShouldQueue so they run in the background on a redis queue. The event uses SerializesModels by default, but when one of the passed models to the event is the logged in user and we fire it, like this:

$user = $this->user(); // logged in user instance
event(new UserCreatedPost($user, $post, $modelX, $modelY));

I am not able to access the user's followers in the respective listener, to check whether or not to notify them if they exist:

// In listener handle method
public function handle(UserCreatedPost $event){
    $followers = $event->user->followers()->get();
}

I get this error:

Call to undefined method Illuminate\Contracts\Database\ModelIdentifier::followers()

The only way I was able to get it to work was to add event wakeup below:

public function handle(UserCreatedPost $event){
    // This fixes it, as it unserializes all the models
    // (even though we only need this model to be unserialized, not all of them)
    $event->__wakeup();


    $followers = $event->user->followers()->first();
    // If at least one follower exists send queued notification
    // else exit
}

I do use the $user instance in a few other listeners under the same event and other event listeners. I don't even know if the $user should be serialized in the first place at all, but it is a model, so the parent event SerializesModels trait automatically serializes all the models (and I don't know of any way to make this specific model not be serialized while other models yes).

Is there a better way to be able to access the $user in the listeners without having to do the wakeup call at all? I have many events with listeners, and just got to implementing queues now, so I really don't want to add that wakeup to all areas in all files that the error would appear, but I do want to queue some of the listeners or their notifications. An alternative would be to remove the event SerializesModels trait and not even worry about that error showing up under this or any other listener I have yet to discover this error in. Are there any issues that can arise, like performance for example or others, by implementing the alternative approach? Any better way?

  • 写回答

1条回答 默认 最新

  • douyang2530 2018-04-01 20:56
    关注

    __wakeup() (defined in SerializesModels) should actually be called by the framework when it unserializes events to execute their queued listeners. The whole purpose of this trait is that it only stores the model identifier in the serialized string (and not other properties) and reloads the model from the database when being unserialized. This is done to save space in the queue, but also because queue processing is delayed and properties can potentially change. So you never want to serialize the whole model with all its properties for queue processing.

    This also means, you can do the very same thing manually, if you want. Instead of passing model objects to the event, you just pass some identifiers to it instead and load the models yourself (which isn't much more than Model::find($id), right?).

    $user = $this->user(); // logged in user instance
    event(new UserCreatedPost($user->id, $post->id, $modelX->id, $modelY->id));
    

    And in the listener:

    // In listener handle method
    public function handle(UserCreatedPost $event){
        $user = User::find($event->user);
        $followers = $user->followers()->get();
    
        // the other stuff you want to do...
    }
    

    I have to admit that I'm not familiar with queued event listeners yet, only with queued jobs and similar. But from what you describe, I would say there might be a bug in the framework somewhere. Actually queued is not the listener but a job that calls the listener, called CallQueuedListener.

    If you take the behavior Laravel utilizes for queued listeners, you could also use the same approach yourself: Don't queue the event listener, but let the listener create a queued job that sends the notifications. Maybe this works better.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里