Laravel 附加多对多关系,同时仍绑定到创建的事件
所以我已经多次遇到这个问题,现在我决定要找到一个更好的解决方案 例如,我有两种型号,Laravel 附加多对多关系,同时仍绑定到创建的事件,laravel,laravel-5,laravel-5.7,Laravel,Laravel 5,Laravel 5.7,所以我已经多次遇到这个问题,现在我决定要找到一个更好的解决方案 例如,我有两种型号,订单和产品。存在多对多关系,因此一个订单可以有多个产品,一个产品当然可以有多个订单。表结构如下所示- 命令 身份证 更多领域 产品 身份证 更多领域 产品订单 订单号 产品标识 因此,当创建订单时,我运行以下命令- $order = Order::create($request->validated()) $order->products()->attach([1,2,3,4...]
订单
和产品
。存在多对多关系,因此一个订单可以有多个产品,一个产品当然可以有多个订单。表结构如下所示-
命令
- 身份证
- 更多领域
- 身份证
- 更多领域
- 订单号
- 产品标识
$order = Order::create($request->validated())
$order->products()->attach([1,2,3,4...]);
因此,这将创建一个订单并将相关产品附加到该订单上
但是,我想使用一个观察者来确定订单何时创建,何时发送并执行相关任务(发送订单确认电子邮件等)。问题是,在触发订单创建观察者时,产品尚未连接
有没有办法做到这一点,建立所有多对多关系,同时创建订单,这样我就可以访问订单中的链接产品
用例1
AJAX调用点击PUT/api/order,后者依次调用order::place()
方法。创建订单后,将向下订单的客户发送电子邮件。现在我可以在这个方法中添加一个事件调度,它反过来会触发电子邮件发送,但这感觉有点不对劲
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.
如果产品ID是静态的,您可以在模型中重新定义
boot
方法
class Order extends Eloquent {
protected static function boot() {
parent::boot();
static::saving(function ($user) {
$this->products()->attach([1,2,3,4...]);
});
}
}
或使用
注册这个
class EventServiceProvider extends ServiceProvider
{
public function boot(DispatcherContract $events)
{
parent::boot($events);
Order::observe(new OrderObserver());
}
}
我认为您的问题的解决方案可以是提供的事务事件 就我个人而言,我偶然发现交易性事件的想法还有另一个原因。我的问题是,我的业务逻辑需要在创建特定实体后执行一些排队作业。因为我的实体是在一个事务中批量创建的,所以有可能触发了一个事件(并且相应的事件侦听器已排队),尽管该事务不久后由于一个错误而回滚。结果是排队的侦听器总是失败 您的场景似乎与我类似,因为您不想立即执行事件侦听器,因为缺少的数据仅在实际创建模型后附加。因此,我建议在事务中包装订单创建和所有其他操作订单的任务。结合使用上述包,您可以触发模型创建的事件,因为实际的事件侦听器只有在事务提交后才会被调用。所有这些的代码基本上可以归结为您已经描述的代码:
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;
}
}
如果您正在使用观察者收听事件,并且当前事件列表不是您想要的。在创建订单并添加所有产品后,您能否不抛出一个新事件?比如在这里@RobBiermann-当然可以,但出于测试目的等,我希望有一个标准事件。比如说,在测试中,我使用数据库种子设定创建了一个订单,但在生产中,我在订单上有一个名为
place
的方法,我需要在两个位置触发该事件扫描您在问题描述中发布两个用例?这有助于找到解决方案:)我认为可以归结为在函数中触发事件,然后在播种器和模型(位置)函数中使用该函数。但现在这只是猜测:)@RobBiermann我添加了几个用例。如前所述,我可以在Order::place()
中触发一个事件,但感觉不对劲——也许是我太爱写代码了?!不幸的是,实际上产品ID是动态的。感谢您的输入,您可以在observer中使用user request(),例如,这正是我想要的!因此,通过使用此包,并在事务中包装订单创建和产品附加,我可以确保我的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;
}
}