Данные очереди 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 сказано объявлять переменные как защищенные в задании, я уже пробовал использовать их как общедоступные. Та же проблема. У меня уже закончились идеи. Что я делаю не так??

Можете просто попробовать поставить $this->subscribers = clone $s;, просто посмотреть, что получится?

GTCrais 09.04.2019 00:59

@GTCrais Пробовал. Не работает... =/

André Raubach 09.04.2019 01:06

Если это поможет... Обе переменные являются информацией из базы данных. Единственная разница между проблемной переменной и другими состоит в том, что это коллекция со многими подписчиками. Два других имеют по одному регистру (одно событие и один сертификат).

André Raubach 09.04.2019 01:09

Попробуйте $this->subscribers = "whatever"; подтвердить/устранить проблему в параметре $s.

GTCrais 09.04.2019 01:14

Я уже делал этот тест. При присвоении любого «любого» значения $this->subscribers в конструкторе значение обычно отображается в обработчике.

André Raubach 09.04.2019 01:27

@GTCrais Я включил в вопрос происхождение данных, переданных в задание.

André Raubach 09.04.2019 01:31

Хм... ну, я предполагаю, что по какой-то причине он не может сериализовать подписчиков. Проверьте черту SerializesModels и попробуйте вручную сериализовать/десериализовать подписчиков, чтобы посмотреть, что произойдет... это единственное, что я могу придумать. Однако он должен иметь возможность сериализовать коллекцию моделей Eloquent...

GTCrais 09.04.2019 01:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
7
2 084
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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;

У меня нет этой структуры. У меня есть таблица eventos, в которой есть «id», «имя», «описание» и т. д. У меня есть таблица users, в которой есть «id», «имя» и «электронная почта». И у меня есть таблица participantes_evento, которая "объединяет" подписчиков каждого "evento" системы, имеющая поля "id", "evento_id" и "user_id". Использовать $subscribers = $evento->users; в этой структуре не получится (да, я знаю, что это не самая правильная структура, но с этим мне приходится иметь дело).

André Raubach 09.04.2019 02:10

Я только что нашел обходной путь для этой проблемы.... но я постараюсь сделать это и вернуться, если это сработает.

André Raubach 09.04.2019 02:40

БИНГО! Это отлично работает, чувак! Большое спасибо за помощь! Просто добавьте return в функцию certificate(), иначе будет выдано исключение. Я отмечу ответ как правильный! Спасибо еще раз!

André Raubach 09.04.2019 02:54

@AndréRaubach Тьфу, извините за опечатку и спасибо за редактирование. Но да, то, что вы описали, — это отношения «многие ко многим», где таблица participantes_evento — это сводная таблица, которая связывает многих пользователей со многими событиями, и наоборот. Отношения belongsToMany — это то, как вы моделируете это в красноречии. Рад, что у вас все заработало!

patricus 09.04.2019 06:37

Ну... кажется, что когда задание выполняется, 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/e60d6a932db98985f160146b09455988 , преимущество повторного выполнения запроса SerializesModel заключается в получении обновленных данных из базы данных. Например: если пользователь изменит ваш адрес электронной почты или имя в своем регистре после, я отправлю статический массив в задание, когда задание будет выполнено, оно будет работать с устаревшей информацией о пользователе.

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

Другие вопросы по теме