Reputation: 526
I have a complicated relationship I'm trying to establish between two models.
The goal is to use $supplier->supply_orders
to access the orders where the user supplies an item.
This throws: LogicException: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
.
With the code I've got I can use $supplier->supply_orders()->get()
, however, when I try to use it as a relationship it throws. Since this is a relationship I should be able to wrap it in a relationship, but how would I go about doing that?
Supplier Model:
class Supplier extends Model {
public function supply_orders() {
return Order::query()
->select('order.*')
->join('item_order', 'order.id', '=', 'item_order.order_id')
->join('item', 'item_order.item_id', '=', 'item.id')
->where('item.supplier_id', '=', $this->id);
}
}
~~~ A whole lot of back info that I don't think you need but might ~~~
sql tables:
supplier
- id
items:
- id
- supplier_id
item_order:
- id
- order_id
- item_id
orders:
- id
The other Eloquent Models:
class Item extends Model {
public function orders() {
return $this->belongsToMany('Order');
}
}
class Order extends Model {}
Example of how this should work:
$supplier = factory(Supplier::class)->create();
$item = factory(Item::class)->create([
'supplier_id' => $supplier->id,
]);
$order = factory(Order::class)->create();
$order->items()->attach($item);
$orders = $supplier->supply_orders // Throws LogicException
This throws: LogicException: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
Upvotes: 0
Views: 223
Reputation: 8178
I believe the reason it throws a relationship error is that you haven't created an Eloquent relation for
$supplier->supply_orders.
Instead, Laravel looks at your supply_orders() as a method in the class, and thus can't figure out which table to use as the pivot. To get the base relationship to work within Eloquent, you'd need to create a new pivot table for the relationship between suppliers and orders something like:
suppliers
-id
orders
-id
order_supplier
-id
-order_id
-supplier_id
From here, Laravel will accept a simple many to many relationship between the two (this would not cause a failure):
Supplier Class:
/**
* Get all orders associated with this supplier via order_supplier table
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function orders(){
return $this->belongsToMany("\App\Order");
}
Now that the relationship is solid both between the suppliers and orders, as well as the orders and items, you can eager load the relationship in all directions. Where it gets complicated for your particular need with the current DB setup is that you have a 3rd parameter from the items table that is not a direct pivot. Without having to re-structure the DB, I think the easiest would be to load your suppliers and the relationships like normal:
$suppliers = Supplier::with('orders', function($query) {
$query->with('items');
});
From here you've got all the relationships loaded and can draw down the ones with the right item->ids in a follow-up to the $suppliers collection. There are quite a few ways to skin the cat (even including all in one query) now that you have the Eloquent relationship... but I tend to keep it a little more simple by breaking it into a few readable bits.
Hope this helps.
Upvotes: 0
Reputation: 9465
Sounds like a hasManyThrough with a many to many relationship. Laravel has no inbuilt support for this but you can always go ahead and write your own relationship like this: https://laravel.io/forum/03-04-2014-hasmanythrough-with-many-to-many
If you dont want relationships you can always do something like:
Order::whereHas('items.supplier', function($query) use($supplier) {
$query->where('id', $supplier->id);
});
For this to work, you need to have a relationship function items
in your Order model and a relationship function supplier
in your item model
Upvotes: 1