aynber
aynber

Reputation: 23011

Eager loading single many-to-many relation

I have two models connected via a pivot table with an extra column to track the quantity

class Item extends Eloquent {
    public function containers()
    {
        return $this->belongsToMany('Container', 'items_containers', 'item_id', 'container_id')->withPivot(['quantity']);
    }
}

class Container extends Eloquent { 
    public function items() {
        return $this->belongsToMany('Item', 'items_containers', 'container_id', 'item_id')->withPivot(['quantity']);
    }
}

And a third model for my orders:

class OrderItem extends Eloquent {
    public function originalItem()
    {
        return $this->hasOne('Item', 'id', 'item_id');
    }
    public function container() {
        return $this->hasOne('Container', 'id', 'container_id');
    }

}

What I want is to be able to get the specific data from the pivot table when eager loading the OrderItem models, so I only get the quantity where the item_id and container_id matches what's on the order item.

OrderItems::whereOrderId($orderId)
   ->with(['originalItem', 'container', '???'])
   ->get();

What's the best way to specify the relationship on the OrderItem, or load it in with with?

Upvotes: 0

Views: 659

Answers (2)

Morteza Rajabi
Morteza Rajabi

Reputation: 2913

The following returns what you want:

$orders = \App\OrderItem::select('item_orders.*', 'items_containers.quantity as quantity')->with('item', 'container')
    ->leftJoin('items_containers', function ($join) {
        $join->on('items_containers.item_id', 'item_orders.item_id')
            ->where('items_containers.container_id', \DB::raw('item_orders.container_id'));
    })
    ->get();

Then you can easily get the quantity.

$orders->first()->quantity;

That's it.

Upvotes: 2

aynber
aynber

Reputation: 23011

Major props to Morteza Rajabi for getting me on the right track. The first key was getting the specific relation, since while Items and Containers are a Many-to-Many relationship, the OrderItem has a One-to-One relationship with both the Item and the Container. In order to get the specific relationship quantity, I had to create an attribute specifying it:

public function getItemContainerQtyAttribute() {
    if($this->item_id && $this->container_id) {
        return $this->depoItem->containers()->where('items_containers.container_id', $this->container_id)->first()->pivot->quantity;
    }
    return null;
}

The item_id and container_id check is because this is a work in progress, and the OrderItems haven't always been created correctly, and some items don't have a container specified.

The next step was to autoload it with the appends attribute within Eloquent:

protected $appends = ['item_container_qty'];

Now whenever I load $item = OrderItems::whereOrderId($order_id)->get();, it will load the the pivot quantity automatically.

Upvotes: 1

Related Questions