Take a moment and understand what you are doing here.
Say the incoming data from request is like
['product_id' => [2,1], 'quantity' => [2,5], 'measure_id' => [3,4]];
The for loop will run 2 times (count($request->quantity)). The values written to database for record identified by quote_id = $id will be:
So finally the values after last iteration will remain persisted.
Another is that you are trying to identify a record for updation by non-primary key - there can be multiple records in quote_detail table with the same value in quote_id field.
Edit:
I have the table (quotes), in it I store the primary data and in the table (quote_detail), the detail and it is related to the first.
Eloquent way
//Quote.php - Quote (eloquent) model class - table:quotes
public function quoteDetails()
{
return $this->hasMany(QuoteDetail::class);
}
//QuoteDetail.php - QuoteDetail (eloquent) model class - table: quote_details
public function belongsTo()
{
return $this->belongsTo(Quote::class);
}
In controller
$quote = Quote::findOrFail($id);
$count = 0;
for($i = 0; $i < count($request->quantity); $i++) {
$quote->quoteDetails()
->updateOrInsert(
/**
* - Check for existing records with following column => value pairs
* - Combination of quote_id & product_id will act as composite key to identify unique records in quote_details table
* - Even better to have unique index using composite key quote_id + product_id
*/
['quote_id' => $quote->id, 'product_id' => $request->product_id[$i]],
/** If a record exists it will be updated with following */
['quantity' => $request->quantity[$i], 'measure_id' => $request->measure_id[$i]]
);
// If a matching record (quote_id + product_id) is not found then a new record will be inserted combining both arguments to the `updateOrInsert` method.
}
Laravel Docs - Queries - Update Statements
Query Builder way
for($i = 0; $i < count($request->product_id); $i ++) {
Db::table('quote_details')
->updateOrInsert(
/**
* - Check for existing records with following column => value pairs
* - Combination of quote_id & product_id will act as composite key to identify unique records in quote_details table
* - Even better to have unique index using composite key quote_id + product_id
*/
['quote_id' => $id, 'product_id' => $request->product_id[$i]],
/** If a record exists it will be updated with following */
['quantity' => $request->quantity[$i], 'measure_id' => $request->measure_id[$i]]
);
// If a matching record (quote_id + product_id) is not found then a new record will be inserted combining both arguments to the `updateOrInsert` method.
}
Update - Better Approach
Better approach would be to define many-to-many relationship between Quote and Product models via quote_details table as pivot table.
//Quote.php
public function products()
{
$this->belongsToMany(Product::class, 'quote_details');
}
//Product.php
public function quotes()
{
return $this->belongsToMany(Quote::class, 'quote_details');
}
Then in controller
$quote = Quote::findOrFail($id);
$syncData = [];
for($i = 0; $i < count($request->product_id); $i++) {
$syncData[$request->product_id[$i]] = [
'quantity' => $request->quantity[$i],
'measure_id' => $request->measure_id[$i]
];
}
$quote->products()->sync($data);
The sync() method will only keep the records in quote_details for which the product_id(s) are received via current request.
Say the earlier values in table were:
id=1, quote_id=1, product_id=1, quantity=2, measure_id=6.
and the new values are
quote_id=1, product_id=3, quantity=2, measure_id=6
then the older record will be deleted and new record will be created as
id=2(or whatever as per autoincrement), quote_id=1, product_id=3, quantity=2, measure_id=6
product_idfor example) for a given id ?