'Access relation of pivot table in Laravel

I have three models Bill, Product and Process. Bill has a ManyToMany relationship with Product and the pivot table have some extra fields. I write the Bill model class like follow:

<?php
    class Bill extends Model
    {
           function products(){
                return $this->belongsToMany(\App\Product::class)
                    ->withPivot('process_id') // the id of the Process 
                    ->withTimestamps();
            }
    }

The Process model is a simple table with an id and a name. I am associating the id in the pivot table for reference the Process, the name could change over time but still referring the same concept so I can't associate the name.

The show page for a single Bill lists the products associated in a table like follow:

@foreach($bill->products as $product)
     <tr>
        <td>{{$product->barcode}}</td>
        <td>{{$product->pivot->process_id}}</td> 
     </tr>
@endforeach

So the problem is that I need the name of the process, but I have the id. I'm not sure how I could get the name.

Thanks



Solution 1:[1]

I think you can use an own Pivot Model, e.g. ProductBill in order to achieve this.

class ProductBill extends Pivot {

    public function process() {
        return $this->belongsTo(Process::class);
    }

}

By using this model in your products relation on Bill

class Bill extends Model {

    function products() {
        return $this->belongsToMany(\App\Product::class)
            ->withPivot('process_id')
            ->using(ProductBill::class)
            ->withTimestamps();
    }

}

When accessing $product->pivot you should get an instance of ProductBill now, hence you should be able to do the following:

<td>{{$product->pivot->process->name}}</td> 

(Unfortunatelly I not able to doublecheck right now :/)

Solution 2:[2]

Without having a direct relation to Process you will likely need to add a helper on your Product model to get the name of Process.

In your Product model:

public function processName($processId) {
    return Process::where('id', $processId)->pluck('name')->first();
}

In your view:

<td>{{$product->processName($product->pivot->process_id) }}</td> 

There may be a better way, but concept this should work.

Solution 3:[3]

I know it's not the most elegant of solutions. but you could always simply do:

Process::find($product->pivot->process_id)->name;

I wouldn't advice this though as you are looping through an array already, so the overheads to doing something like this would be quite large.

Another solution would be to create a Pivot class called say BillProductPivot which would have a relationship to return both Product and Process, then when you call them you should be using eager loading to get the relationships. end product might look like this:

$bill->load('productPivots', 'productPivot.process', 'productPivot.product');

@foreach($bill->productPivots as $productPivot)
 <tr>
    <td>{{$productPivot->product->barcode}}</td>
    <td>{{$productPivot->process->name}}</td> 
 </tr>
@endforeach

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 miken32
Solution 2 Darryl E. Clarke
Solution 3