Updating multiple data at once in two different table in Laravel 9 - php

I want to update multiple data at once in two different table, lets just call it table1 and table2. On table1 I have 3 columns, id, detail_id, and program_name. On table2 I also have 3 columns, id, age, and detail_program. I can store the data from user input into database using this code
$detailId = [];
foreach($request['age'] as $key => $ages) {
$programDetails = ProgramDetail::create([
'age' => $ages,
'detail_program' => $request['detail_program'][$key]
]);
$detailId[] = $programDetails->id;
}
$detailId_string = implode(',', $detailId);
ProgramVaksin::create([
'detail_id' => $detailId_string,
'program_name' => $request->program_name
]);
But when I try to update the data, It can update and return success message, but the data is not what user inputting. For example, user want to change the age data that has detail_id 20,30, and 40 from 1, 2, 3 become 3, 4, 5. After the user click the update button, the age data that user inputting it's become random. Like it should be 3, 4, 5 but it's become 5, 4, 4 or 4, 5, 5 or nothing change at all. This is my code for updating data
public function update(Request $request, ProgramVaksin $programVaksin)
{
$age = $request->input('age');
$detail = $request->input('detail_program');
for ($i = 0; $i < count($age); $i++) {
ProgramDetail::where('id', $programVaksin->detail_id[$i])->update([
'age' => $age[$i],
'detail_program' => $detail[$i]
]);
}
ProgramVaksin::where('id', $programVaksin->id)->update([
'program_name' => $request->program_name
]);
return redirect('/dashboard/program-vaksin')->with('success', 'Data has been updated');
}
Can someone help me about this?

If $age is an array, you could make a collection from it and get a random element on each update.
$ages = collect($request->input('age', [])); // if no age is present, at least have an empty array
$detail = $request->input('detail_program');
for ($i = 0; $i < count($ages); $i++) {
ProgramDetail::where('id', $programVaksin->detail_id[$i])->update([
'age' => $ages->random(),
'detail_program' => $detail[$i]
]);
}
If you want to use pure php methods, there's also array_rand
$ages = $request->input('age', []); // if no age is present, at least have an empty array
$detail = $request->input('detail_program');
for ($i = 0; $i < count($ages); $i++) {
ProgramDetail::where('id', $programVaksin->detail_id[$i])->update([
'age' => $ages[array_rand($ages)],
'detail_program' => $detail[$i]
]);
}

Related

How I get data by group User ID for foreach controller function in Laravel

How can I get data by grouping user_id for a foreach loop in a controller's function in Laravel. For example, user_id = 2, 5 rows available, user_id = 1, 10 rows available. Then show 2 arrays.
$lists = lists::wherestatus(1)->groupby('user_id')->get();
foreach($lists as $list){
$list = functionHere;
}
What function can I create for this on the controller for grouping?
I need more information, but based on what you shared, you should be able to do this (removing the foreach):
$lists = Lists::whereStatus(1)->get()->groupBy('user_id');
The difference is that if you use groupBy before get, you are grouping your query by user_id, so instead of getting 5 rows for user_id = 2 and 10 for user_id = 1, you are going to get 2 rows and just the latest data, so you need to use Collection's groupBy.
What you want to do is group all the information by user_id but have each row, a schema like this:
[
'1' => [ // user_id
['user_id' => '1', 'column1' => 'random value'],
['user_id' => '1', 'column1' => 'other value'],
// 8 remaining rows
],
'2' => [ // user_id
['user_id' => '2', 'column1' => 'other nice value'],
// 4 remaining rows
],
]
you should first in List model set:
public function scopeStatus(){
return $this->where('status','1');
}
and in your controller:
$products = List::status()->groupby('user_id')->get();

How to get duplicate array out of an array

