I have a Laravel app that powers an ecommerce website with moderate traffic. This website allows people to place orders via the frontend, but it also has backend functionality for taking orders over the phone via a call centre.
An order is related to a customer, and a customer can optionally be user - a user being someone with a login to the frontend. A customer with no user account is only ever created as a result of an order being taken via the call centre.
The issue I have encountered is very odd, and I believe might be some kind of Laravel bug.
It only occurs very occasionally, but what is happening is that when an order is taken via the call centre for a customer with no user account, an order confirmation is being sent out to a random user - literally random, as far as I can tell, just plucked out of the database despite no relation in the data.
These are the relevant parts of the models in the project:
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');
}
}
The logic that sends the order confirmation is within an event handler that gets fired after the order has been paid.
Here is the OrderSuccess event (edited for brevity):
use App\Order;
class OrderSuccess extends Event
{
public $order;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
}
As can be seen, this event is passed an Order model object.
Here it is (edited for brevity):
/**
* 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');
});
}
}
There is a check to see if the $order->customer->user object is not null and, if true, an order confirmation is sent. If it is null (which it frequently is), then no confirmation is sent.
As can be seen from the above, I added a log to record the objects when an email is sent. Here is an example of an erroneous one (again, truncated for brevity):
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] =>
)
As you can see, there is no user_id for Customer, and yet Laravel has returned a User object.
What is more, if I manually fire the exact same OrderSuccess event, the above is not reproducible - it does not send the email, and it does not load a User object.
As I said before, this issue is happening very infrequently - there are on average about 40 orders a day via the call centre for customers with no user account, and the highlighted issue might only occur once or twice a week.
I'm not familiar enough with Laravel to know what might be the issue here - is it some form of model caching, a problem with Eloquent ORM, or some other gremlin in the system?
Any ideas appreciated - I may post this problem in the Laravel github issue tracker if it appears to be some form of bug.
via Chebli Mohamed
Aucun commentaire:
Enregistrer un commentaire