所以我几次遇到这个问题,现在我已经决定要找到更好的解决方案了。
例如,我有两个模型,Order
和Product
。存在多对多的关系,因此订单可以具有多个产品,并且产品当然可以具有多个订单。表结构如下所示 -
命令
制品
product_orders
因此,当创建订单时,我运行以下 -
$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.
我认为你的问题的解决方案可能是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;
}
}
如果产品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());
}
}