Laravel 5.5 - Сериализация моделей в событии вызывает ошибку идентификатора модели?


У меня есть мероприятие laravel с несколькими слушателями. Некоторые слушатели или их уведомления (в зависимости от того, отнимают ли они много времени) реализуют ShouldQueue, поэтому они запускаются в фоновом режиме в очереди redis. Событие использует SerializesModels по умолчанию, но когда одна из переданных моделей события является зарегистрированным пользователем, и мы запускаем ее, например:

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

Я не могу получить доступ к подписчикам пользователя в соответствующем прослушивателе, чтобы проверить, следует ли уведомлять их, если они существуют:

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

Я получаю эту ошибку:

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

Единственный способ, которым я смог заставить его работать, - это добавить пробуждение события ниже:

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
}

Я делаю использую экземпляр $user в нескольких других прослушивателях в рамках того же события и других прослушивателей событий. Я даже не знаю, следует ли вообще сериализовать $user, но это модель, поэтому признак родительского события SerializesModels автоматически сериализует все модели (и я не знаю, как сделать эту конкретную модель не сериализуется, в то время как другие модели да).

Есть ли лучший способ получить доступ к $user в прослушивателях без необходимости вообще выполнять вызов wakeup? У меня много событий со слушателями, и я только что приступил к реализации очередей, поэтому я действительно не хочу добавлять это wakeup во все области во всех файлах, где будет отображаться ошибка, но я хочу поставить в очередь некоторых слушателей или их уведомления. Альтернативой было бы удалить признак события SerializesModels и даже не беспокойтесь об этой ошибке, появляющейся под этим или любым другим слушателем, в котором мне еще предстоит обнаружить эту ошибку. Существуют ли какие-либо проблемы, которые могут возникнуть, например, с производительностью или другими, при реализации альтернативного подхода? Есть ли лучший способ?

Author: Wonka, 2018-03-30

1 answers

__wakeup() ( определенный в SerializesModels) на самом деле фреймворк должен вызываться, когда он отменяет сериализацию событий для выполнения их прослушивателей в очереди. Вся цель этой функции заключается в том, что она сохраняет идентификатор модели только в сериализованной строке (а не в других свойствах) и перезагружает модель из базы данных при несериализации. Это делается для экономии места в очереди, а также потому, что обработка очереди задерживается и свойства потенциально могут измениться. Так что ты никогда не захочешь сериализуйте всю модель со всеми ее свойствами для обработки очередей.

Это также означает, что вы можете сделать то же самое вручную, если хотите. Вместо того, чтобы передавать объекты модели событию, вы просто передаете ему некоторые идентификаторы и загружаете модели самостоятельно (что не намного больше, чем Model::find($id), верно?).

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

И в слушателе:

// 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...
}

Я должен признать, что я еще не знаком со слушателями событий в очереди, только с заданиями в очереди и тому подобным. Но из того, что вы описываете, я бы сказал, что где-то в фреймворке может быть ошибка. На самом деле в очереди находится не слушатель, а задание, которое вызывает слушателя, называется CallQueuedListener.

Если вы используете поведение, которое Laravel использует для прослушивателей в очереди, вы также можете использовать тот же подход самостоятельно: не ставьте прослушиватель событий в очередь, но позвольте прослушивателю создать задание в очереди, которое отправляет уведомления. Может быть, это работает лучше.

 2
Author: Namoshek, 2018-04-01 20:56:08