MarvinVK MarvinVK - 1 year ago 95
PHP Question

Laravel: add product sizes relation with a price pivot

I'm trying this for a while now and I can't seem to figure it out.

So I have a Products and a Sizes table with a belongs to many relation.

So in my model I have:

public function sizes()
return $this->belongsToMany(Size::class, 'size_product')->withPivot('price');

My forms looks like this:

My forms looks like this (don't loog at the styles)

My blade looks like this:

<h2 class="fields-holder__title">Sizes</h2>
@foreach($sizes as $size)
<div class="field-holder__container">
<input type="checkbox" name="sizes[]" value="{{ $size->id }}">
<input type="text" name="prices[]" placeholder="Price">

And in my controller on post I do:

// add and remove sizes pivot
$sizes = [];
foreach ($request->sizes as $size) {
array_push($sizes, $size);

But how do I save the prices?

I know you can do this in Laravel:

$product->sizes()->sync($size, ['price' => $price]);

But how do I get this in the foreach.

I hope someone can help me out.


Answer Source

First of all, the logic for saving the Product with it's corresponding sizes/prices doesn't belong in your Controller, but in your Model (or some intermediate data layer).

As for your issue: you can only save pivot relations to a record that already has an id, ie. one that has already been saved to the database. Also, the sync() method on the belongsToMany class is meant for saving multiple relations by ids, and accepts a boolean as a second argument (whether to detach or not, default is true).

In this case you should do a foreach over the array of sizes, an attach() each one, with it's price, to the parent model. Something like this:


public method store(Request $request)
    // call the create method on the model
    $product = Product::createForSizes(
        $request->only('name', 'sizes', 'prices')

    return $product 
        ? redirect()->route('some.route')
        : redirect()->route('some.other.route');


public static method createForSizes($name, array $sizes, array $prices)
    // create and save a new instance of the model
    if(!$product = static::create(compact('name'))) {
        return false;

    // attach each size, with it's price
    foreach($sizes as $index => $id) {
        $price = isset($prices[$index]) ? $prices[$index] : null;
        $product->sizes()->attach($id, compact('price'));

    return $product;

Note: Laravel looks for pivot tables automatically if you name them as plural, in alphabetical order. So if you name your pivot table products_sizes, you can omit the table name from the relation method like so:

public function sizes()
    return $this->belongsToMany(Size::class)->withPivot('price');
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download