Eager Loading: Use `with` on pivot with eloquent relationship
The current accepted answer deviates from the original data structure. I created a package which can help you achieve what you want and also it maintains the original data structure. Please read my medium story here: https://medium.com/@ajcastro29/laravel-eloquent-eager-load-pivot-relations-dba579f3fd3a
First, create your custom pivot model and define relations on pivot model, in your case:
use Illuminate\Database\Eloquent\Relations\Pivot;
class BundleProduct extends Pivot
{
public function price()
{
return $this->belongsTo(Price::class);
}
}
Then use the pivot model in the relation:
class Bundle extends Model
{
public function products()
{
return $this->belongsToMany(Product::class)
->withPivot('price_id') // this is needed to query the relation `price`
->using(BundleProduct::class);
}
}
Make sure you use the trait AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait
in the Product
model because it is the related model in belongsToMany relation. This let us enable eager loading the pivot relations.
use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;
class Product extends Model
{
use EagerLoadPivotTrait;
}
Then eager load it like this:
$bundle = Bundle::with('products.pivot.price')->first();
$price = $bundle->products->first()->pivot->price;
One solution could be adding a BundleProduct
model for the pivot. Then link the BundleProduct object to Bundle model:
class Bundle extends Model
{
public function bundleProducts()
{
return $this->hasMany(BundleProduct::class, 'bundle_id', 'id');
}
}
To get all your bundles with their associated products and prices in this bundle, just do:
Bundle::with('bundleProducts.product', 'bundleProducts.price')->get();
That worked for me, hope it could help someone else.
Documentation: Eloquent: Relationships: Many To Many
By default, only the model keys will be present on the pivot object. If your pivot table contains extra attributes, you must specify them when defining the relationship:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
That means that the withPivot()
method only adds missing fields to the pivot
object. To retrieve the actual Price
model you will have to set up another relationship. It would look something like this:
/**
* Class Bundle
*
* Bundle model with the products relationship
*/
class Bundle extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
}
/**
* Class Product
*
* Product model with the prices relationship
*/
class Product extends Model
{
public function prices()
{
return $this->belongsToMany(Price::class);
}
}
/**
* Class Price
*
* Simple model, end result
*/
class Price extends Model
{
// Model definition...
}
This is basic and of course not the complete code, only the functions necessary for the answer.
After this all you need to do to retrieve relationships is the following:
// You can query a child relationship using the dot (.). Prices collection will be accessible within each member of the products collection
$all_bundles = Bundle::with('products.prices')->get();
$price_id = $all_bundles->first()
->products->first()
->prices->first()->id;