在仍然绑定到已创建的事件时附加多对多关系

问题描述 投票:0回答:2

所以我几次遇到这个问题,现在我已经决定要找到更好的解决方案了。

例如,我有两个模型,OrderProduct。存在多对多的关系,因此订单可以具有多个产品,并且产品当然可以具有多个订单。表结构如下所示 -

命令

  • ID
  • 更多领域......

制品

  • ID
  • 更多领域......

product_orders

  • ORDER_ID
  • PRODUCT_ID

因此,当创建订单时,我运行以下 -

$order = Order::create($request->validated())
$order->products()->attach([1,2,3,4...]);

因此,这会创建一个订单并将相关产品附加到其上。

但是,我想使用观察者,确定订单何时创建并发送并执行相关任务(发送订单确认电子邮件等)问题是,在订单创建观察者被触发时,产品尚未附加。

有没有办法做到这一点,建立所有多对多关系并同时创建订单,以便我可以访问Order创建的观察者中的链接产品?

用例1

AJAX调用命中PUT / api / order,后者又调用Order::place()方法。创建订单后,会向下订单的客户发送电子邮件。现在我可以在这个方法中放一个事件调度,然后触发电子邮件发送但这只是感觉有点hacky。

public static function place (SubmitOrderRequest $request)
{
    $order = Order::create($request->validated());

    $order->products()->attach($request->input('products'));

    return $order;
}

用例2

我正在进行功能测试,以确保在创建订单时发送电子邮件。现在,此测试通过(并且电子邮件发送工作),但是在执行的此时它无法输出链接的产品。

/**
 * @test
 **/
public function an_email_is_sent_on_order_creation()
{
    Mail::fake();

    factory(Order::class)->create();

    Mail::assertSent(OrderCreatedMailable::class);
}


Thanks,
Chris.
laravel laravel-5 laravel-5.7
2个回答
1
投票

我认为你的问题的解决方案可能是this package from fntneves提供的交易事件。

就个人而言,我偶然发现了交易事件的想法。我遇到的问题是,在创建特定实体后,我的业务逻辑需要执行一些排队的作业。因为我的实体是在事务中批量创建的,所以有可能触发了一个事件(并且相应的事件侦听器已经排队),尽管该事务由于之后不久发生了错误而被回滚。结果是总是失败的排队听众。

您的方案似乎与我相当,因为您不希望由于缺少数据而立即执行您的事件侦听器,这些数据仅在实际创建模型后附加。出于这个原因,我建议包装您的订单创建以及在交易中操纵订单的所有其他任务。结合所述包的使用,您可以触发模型创建的事件,因为只有在提交事务后才会调用实际的事件侦听器。所有这些的代码基本上归结为您已经描述的内容:

DB::transaction(function() {
    $order = Order::create($request->validated());
    $order->products()->attach($request->input('products'));
});

在您的模型中,您只需定义一个OrderCreated事件或使用另一个答案中建议的观察者:

class Order
{
    protected $dispatchesEvents = [
        'created' => OrderCreated::class,
    ];
}

class OrderCreated implements TransactionalEvent
{
     public $order;

    /**
     * Create a new event instance.
     *
     * @param  \App\Order  $order
     * @return void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }
}

0
投票

如果产品ID是静态的,您可以在模型中重新定义boot方法

class Order extends Eloquent {

   protected static function boot() {
      parent::boot();

      static::saving(function ($user) {
        $this->products()->attach([1,2,3,4...]);
      });
    }
}

或者使用observers

class OrderObserver 
{
    public function created($model)
    {
          //
    }
}

注册这个

class EventServiceProvider extends ServiceProvider
{
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);

        Order::observe(new OrderObserver());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.