I have an array with orders. Example:
$orders = [
'0' => [
'ordernumber' => 1,
'customer' => [
'phone' => '0123456789',
'mobile' => '0612345678'
],
],
'1' => [
'ordernumber' => 2,
'customer' => [
'phone' => '0123456789',
'mobile' => '0612345678'
],
],
'2' => [
'ordernumber' => 3,
'customer' => [
'phone' => '0987654321',
'mobile' => '0687654321'
],
],
'3' => [
'ordernumber' => 3,
'customer' => [
'phone' => '0123456789',
'mobile' => '0612345678'
],
]
];
I want to sort these orders. As you can see there can be orders where the same customer (customer with same phone number, this can be either same phone number or same mobile number) has multiple orders. I want to put all the orders that have the same phone number (doesn't matter if the phone number matches or the mobile number) in an array $duplicateOrders and all the "single" orders (orders that dont match a phone number) in an array $singleOrders. At the end the orders array must be empty. But no order can be lost or be in both arrays.
I have tried to loop through the orders with a foreach loop where I put every order in the $singleOrders array and unset it from the $orders array. I than try to match that order with another foreach loop to all the remaining orders in $orders. If I get a match i put that order (this is done once) in the $duplicateOrders array and every match of it also (I unset every match also from the $orders array). If the orders array is empty I stop, otherwise the first foreach loops kicks in and takes the next order and the proces repeats. This is my code:
protected function splitDuplicateOrders()
{
$singleOrderKey = 0;
if ($this->orders) {
foreach ($this->orders as $key => $order) {
if (count($this->orders) == 0) {
break;
}
array_push($this->singleOrders, $order);
unset($this->orders[$key]);
$orderPushed = false;
foreach ($this->orders as $otherKey => $value) {
if ($order->customer->phone == $value->customer->phone || $order->customer->mobile == $value->customer->mobile) {
if (!$orderPushed) {
array_push($this->duplicateOrders, $order);
}
array_push($this->duplicateOrders, $value);
unset($this->orders[$otherKey]);
unset($this->singleOrders[$singleOrderKey]);
$orderPushed = true;
}
}
$singleOrderKey++;
}
}
}
I expected to have an $duplicateOrders array with all the duplicates and a $singleOrders array with all the singles. I tested this with an $orders array of a total of 4 orders where 2 of them were duplicates and 2 were singles. The function sorted it nicely (but only if the orders aren't right after each other, if they are it still sorts the duplicates right but leaves one also in the $singleOrders and than I have 5 orders). Than I tested it where there were 3 duplicates and 1 single order. The $duplicateOrders array was correct but in the $singleOrders the single order was placed but also one duplicate order from the $orders array. It somehow removed the 2 duplicates correct but left one duplicate in the $singleOrders array.
Can someone help me to debug this or provide a different approach? I have been trying to solve this for 2 days but no success.
You could make use of Laravel Collections, in this case I'm gonna use the partition() method. From the documentation:
partition()
The partition method may be combined with the list PHP function to
separate elements that pass a given truth test from those that do not:
$collection = collect([1, 2, 3, 4, 5, 6]);
list($underThree, $equalOrAboveThree) = $collection->partition(function ($i) {
return $i < 3;
});
$underThree->all();
// [1, 2]
$equalOrAboveThree->all();
// [3, 4, 5, 6]
So in your case:
$orders = /** query or API to get orders as array */;
list($repeated, $single) = collect($orders)
->partition(function ($order) use ($orders) {
return $orders->where('customer.phone', $order['customer']['phone'])->count() > 1
OR $orders->where('customer.mobile', $order['customer']['mobile'])->count() > 1;
});
// now you can use them:
$repeated->all();
$single->all();
Notice that this two newly created objects ($repeated and $single) are in fact also instances of the Collection class (as you can see where I used the all() method on each), so you can keep constraining/sorting/customizing them with the help of the Collection's methods.

Laravel Array to string conversion when using sizeof

i'm new on laravel, basically when i using codeigniter this code works fine.
The problem is i cannot use this for insert data.
for($count = 0; $count < sizeof($cid); $count++){
inset to table for item 1,
inset to table for item 2,
inset to table for item 3,
}
this is my controller
$request->validate([
'pembelian_kode' => 'required',
'barang_kode' => 'required',
'pembelian_total' => 'required',
'pembelian_qty' => 'required',
'supplier_id' => 'required',
]);
$cid = Input::POST('cid');
$cg = PembelianModel::create($request->all());
if($cg){
for($count = 0; $count < sizeof($cid); $count++){
DB::table('pembelian_details')->insert([
'pembelian_kode' => $request['pembelian_kode'], 'barang_kode' => $request['barang_kode'], 'pd_qty' => $request['pembelian_qty']]
);
}
}
return redirect()->route('pembelians.index')
->with('success','Data berhasil ditambah');
reults error
Array to string conversion (SQL: insert into `pembelian_details` (`pembelian_kode`, `barang_kode`, `pd_qty`) values (PBL1812025877, BRG10181125230, 10))
so i have two tables 1 is 'orders' and also 'order_details'. For the table orders it has been successful in adding data, but for orders details there are still errors.
can someone help me ?
I just modified your script .Hope this will work
Problems:
$request['barang_kode']
Missing index
$request is an object not array
$cid = $request->cid;
$cg = PembelianModel::create($request->all());
if($cg){
for($count = 0; $count < count($cid); $count++){
DB::table('pembelian_details')->insert([
'pembelian_kode' => $request->pembelian_kode[$count],
'barang_kode' => $request->barang_kode[$count],
'pd_qty' => $request->pembelian_qty[$count]
]
);
}
}
return redirect()->route('pembelians.index')
->with('success','Data berhasil ditambah');

Error in getting the last inserted ID of a query using batch insert in CodeIgniter

How can I get the last inserted ID of a query using the batch insert in CodeIgniter. I used the code $this->db->insert_id() but it returns the ID of my first inserted array. I can't get the last insert.
Here's what I did:
for ($x = 0; $x < sizeof($filtername); $x++) {
$orders[] = array(
'poid' => null,
'order_id' => $poid,
'item_desc' => $filtername[$x],
'item_qty' => $filterquantity[$x],
'item_price' => $filterprice[$x],
'total' => $filtertotal[$x],
'cash_on_delivery' => $val_delivery,
'is_check' => $val_check,
'bank_transfer' => $val_transfer,
'transaction_date' => $dateorder
);
}
$this->db->insert_batch('po_order', $orders);
echo $this->db->insert_id(); //will return the first insert array
I can't spot where's my error. My last option is to get it using a query. I also did mysql_insert_id() but always returns to 0.
I think the best way would be to use the batch insert instead of individual inserts in a loop for performance , but to get the last insert id, ADD the First Insert ID & the Affected Rows.
$this->db->insert_batch('po_order', $orders);
$total_affected_rows = $this->db->affected_rows();
$first_insert_id = $this->db->insert_id();
$last_id = ($first_insert_id + $total_affected_rows - 1);
You will need to do something like this,
$insertIds = array();
for ($x = 0; $x < sizeof($filtername); $x++) {
$orders = array(
'poid' => null,
'order_id' => $poid,
'item_desc' => $filtername[$x],
'item_qty' => $filterquantity[$x],
'item_price' => $filterprice[$x],
'total' => $filtertotal[$x],
'cash_on_delivery' => $val_delivery,
'is_check' => $val_check,
'bank_transfer' => $val_transfer,
'transaction_date' => $dateorder
);
$this->db->insert('po_order', $orders);
$insertIds[$x] = $this->db->insert_id(); //will return the first insert array
}
print_r($insertIds); //print all insert ids

PHP/mySQL: Import data and store in hierarchical nested set for use with jsTree

I'm using jsTree to view hierarchical data that is stored in a mySQL database as a nested set (left, right, level, etc.). This is working fine, but I need to allow users to import data by uploading a CSV file. When they do so, any existing data in the table will be removed so I don't have to worry about updating the left/right fields.
The data they will be uploading will be in this format:
"Code","Title"
"100","Unit 100"
"200","Unit 200"
"101","Task 101: This is a task"
"102","Task 102: Another task"
"201","Task 201: Yet another"
"300","Unit 300"
"301","Task 301: Another one"
Everything will be a child of a main "Group" that is a level 1 node. All of the "codes" divisible by 100 (ie. 100, 200, 300) will be level 2 (parent nodes.. children of "Group"). All others will be level 3 (child) nodes of their respective parent nodes (ie. 101 and 102 are children of 100, 201 is a child of 200, etc.)
The resulting table in mySQL should look like this:
id parent_id position left right level title
1 0 0 1 18 0 ROOT
2 1 0 2 17 1 Group
3 2 0 3 8 2 Unit 100
4 2 1 9 12 2 Unit 200
5 3 0 4 5 3 Task 101: This is a task
6 3 1 6 7 3 Task 102: Another task
7 4 0 10 11 3 Task 201: Yet another
8 2 2 13 16 2 Unit 300
9 8 0 14 15 3 Task 301: Another one
The tree would then look like this:
My question is: using PHP, what is the best method to accomplish this? I already have code in place that pulls the data contained in the uploaded CSV file and stores it in an array, but I'm not sure what the logic to convert this to a nested set should look like.
Right now, the data is stored in a 2-dimensional array called $data (in the format $data[$col][$row]):
$data[0][0] = "Code";
$data[0][1] = "100";
$data[0][2] = "200";
$data[0][3] = "101";
$data[0][4] = "102";
$data[0][5] = "201";
$data[0][6] = "300";
$data[0][7] = "301";
$data[1][0] = "Title";
$data[1][1] = "Unit 100";
$data[1][2] = "Unit 200";
$data[1][3] = "Task 101: This is a task";
$data[1][4] = "Task 102: Another task";
$data[1][5] = "Task 201: Yet another";
$data[1][6] = "Unit 300";
$data[1][7] = "Task 301: Another one";
Array ( [0] => Array ( [0] => Code [1] => 100 [2] => 200 [3] => 101 [4] => 102 [5] => 201 [6] => 300 [7] => 301 ) [1] => Array ( [0] => Title [1] => Unit 100 [2] => Unit 200 [3] => Task 101: This is a task [4] => Task 102: Another task [5] => Task 201: Yet another [6] => Unit 300 [7] => Task 301: Another one ) )
Any help would be very much appreciated. I now have the parent_id, position, and level being calculated correctly... I just need to figure out the left/right part. Here is the code I'm currently using (thanks for getting me started Matteo):
$rows = array();
// insert ROOT row
$rows[] = array(
'id' => 1,
'parent_id' => 0,
'position' => 0,
'left' => 1,
'right' => 10000, // just a guess, will need updated later
'level' => 0,
'title' => 'ROOT',
);
echo "<br>";
print_r($rows[0]);
// insert group row
$rows[] = array(
'id' => 2,
'parent_id' => 1,
'position' => 0,
'left' => 2,
'right' => 9999, // just a guess, will need updated later
'level' => 1,
'title' => 'Group',
);
echo "<br>";
print_r($rows[1]);
// next ID to be used
$id = 3;
// keep track of code => ID correspondence
$map = array();
// parse data
for ($i = 1, $c = count($data[0]); $i < $c; ++$i) {
// save ID in the map
$map[$data[0][$i]] = $id;
// initialize the current row
$row = array(
'id' => $id,
'parent_id' => 1,
'position' => 0,
'left' => 0,
'right' => 0,
'level' => 1,
'title' => $data[1][$i],
);
// if the code is multiple of 100
if ($data[0][$i] % 100 == 0) {
$row['parent_id'] = 2;
$row['level'] = 2;
$row['position'] = (floor($data[0][$i] / 100)) - 1;
} else {
// get parent id from map
$row['parent_id'] = $map[floor($data[0][$i] / 100) * 100];
$row['level'] = 3;
$row['position'] = $data[0][$i] % 100;
}
// add the row
$rows[] = $row;
++$id;
echo "<br>";
print_r($row);
}
Given your $data array, you could parse it like this:
// this will contain all the rows to be inserted in your DB
$rows = array();
// insert ROOT row
$rows[0] = array(
'id' => 1,
'parent_id' => 0,
'position' => 0,
'level' => 0,
'left' => 1,
'right' => 10000,
'title' => 'ROOT',
);
// insert group row
$rows[1] = array(
'id' => 2,
'parent_id' => 1,
'position' => 0,
'level' => 1,
'left' => 2,
'right' => 9999,
'title' => 'Group',
);
// keep trace of code => ID correspondence
$map = array();
// next ID to be used
$id = 3;
// keep father => sons relationship
$tree = array();
// keep trace of code => row index correspondence
$indexes = array();
// next row index
$index = 2;
// parse your data
for ($i = 1, $c = count($data[0]); $i < $c; ++$i) {
// current code
$code = $data[0][$i];
// save ID in the map
$map[$code] = $id;
// update the indexes map
$indexes[$code] = $index;
// prepare the current row
$row = array(
'id' => $id,
'title' => $data[1][$i],
)
// get the value of code mod 100
$mod = $code % 100;
// if the code is multiple of 100
if ($mod == 0) {
// the parent_id is 2
$row['parent_id'] = 2;
// it is level two
$row['level'] = 2;
// compute position
$row['position'] = floor($code / 100) - 1;
}
else {
// get the parent code
$parent = floor($code / 100) * 100;
// get parent id from map using parent code
$row['parent_id'] = $map[$parent];
// it is level three
$row['level'] = 3;
// save position
$row['position'] = $mod;
// save in relationship tree
$tree[$parent][] = $code;
}
// add the row
$rows[$index] = $row;
// prepare next id
++$id;
// update row index
++$index;
}
// sort the relationship tree base on the parent code (key)
ksort($tree, SORT_NUMERIC);
// next left value
$left = 3;
// now, using the relationship tree, assign left and right
foreach ($tree as $parent => $sons) {
// calculate parent left value
$parentLeft = $left;
// prepare next left value
++$left;
// to be sure that the sons are in order
sort($sons, SORT_NUMERIC);
// assign values to sons
foreach ($sons as $son) {
// index in the rows array
$index = $indexes[$son];
// set left value
$rows[$index]['left'] = $left;
// set right value
$rows[$index]['right'] = $left + 1;
// increment left value
$left += 2;
}
// calculate parent right value
$parentRight = $left;
// prepare next left value
++$left;
// index of parent in the rows array
$index = $indexes[$parent];
// set the values
$rows[$index]['left'] = $parentLeft;
$rows[$index]['right'] = $parentRight;
}
// update group row right value
$rows[1]['right'] = $left;
// prepare next left value
++$left;
// update root row right value
$rows[0]['right'] = $left;
At this point, you can insert all the rows one at a time.
EDIT: now the script should handle all the required values correctly.
I would use Doctrine2 with a Nested Set Extension. You could use a nice and convenient API and don't have to worry about the nested set implementation:
See
http://www.gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2
or http://wildlyinaccurate.com/simple-nested-sets-in-doctrine-2
There are several extensions on github. Actually, i don't know which one is best.
https://github.com/l3pp4rd/DoctrineExtensions
https://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior
https://github.com/blt04/doctrine2-nestedset
List item
If your data is flat, you could parse for keywords like 'Unit' or 'Task' to arrange your elements to the needed hierarchical order.

Categories