Данные очереди Laravel не передаются от конструктора к обработчику

У меня проблема с заданием в очереди Laravel 5.6. Я передаю конструктору 3 аргумента. На этом этапе я проверил, и все аргументы содержат данные. Но когда я запускаю задание, один из них в обработчике пуст.

Это функция, которая отправляет задание:

public function send() {
    $event = Evento::find($id);
    $subscribers = ParticipantesEvento::join('users', 'participantes_eventos.user_id', '=', 'users.id')
           ->select('users.name', 'users.email')
           ->where('evento_id', '=', $evento->id)
           ->get();
    $certificate = Certificado::where('evento_id', '=', $evento->id)->first();

    dispatch(new SendCertificatesByEmail($subscribers, $event, $certificate));

    return redirect()->back()->with('success', 'Fazendo os paranauê...');
}

Это работа:

namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class SendCertificatesByEmail implements ShouldQueue {

    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $subscribers, $events, $certificate;

    public function __construct($s, $e, $c) {
        $this->subscribers = $s;
        $this->events      = $e;
        $this->certificate = $c;

        print_r($this->subscribers);   // Have data
        print_r($this->events);        // Have data
        print_r($this->certificate);   // Have data
    }

    public function handle() {
        print_r($this->subscribers);    // IS EMPTY!!!
        print_r($this->events);         // Have data
        print_r($this->certificate);    // Have data
    }
}

Хотя в документации Laravel говорится, что переменные должны быть объявлены защищенными в задании, я уже пробовал использовать их как общедоступные. Та же проблема. У меня уже нет идей. Что делаю не так ??


person André Raubach    schedule 08.04.2019    source источник
comment
Можешь просто попробовать поставить $this->subscribers = clone $s;, просто посмотреть, что из этого получится?   -  person GTCrais    schedule 09.04.2019
comment
@GTCrais Пробовал. Не работает ... = /   -  person André Raubach    schedule 09.04.2019
comment
Если это поможет ... Обе переменные - это информация из базы данных. Единственная разница между проблемной переменной и другими заключается в том, что это коллекция с большим количеством подписчиков. У двух других есть только один регистр (одно событие и один сертификат).   -  person André Raubach    schedule 09.04.2019
comment
Попробуйте $this->subscribers = "whatever"; подтвердить / устранить проблему, связанную с параметром $s.   -  person GTCrais    schedule 09.04.2019
comment
Я уже сделал этот тест. Если присвоить $this->subscribers любое значение в конструкторе, значение будет нормально отображаться в обработчике.   -  person André Raubach    schedule 09.04.2019
comment
@GTCrais Я включил в вопрос происхождение данных, переданных в задание.   -  person André Raubach    schedule 09.04.2019
comment
Хм ... ну, я полагаю, он по какой-то причине не может сериализовать подписчиков. Посмотрите черту SerializesModels и попробуйте вручную сериализовать / десериализовать подписчиков, чтобы увидеть, что произойдет ... это единственное, что я могу придумать. Однако он должен иметь возможность сериализовать коллекцию моделей Eloquent ...   -  person GTCrais    schedule 09.04.2019


Ответы (2)


Ваша коллекция красноречивых моделей построена неправильно. Из-за этого Laravel не может должным образом сериализовать их для отправки и десериализовать при выполнении задания.

Когда вы отправляете красноречивую модель (или коллекцию моделей) в задание очереди, Laravel сериализует идентификаторы моделей только при отправке задания. Когда задание затем обрабатывается, оно берет идентификаторы и извлекает данные из базы данных.

В данном случае ваша $subscribers представляет собой красноречивую коллекцию ParticipantesEvento моделей. Кроме того, из-за вашего запроса единственные данные, которые есть у ваших моделей, - это имя и адрес электронной почты пользователя. Итак, когда Laravel попытается сериализовать ключи этой коллекции, он их не найдет.

Даже если вы обновите свой запрос, чтобы включить поле participantes_eventos.id в модель, при запуске задания ваше свойство subscribers будет новой коллекцией моделей ParticipantesEvento без пользовательских данных, которые вы включили из исходного запроса.

Ваш код показывает, что вы действительно хотите, чтобы ваш $subscribers был пользователями, привязанными к событию. Предполагая, что у вас настроены красноречивые отношения, вы можете просто сделать это:

$subscribers = $event->users;

Если у вас нет настроек отношений, добавьте это в свою Evento модель. Это устанавливает связь "многие ко многим" из событий. пользователям через participantes_eventos таблицу.

public function users()
{
    return $this->belongsToMany(User::class, 'participantes_eventos');
}

То же самое можно сделать и с сертификатом. Добавьте этот метод в свою модель Evento, чтобы установить связь «один-к-одному». от события к сертификату:

public function certificate()
{
    return $this->hasOne(Certificado::class);
}

А потом используйте это так:

$certificate = $event->certificate;
person patricus    schedule 08.04.2019
comment
У меня нет этой структуры. У меня есть таблица eventos с идентификатором, именем, описанием и т. Д. У меня есть таблица users с идентификатором, именем и адресом электронной почты. И у меня есть participantes_evento таблица, которая объединяет подписчиков каждого события системы, имея поля 'id', 'evento_id' и 'user_id'. Использование $subscribers = $evento->users; не будет работать в этой структуре (да, я знаю, что это не самая правильная структура, но это то, с чем я должен иметь дело). - person André Raubach; 09.04.2019
comment
Я только что нашел способ обойти проблему ... но я постараюсь сделать это и вернуться, если это сработает. - person André Raubach; 09.04.2019
comment
БИНГО! Это прекрасно работает, чувак! Большое спасибо за помощь! Просто добавьте return в функцию certificate(), иначе будет выдано исключение. Отмечу ответ как правильный! Спасибо еще раз! - person André Raubach; 09.04.2019
comment
@ AndréRaubach Ух, извините за опечатку и спасибо за редактирование. Но да, то, что вы описали, является отношением «многие ко многим», где participantes_evento таблица является сводной таблицей, которая связывает множество пользователей со многими событиями, и наоборот. Отношения belongsToMany - это то, как вы красноречиво моделируете это. Рад, что у вас все получилось! - person patricus; 09.04.2019

Что ж ... похоже, что когда задание выполняется, SerializesModels повторяет запрос модели, и по какой-то причине он выходит из строя. Я нашел обходной путь ... В функции, в которой я отправляю задание, вместо передачи модели в задание я создал массив с результатом. И передаем этот массив в задание. Таким образом, задание не будет повторять запрос, а просто прочитает полученный статический массив:

$inscritos = ParticipantesEvento::join('users', 'participantes_eventos.user_id', '=', 'users.id')
    ->select('users.name', 'users.email')
    ->where('evento_id', '=', $evento->id)
    ->get();

$insc = array();
foreach ($inscritos as $inscrito) {
    $insc[] = $inscrito;
}

Но...

ВНИМАНИЕ:

В некоторых случаях это может вызвать проблемы. Как сказано в этой статье: https://gistlog.co/JacobBennett/e60d6a932db14985 SerializesModel повторить запрос - это взять обновленные данные из базы данных. Например: если пользователь изменит ваш адрес электронной почты или имя в своем реестре после, я отправлю статический массив в задание, когда задание будет выполнено, оно будет работать с устаревшей информацией пользователя.

Однако на данный момент это сработало ... пока я думаю, что это более элегантное решение этой проблемы. Спасибо всем, что помогло!

person André Raubach    schedule 09.04.2019