ma.mehralian's avatar

Laravel has-many-through with multiple intermediate tables

I am new to Laravel 5. I am trying to develop multiple-shop eCommerce platform. So the following tables created:

  • shops: id, name, ...
  • products: id, shop_id, ...
  • orders: id, ...
  • order_details: id, order_id, product_id, ...

And this is the summery of my models' relationships:

  • Shop->products: Shop hasMany Product
  • Product->shop: Product belongsTo Shop
  • Order->details: Order hasMany OrderDetail
  • OrderDetail->order: OrderDetail belongsTo Order
  • OrderDetail->product: OrderDetail belongsTo Product
  • Product->orders: Product hasMany OrderDetail

1: Is it possible to define Shop->orders relationship?(It seams has-many-through not works in this case due to multiple intermediate tables)

2: If it is possible, could the shop->orders->details contains only the records related to shop products?

It should be note that each Order may contain products from multiple shops but the shop->orders->details relation should contains only the shop products.

0 likes
3 replies
surendrasahi's avatar
  1. Shop->orders relationship is possible if orders table has prod_id foreign key.

shops: id, name,... products: id, shop_id,... orders: id, prod_id,....

Then you can build relationship like this.

/Add this in Shop Model:/


public function products()
{
    return $this->hasMany('App\Product');
}


public function orders()
{
    return $this->hasManyThrough('App\Order', 'App\Product');
}

/Add this in Product Model:/


public function shop()
{
    return $this->belongsTo('App\Product');
}

public function orders()
{
    return $this->hasMany('App\Order');
}

/Add this in Order Model:/


public function product()
{
    return $this->belongsTo('App\Product');
}

Now you can retrieve results with the following queries.

Products belong to Shop:

$shop_products = App\Shop::find(id)->products;

Orders belong to Shop:


$shop_orders = App\Shop::find(id)->products->orders;

Orders belong to product;


$product_orders = App\Product::find(id)->orders;
  1. You have to create another method for getting order details. Laravel Eloquent doesn't support hasManyThrough relationships if multiple intermediate tables are present. In such cases you have to write joins like this using DB Facade.
$shop_order_details = DB::table('order_details')
                    ->join('orders', 'order_details.order_id', '=', 'orders.id')
                    ->join('products', 'orders.product_id', '=', 'products.id')
                    ->join('shops', 'products.shop_id', '=', 'shops.id')
                    ->select('order_details.*')
                    ->where('shop_id', '=', $id)
                    ->get();

This will give you all order details related to one shop. If you wish to use only eloquent then you have to add shop_id foreign key to your order_details or orders table and follow the above procedure.

staudenmeir's avatar

I created a HasManyThrough relationship with unlimited levels: Repository on GitHub

After the installation, you can use it like this:

class Shop extends Model {
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function orders() {
        return $this->hasManyDeep(Order::class, [Product::class, 'order_details']);
    }
}
10 likes
_Marco_'s avatar

Hey @staudenmeir I use your library and with this particular relation it's not working since my FK is not by id.

I tried:

	return $this->hasManyDeep(Order::class, [Product::class, 'order_details'], ['iso']);

Please or to participate in this conversation.