0

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.

UPDATE

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.

Mr Office
  • 290
  • 1
  • 9
  • It will use the result from the first time it's called on the page yes. I also think that using a condition in a relation is not quite what Taylor had in mind for it :P – Luceos Feb 23 '15 at 15:16
  • 1
    You might want look into [polymorphism](http://laravel.com/docs/5.0/eloquent#polymorphic-relations) for this guest/user setup – lukasgeiter Feb 23 '15 at 15:23
  • Thanks for the info - yes I did think it was a bit of a hack but it worked so well in my views :) Is this a common issue with database structure then? Should I instead have `orders_guests` and `orders_users` pivot tables? – Mr Office Feb 23 '15 at 15:24
  • Thanks @lukasgeiter - that does seem to be what I'm looking for. Hopefully I can get that working. – Mr Office Feb 23 '15 at 16:22
  • First of all, you need to parse Model name under `with` method not method name of the model. The model name would you want to eager loading with. – Safoor Safdar Feb 23 '15 at 16:33

0 Answers0