我有一个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
对象是否不为null,如果为true,则发送订单确认。如果为null(通常为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] =>
)
如您所见,
Customer
没有user_id,但是Laravel返回了User
对象。而且,如果我手动触发完全相同的
OrderSuccess
事件,则以上内容不可重现-它不会发送电子邮件,也不会加载User
对象。正如我之前说过的,此问题很少发生-对于没有用户帐户的客户,每天平均有40个左右的订单通过调用中心进行,而突出显示的问题可能仅一周发生一次或两次。
我对Laravel不太了解,可能是这里的问题-是某种形式的模型缓存,Eloquent ORM的问题还是系统中的其他gremlin?
任何想法表示赞赏-如果它似乎是某种形式的错误,我可以在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方法。为了尝试另一种解决方案,我将事件代码从事件处理程序中取出,并将其放置在 Controller 中-之前我是使用
Event::fire(new OrderSuccess ($order));
通过OrderSuccess事件触发的,而我注释掉了这一行,只是将事件处理程序代码放置在了 Controller 中方法:$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
我似乎还为时过早,指出将代码移到事件之外可以解决该问题-实际上,通过记录,在过去的两天内,我可以看到发出了更多不正确的订单确认信息(在将近3个订单后,总共发送了5个)周没有问题)。
我注意到已收到恶意订单确认的用户ID似乎正在递增(不是没有空缺,而是仍然按升序排列)。
我还注意到,每个问题订单都是通过现金和帐户信用付款的-大多数都是现金付款。我对此进行了进一步研究,用户ID实际上是相关信用交易的ID!
以上是尝试解决此问题的第一个铸铁突破。仔细检查后,我发现问题仍然是随机的-有相当多(至少50%)的订单已通过帐户信用支付给没有用户帐户的客户,但并未导致发送错误的电子邮件(尽管关联的信用交易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();
正在我的credit_transactions
表中生成ID,Laravel会使用该ID来检索用户对象。从上面的处理程序中可以看出,我在任何时候都不会更新$order
对象。Laravel如何使用(还记得,仍然是随机的,大约少于50%的时间)使用我新创建的
$credit_transaciton
的ID来填充$order->customer->user
模型对象?
最佳答案
我不能帮助您找到导致问题的根源,但是我可以根据问题的更新1中提供的逻辑来提供可能的解决方法。
原始逻辑
$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,因此将返回的客户限制为具有user_id
的客户可能更有效。这可以通过使用whereNotNull()
方法来实现。然后,我们可以继续检查是否有回头客,如果有,请发送电子邮件等。$customer = Customer::whereNotNull('user_id')->find($order->customer_id);
if (!$customer->isEmpty()) {
// send email and log actions etc
}
通过使应用程序没有机会返回带有空
user_id
的客户,这有望解决您的问题,但是不幸的是,它并没有说明其最初发生的原因。
关于php - Laravel 5.1 Eloquent ORM随机返回不正确的关系-*重大更新*,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33607125/