Ramadhani Baharzah
Ramadhani Baharzah

Reputation: 77

How to update in Laravel Eloquent (HasMany Relationship)

i had two modules which are Product and Items Modules Here the relationship between these two module are: Product hasMany items and Items belongsTo product

The table for Product Module are: id, product_name The table for Items Module are: id, products_id, item_name, quantity, price

This is my code for UPDATE

public function update(Request $request)
{
    $product = Product::findOrFail($id);
    $product->product_name = $request->product_name;
    $product->update();
    // Remove all items and add new
    $product->items()->delete();
    // Save each items
    if($request->get('item_name')){
        foreach($request->get('item_name') as $key => $item_name)
        {   
            $items = new Items();
            $items->products_id = $product->id;
            $items->item_name = $item_name;
            $items->quantity = $request->quantity[$key];
            $items->price = $request->price[$key];
            $items->save();
        };
    };
}

The structure for this UPDATE code is whenever there is an update, each items will be deleted and update information will be added as new row.

What i want is the items SHOULD NOT be deleted and add as new. This is because i wants to MAINTAIN THE ITEMS ID. What should i modified to my current code?

Upvotes: 1

Views: 3309

Answers (1)

Tarsis Cruz
Tarsis Cruz

Reputation: 133

If your purpose is to make it more dynamic to add, delete and update the items we have to handle this with another way!
Unfortunately Laravel does not provide some method like sync() to handle many-to-one relationships, just with many-to-many. So you have to insert some additional logic into your code. We will use the id key to handle this logic.
So, for this works, all the product items came from request must have the key id. The new items (those that do not yet exist in the database) must have the id key empty.

For example:

[
  {
    "id": 1,
    "name": "Item 1",
    "quantity": 2,
    "price": 10,
    "product_id": 1,
  },
  {
    "id": "",
    "name": "Item 2",
    "quantity": 3,
    "price": 22,
    "product_id": 1,
  },
  {
    "id": "",
    "name": "Item 3",
    "quantity": 9,
    "price": 33,
    "product_id": 1,
  }
]

Note the just the first item will be updated, the second and third will be added because the id key is empty, and the items that dont came into array but exists on the database will be deleted.

So, lets go!

1 - Create 3 auxiliary variables to items with id, items without id and items id. Note that we use collect() method to help us to handle the arrays:

$items_without_id = collect($items)->where('id', '');
$items_with_id = (clone collect($items))->where('id', '!=', '');
$items_ids = $items_with_id->pluck('id');

2 - Update the items with id:

foreach ($items_with_id as $item) {
   $obj = App\ProductItem::find($item['id']);
   $obj->name = $item['name'];
   $obj->price = $item['price'];
   $obj->quantity = $item['quantity'];
   $obj->save();
}

3 - Remove items that don't came into the array, we supposed that these items have to be deleted:

$product->items()->whereNotIn('id', $items_ids)->delete();

4 - Finally insert items that came without id. We supposed that these items has to be added:

$items_without_id->each(function ($item) use ($product) {
   $obj = new App\ProductItem();
   $obj->name = $item['name'];
   $obj->price = $item['price'];
   $obj->quantity = $item['quantity'];
   $obj->product_id = $product->id;
   $obj->save();
});

Full code:

$product = App\Product::findOrFail($id);
$items = $request->items;

$items_without_id = collect($items)->where('id', '');
$items_with_id = (clone collect($items))->where('id', '!=', '');
$items_ids = $items_with_id->pluck('id');

foreach ($items_with_id as $item) {
   $obj = App\ProductItem::find($item['id']);
   $obj->name = $item['name'];
   $obj->price = $item['price'];
   $obj->quantity = $item['quantity'];
   $obj->save();
}

$product->items()->whereNotIn('id', $items_ids)->delete();

$items_without_id->each(function ($item) use ($product) {
   $obj = new App\ProductItem();
   $obj->name = $item['name'];
   $obj->price = $item['price'];
   $obj->quantity = $item['quantity'];
   $obj->product_id = $product->id;
   $obj->save();
});

Testing with postman:

enter image description here

Hope this helps. Sorry for my bad english.

Upvotes: 2

Related Questions