Say I have an orders
table and a users
table and a guests
table, for a company who accept orders from both users
and guests
.
I also have a is_guest
boolean on the orders
table which lets me know quickly whether the order has been made by a guest or a registered user.
I have a model method called customer
which returns the eloquent relation like so:
public function customer()
{
return $this->is_guest ? $this->belongsTo('Guest', 'user_id') : $this->belongsTo('User', 'user_id');
}
This works very well when I pass orders
to the view and access the customer's data like so:
// Maps to either $order->user->firstname OR $order->guest->firstname
echo $order->customer->firstname;
But when I try to use this functionality when using eager loading it doesn't quite work:
$orders = Order::with('customer')->get();
return Response::make($orders);
It only returns the eager loaded customer data for either the user
or the guest
and never both.
I'm wondering why this is and how to get round it?
Is it because of the way the eager loading works - it only calls the customer()
method once just as it only hits the database once, so whatever the first result of the query is, it will use that to determine the rest of the query too?
If I am trying to get a JSON response of all the order
data with all of the customer's details too, how would I do that?
Thanks.
Yes, turns out I was abusing the Laravel relationship method by adding a condition. Using the polymorphic relations is a much better approach as suggested by @lukasgeiter. http://laravel.com/docs/4.2/eloquent#polymorphic-relations
I did have trouble loading other relations based on the polymorphic relation. For example if both User
and Guest
had corresponding tables UserDetail
and GuestDetail
then I couldn't get the eager loading to work. So I added this to both the User
and Guest
models:
protected $with = ['detail'];
This means that whenever the customer
polymorphic relation is eager loaded, then both User
and Guest
will load their relationships automatically. I think I could have also used the 'lazy loading' functionality $order->load('customer')
but I didn't try it out.
public function detail()
{
return $this->hasOne('UserDetail');
}
Thanks guys.