Laravel队列数据未从构造函数传递到处理程序

时间:2019-04-08 21:42:45

标签: php laravel queue laravel-queue

我在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的文档说要在工作中将变量声明为受保护的变量,但我也已经尝试将它们作为公共变量使用。同样的问题。我已经没有主意了。我做错了什么?

2 个答案:

答案 0 :(得分:2)

您的口才模型集合结构不正确。因此,Laravel无法在作业运行时正确地对其进行序列化以进行分发和反序列化。

当您将雄辩的模型(或模型集合)发送到队列作业时,Laravel仅在调度作业时序列化模型的ID。处理完作业后,它将获取ID并从数据库中检索数据。

在这种情况下,您的$subscribersParticipantesEvento模型的雄辩的集合。同样,由于您的查询,模型拥有的唯一数据是用户的姓名和电子邮件。因此,当Laravel尝试序列化此集合的键时,将找不到任何键。

即使您确实更新了查询以在模型上包含participantes_eventos.id字段,运行作业时,您的subscribers属性也将是ParticipantesEvento模型的新集合,而无需包含用户数据从您的原始查询。

您的代码显示,您真正希望$subscribers成为事件附属的用户。假设您已建立了雄辩的关系,则只需执行以下操作即可:

$subscribers = $event->users;

如果没有设置人际关系,请将其添加到您的Evento模型中。这样会通过participantes_eventos表将many-to-many relationship从事件设置到用户。

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

您也可以对证书执行相同的操作。将此方法添加到您的Evento模型中,以设置从事件到证书的one-to-one relationship

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

然后像这样使用它:

$certificate = $event->certificate;

答案 1 :(得分:1)

好吧...似乎在执行作业时,SerializesModels重复对Model的查询,由于某种原因,它变得很糟糕。我做了一个解决方法... 在我分派工作的函数中,我没有将模型传递给工作,而是对结果进行了排列。并将此数组传递给作业。这样,作业将不会重复查询,而只是读取收到的静态数组:

$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重做查询的优点是从数据库中获取更新的数据。例如:如果用户在之后之后在其寄存器中更改了您的电子邮件或姓名,我会将静态数组发送给该作业,则在该作业执行时,它将使用过时的用户信息。

但是,它暂时起到了作用……而我认为这是一个更优雅的解决方案。感谢所有的帮助!