How create nested relationship over three models

Published 11 months ago by abombelli


I'm completely new to Laravel and have the following situation:

I have the following Models:

  • Treatments; belongsToMany Products, belongsTo User
  • Products; belongsToMany Treatments, hasManyPrescriptions
  • Prescriptions; ??
  • Users; hasMany Treatments

Treatments can have many Products. Each associated Product to a Treatment can have a unique Prescription.

The tables are:

  • Users (id, name)
  • Treatments (id, name, user_id)
  • Products (id, name)
  • Product_Treatment (product_id, treatment_id)
  • Prescriptions (id, amount, product_id, treatment_id, user_id)

I manage to create the correct relations from products to each treatment. What I cannot figure out is how to relate the prescription to the product in the corresponding treatment. A product can belong to many treatments. If I use a normal pivot table for products_prescription, then this relation applies to all treatments. This should not be the case.

How should I setup the relationship, so I'm able to use this in blade? @foreach ($treatment->products as $product) {{ $product->name }} {{ $product->prescription->amount }} @endforeach

Thanks a lot for any hint or help. Aldo

Best Answer (As Selected By abombelli)

Why not simply add a column amount in product_treatment pivot (withPivot) ?



I dont understand the difference between Treatments and Prescriptions.


A Treatment has many products, where each product has a different prescription (amount of intake a user needs).

The prescription can be different for the same product in another treatment.

I hope this clarifies.


An addition: products are shared across treatments. Prescriptions are product/treatment specific.


Why not simply add a column amount in product_treatment pivot (withPivot) ?


Of course! Thanks a lot. I searched to much ;-)

Now I can insert the values into the pivot table: $treatment->products()->updateExistingPivot($product->id, [ 'consumption_interval' => request('consumption_interval'), 'units_per_interval' => request('units_per_interval') ]);

Where I'm still stuck, is accessing the values in the view. The pivot attributes appear fine in the "show" view {{ $product->pivot->units_per_interval }}, but not when editing the attributes. Then the array is missing the pivot relationship. Any idea what I'm missing?


I dont see the diffrence between show and edit about this attribute.


In show I have:

@foreach ($treatment->products as $product)

Then for the edit view I have the following function in the TreatmentsController, where I pass the treatment and product id in the route Route::get('/treatments/{treatment}/prescription/{product}/edit', '[email protected]_prescription'):

public function edit_prescription(Treatment $treatment, Product $product) {
    return view('prescriptions.edit', compact('product', 'treatment') );

But somehow I do not get the attribute in the edit view via $product->pivot->units_per_interval


Not sure of your queries, but looks like in this case it's rather :


Then I get an error: Trying to get property of non-object.

Do I need to specifically create a query for the single edit view?


Sounds weird, as you need same informations for show and edit.


Yes. The only difference is, in show I access the pivot over the foreach loop and in the edit view I just pass the $product and $treatment object. And both are missing the relationship.


But you edit a treatment that can have many products ?


Yes. Treatment model looks like this:

class Treatment extends Model

    protected $fillable = ['name'];

    public function user() {

        return $this->belongsTo(User::class);


    public function products() {

        return $this->belongsToMany(Product::class)->withPivot('consumption_interval', 'units_per_interval');


And I edit from the treatment controller.


So when you edit a treatment you must eager load all the products and you can access the pivot...


Could you point me to the right direction? Don I do this from the model or the controller?

Please sign in or create an account to participate in this conversation.