我有一个Laravel应用程序,为电子商务网站提供适度的流量.该网站允许人们通过前端下订单,但它还具有通过呼叫中心通过电话接听订单的后端功能.
订单与客户相关,客户可以选择是用户 - 用户是登录前端的用户.只有通过呼叫中心下达订单才能创建没有用户帐户的客户.
我遇到的问题非常奇怪,我相信可能是某种Laravel错误.
它只是偶尔发生,但正在发生的事情是,当通过呼叫中心为没有用户帐户的客户下订单时,订单确认将被发送给随机用户 - 字面意思是随机的,据我所知,尽管数据没有关系,但刚从数据库中拔出.
这些是项目中模型的相关部分:
class Order extends Model { public function customer() { return $this->belongsTo('App\Customer'); } } class Customer extends Model { public function orders() { return $this->hasMany('App\Order'); } public function user() { return $this->belongsTo('App\User'); } } class User extends Model { public function customer() { return $this->hasOne('App\Customer'); } }
这些是上面的数据库迁移(为简洁起见编辑):
Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('first_name'); $table->string('last_name'); $table->string('email')->unique(); $table->string('password', 60); $table->boolean('active'); $table->rememberToken(); $table->timestamps(); $table->softDeletes(); }); Schema::create('customers', function(Blueprint $table) { $table->increments('id'); $table->integer('user_id')->nullable->index(); $table->string('first_name'); $table->string('last_name'); $table->string('telephone')->nullable(); $table->string('mobile')->nullable(); $table->timestamps(); $table->softDeletes(); }); Schema::create('orders', function(Blueprint $table) { $table->increments('id'); $table->integer('payment_id')->nullable()->index(); $table->integer('customer_id')->index(); $table->integer('staff_id')->nullable()->index(); $table->decimal('total', 10, 2); $table->timestamps(); $table->softDeletes(); });
发送订单确认的逻辑位于支付订单后触发的事件处理程序中.
这是OrderSuccess
事件(为简洁起见编辑):
namespace App\Events; use App\Events\Event; use App\Order; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class OrderSuccess extends Event { use SerializesModels; public $order; /** * Create a new event instance. * * @return void */ public function __construct(Order $order) { $this->order = $order; } }
可以看出,此事件是传递给Order
模型对象的.
这是事件处理程序(为简洁起见编辑):
/** * Handle the event. * * @param OrderSuccess $event * @return void */ public function handle(OrderSuccess $event) { // set order to paid $order = $event->order; $order->paid = date('Y-m-d H:i:s'); $order->save(); if(!is_null($order->customer->user)) { App_log::add('customer_order_success_email_sent', 'Handlers\Events\OrderSuccessProcess\handle', $order->id, print_r($order->customer, true).PHP_EOL.print_r($order->customer->user, true)); // email the user the order confirmation Mail::send('emails.order_success', ['order' => $order], function($message) use ($order) { $message->to($order->customer->user->email, $order->customer->first_name.' '.$order->customer->last_name)->subject('Order #'.$order->id.' confirmation'); }); } }
检查$order->customer->user
对象是否为空,如果为true,则发送订单确认.如果它为null(经常是),则不发送确认.
从上面可以看出,我添加了一个日志来记录发送电子邮件时的对象.这是一个错误的例子(为简洁而再次截断):
App\Customer Object ( [attributes:protected] => Array ( [id] => 10412 [user_id] => [first_name] => Joe [last_name] => Bloggs [telephone] => 0123456789 [created_at] => 2015-09-14 13:09:45 [updated_at] => 2015-10-24 05:00:01 [deleted_at] => ) [relations:protected] => Array ( [user] => App\User Object ( [attributes:protected] => Array ( [id] => 1206 [email] => johndoe@whoknows.com [password] => hashed [remember_token] => [created_at] => 2015-09-19 09:47:16 [updated_at] => 2015-09-19 09:47:16 [deleted_at] => ) ) ) [morphClass:protected] => [exists] => 1 [wasRecentlyCreated] => [forceDeleting:protected] => ) App\User Object ( [attributes:protected] => Array ( [id] => 1206 [email] => johndoe@whoknows.com [password] => hashed [remember_token] => [created_at] => 2015-09-19 09:47:16 [updated_at] => 2015-09-19 09:47:16 [deleted_at] => ) [morphClass:protected] => [exists] => 1 [wasRecentlyCreated] => [forceDeleting:protected] => )
如您所见,没有user_id Customer
,但Laravel已经返回了一个User
对象.
更重要的是,如果我手动触发完全相同的OrderSuccess
事件,上面的内容是不可重现的 - 它不会发送电子邮件,也不会加载User
对象.
正如我之前所说,这个问题很少发生 - 通过呼叫中心平均每天约有40个订单,没有用户帐户的客户,突出显示的问题可能每周只发生一次或两次.
我对Laravel不太熟悉,不知道这里可能存在什么问题 - 它是某种形式的模型缓存,Eloquent ORM的问题,还是系统中的其他一些问题?
任何想法赞赏 - 我可能会在Laravel github问题跟踪器中发布此问题,如果它似乎是某种形式的错误.
更新关于提出的一些答案/评论,我试图删除任何潜在的Eloquent ORM问题,手动检索数据,如下所示:
$customer = Customer::find($order->customer_id); $user = User::find($customer->user_id); if(!is_null($user)) { // send email and log actions etc }
以上仍然产生相同的随机结果 - 即使客户没有user_id
(在这种情况下它是NULL),也会检索不相关的用户.
更新2由于第一次更新没有任何帮助,我恢复使用原始的Eloequent方法.为了尝试另一个解决方案,我从事件处理程序中取出了我的事件代码,并将其放在我的控制器中 - 我之前使用OrderSuccess事件触发Event::fire(new OrderSuccess ($order));
,而是我注释了这一行,并将事件处理程序代码放在控制器方法中:
$order = Order::find($order_id); //Event::fire(new OrderSuccess ($order)); // code from the above event handler $order->paid = date('Y-m-d H:i:s'); $order->save(); if(!is_null($order->customer->user)) { App_log::add('customer_order_success_email_sent', 'Handlers\Events\OrderSuccessProcess\handle', $order->id, print_r($order->customer, true).PHP_EOL.print_r($order->customer->user, true)); // email the user the order confirmation Mail::send('emails.order_success', ['order' => $order], function($message) use ($order) { $message->to($order->customer->user->email, $order->customer->first_name.' '.$order->customer->last_name)->subject('Order #'.$order->id.' confirmation'); }); }
上述更改已在生产站点上进行了一周以上 - 自此更改以来,没有一个问题的实例.
我能达到的唯一可能的结论是Laravel事件系统中的某种错误,以某种方式破坏了传递的对象.或者其他什么东西可以发挥作用?
更新3 似乎我说过在事件之外移动我的代码修复问题还为时过早 - 实际上,通过我的日志记录,在最近2天我可以看到更多不正确的订单确认被发送出去(总共5个,之后差不多3个星期没有问题).
我注意到收到恶意订单确认的用户ID似乎正在递增(不是没有间隙,但仍然按升序排列).
我还注意到每个问题订单都是通过现金和账户信用支付的 - 大多数只是现金.我进一步研究了这个,用户ID实际上是相关信用交易的ID!
以上是试图解决这一问题的第一次铸铁突破.经过仔细检查,我可以看到问题仍然是随机的 - 有很多(至少50%)订单已通过帐户信用支付给没有用户帐户的客户,但没有导致发送不正确的电子邮件out(尽管相关的信用交易ID具有用户id匹配).
所以,问题仍然是随机的,或者看似如此.我的信用兑换事件是这样触发的:
Event::fire(new CreditRedemption( $credit, $order ));
在我的OrderSuccess
事件之前调用上面的内容- 正如您所看到的,两个事件都传递给$order
模型对象.
我的CreditRedemption
事件处理程序如下所示:
public function handle(CreditRedemption $event) { // make sure redemption amount is a negative value if($event->credit < 0) { $amount = $event->credit; } else { $amount = ($event->credit * -1); } // create the credit transaction $credit_transaction = New Credit_transaction(); $credit_transaction->transaction_type = 'Credit Redemption'; $credit_transaction->amount = $amount; // negative value $credit_transaction->customer_id = $event->order->customer->id; $credit_transaction->order_id = $event->order->id; // record staff member if appropriate if(!is_null($event->order->staff)) { $credit_transaction->staff_id = $event->order->staff->id; } // save transaction $credit_transaction->save(); return $credit_transaction; }
该$credit_transaction->save();
是产生在我的ID credit_transactions
以某种方式被使用Laravel检索用户对象表.从上面的处理程序中可以看出,我不会$order
在任何时候更新我的对象.
Laravel如何使用(记住,仍然是随机的,一些<50%的时间)我新创建的id $credit_transaciton
来填充$order->customer->user
模型对象?