I am just learning PHP and using the Codeigniter framework.
I'm using this code in my controller when inserting new data and it's working.
//INSERT MULTI ROWS TABEL harga_inventori
$kode_inventori = $_POST['kode_inventori'];
$result = array();
foreach($_POST['kode_kategori_pelanggan'] AS $key => $val){
$result[] = array(
"kode_kategori_pelanggan" => $_POST['kode_kategori_pelanggan'][$key],
"kode_inventori"=>$kode_inventori,
"harga" => $_POST['harga_jual'][$key],
"diskon" => $_POST['diskon'][$key]
);
}
$res = $this->db->insert_batch('harga_inventori', $result);
redirect("inventori");
But when I'm using the same pattern for the updating function, it's not working at all.
for($i = 0; $i < count($_POST['harga_jual'][$i]); $i++) {
if($_POST['kode_kategori_pelanggan'][$i] != '') {
$res[] = array(
'harga' => $_POST['harga_jual'][$i],
'diskon' => $_POST['diskon'][$i],
);
$this->db->where('kode_inventori',$_POST['kode_inventori']);
$this->db->where('kode_kategori_pelanggan',$_POST['kode_kategori_pelanggan'][$i]);
$this->db->update('harga_inventori',$res);
}
}
redirect("inventori");
I'm trying the update_batch() but I got many errors, so I'm using for loop and updating a single row at a time.
What could be the problem here?
Its only a typo. You should pass the array $res not $data, and change $res[] to $res since it is not needed. You should also check with isset() to prevent errors of undefined:
for($i = 0; $i < count($_POST['harga_jual'][$i]); $i++) {
if(isset($_POST['kode_kategori_pelanggan'][$i])) {
$res = array(
'harga' => $_POST['harga_jual'][$i],
'diskon' => $_POST['diskon'][$i],
);
$this->db->where('kode_inventori',$_POST['kode_inventori']);
$this->db->where('kode_kategori_pelanggan',$_POST['kode_kategori_pelanggan'][$i]);
$this->db->update('harga_inventori',$res);
}
}
redirect("inventori");
It would help to see some of your data to know what you are trying to do. It seems a little strange that you initiate the counter $i at the same time using it as an array key in the for loop like this: for($i = 0; $i < count($_POST['harga_jual'][$i]); $i++)
It would help to know how the data in your $_POST looks like. You could try to remove the [$i] in your for loop. I would also check each POST variable it they are set before using them, something like:
for($i = 0; $i < count($_POST['harga_jual']); $i++) {
if(isset($_POST['kode_kategori_pelanggan'][$i])) {
// CHECK IF POST VARIABLES IS SET AND IF NOT SET A DEFAULT VALUE (IN THIS EXAMPLE AN EMPTY STRING):
$harga_jual = isset($_POST['harga_jual'][$i]) ? $_POST['harga_jual'][$i] : '';
$diskon = isset($_POST['diskon'][$i]) ? $_POST['diskon'][$i] : '';
$kode_inventori = isset($_POST['kode_inventori']) ? $_POST['kode_inventori'] : '';
$kode_kategori_pelanggan = $_POST['kode_kategori_pelanggan'][$i]; // ALREADY CHECKED ISSET ABOVE...
$data = array(
'harga' => $harga_jual,
'diskon' => $diskon,
);
$this->db->where('kode_inventori',$kode_inventori);
$this->db->where('kode_kategori_pelanggan', $kode_kategori_pelanggan);
$this->db->update('harga_inventori', $data);
}
}
redirect("inventori");
Related
I have a phone book array I get from a database, where everyone appears once with their stationary phone number and a second with their mobile number.
I need to make this an array where everyone has only one line, with their phone number and mobile number
//My array
$data = array(
array('name'=>'robert','family'=>'bridgstone','home'=>'0258101234'),
array('name'=>'robert','family'=>'bridgstone','phone'=>'07258101235'),
array('name'=>'dan','family'=>'swartz','home'=>'098101244'),
array('name'=>'ben','family'=>'wais','home'=>'0447256155778'),
array('name'=>'ben','family'=>'wais','phone'=>'04472861558878'),
);
//The result that should come out
$data = array(
array('name'=>'robert','family'=>'bridgstone','home'=>'0258101234','phone'=>'07258101235'),
array('name'=>'dan','family'=>'swartz','home'=>'098101244','phone'=>''),
array('name'=>'ben','family'=>'wais','home'=>'0447256155778','phone'=>'04472861558878')
);
I would do it the following way:
first I would generate a unique key that identify the row (in your case the name and the family, for example).
then check if a element with the same key exist, if it already exist merge the two component.
Optional if you only want an array of values transform the result with array_value function.
$dataArray = array(
array('name'=>'robert','family'=>'bridgstone','home'=>'0258101234'),
array('name'=>'robert','family'=>'bridgstone','phone'=>'07258101235'),
array('name'=>'dan','family'=>'swartz','home'=>'098101244'),
array('name'=>'ben','family'=>'wais','home'=>'0447256155778'),
array('name'=>'ben','family'=>'wais','phone'=>'04472861558878'),
);
$result = [];
foreach($dataArray as $data){
//Just in case that the name or the family is not assigned (operator ??)
$key = ($data['name']??'').'-'.($data['family']??'');
$result[$key] = array_merge($result[$key]??[],$data);
}
//Optional, get only the array values
$result = array_values($result);
I did so
$data = array(
array('name'=>'robert','family'=>'bridgstone','home'=>'0258101234'),
array('name'=>'robert','family'=>'bridgstone','phone'=>'07258101235'),
array('name'=>'dan','family'=>'swartz','home'=>'098101244'),
array('name'=>'ben','family'=>'wais','home'=>'0447256155778'),
array('name'=>'ben','family'=>'wais','phone'=>'04472861558878'),
);
count($data) < 2 ? exit(): $data;
for($i=0;$i<count($data);$i++){
$array_unique[$i] = $data[$i]["name"];
$array_unique[$i] = $data[$i]["family"];
}
$array_unique = array_unique($array_unique);
if(count($array_unique) == 1){
$last_array[0]=$array_unique[0];
$last_array[0]["phone"]=$array_unique[0]["phone"];
}
else{
$array_uniqueKeys = array_keys($array_unique);
for($i = 0;$i < count($array_unique);$i++){
$firstIndex = $i + 1;
$firstIndex == count($array_unique) ? $nextKey = count($data) : $nextKey = $array_uniqueKeys[$firstIndex];
$paar = $nextKey - $array_uniqueKeys[$i];
$dataslice = array();
$i3=0;
for($i2 = $array_uniqueKeys[$i];$i2 < ($array_uniqueKeys[$i]+$paar);$i2++){
if(in_array($i2,$array_uniqueKeys)){
$last_array[$i]=$data[$i2];
}
else{
$last_array[$i]["phone"]=$data[$i2]["phone"];
}
$i3++;
}
}
}
print_r($last_array);
I use CodeIgniter, and when an insert_batch does not fully work (number of items inserted different from the number of items given), I have to do the inserts again, using insert ignore to maximize the number that goes through the process without having errors for existing ones.
When I use this method, the kind of data I'm inserting does not need strict compliance between the number of items given, and the number put in the database. Maximize is the way.
What would be the correct way of a) using insert_batch as much as possible b) when it fails, using a workaround, while minimizing the number of unnecessary requests?
Thanks
The Correct way of inserting data using insert_batch is :
CI_Controller :
public function add_monthly_record()
{
$date = $this->input->post('date');
$due_date = $this->input->post('due_date');
$billing_date = $this->input->post('billing_date');
$total_area = $this->input->post('total_area');
$comp_id = $this->input->post('comp_id');
$unit_id = $this->input->post('unit_id');
$percent = $this->input->post('percent');
$unit_consumed = $this->input->post('unit_consumed');
$per_unit = $this->input->post('per_unit');
$actual_amount = $this->input->post('actual_amount');
$subsidies_from_itb = $this->input->post('subsidies_from_itb');
$subsidies = $this->input->post('subsidies');
$data = array();
foreach ($unit_id as $id => $name) {
$data[] = array(
'date' => $date,
'comp_id' => $comp_id,
'due_date' => $due_date,
'billing_date' => $billing_date,
'total_area' => $total_area,
'unit_id' => $unit_id[$id],
'percent' =>$percent[$id],
'unit_consumed' => $unit_consumed[$id],
'per_unit' => $per_unit[$id],
'actual_amount' => $actual_amount[$id],
'subsidies_from_itb' => $subsidies_from_itb[$id],
'subsidies' => $subsidies[$id],
);
};
$result = $this->Companies_records->add_monthly_record($data);
//return from model
$total_affected_rows = $result[1];
$first_insert_id = $result[0];
//using last id
if ($total_affected_rows) {
$count = $total_affected_rows - 1;
for ($x = 0; $x <= $count; $x++) {
$id = $first_insert_id + $x;
$invoice = 'EBR' . date('m') . '/' . date('y') . '/' . str_pad($id, 6, '0', STR_PAD_LEFT);
$field = array(
'invoice_no' => $invoice,
);
$this->Companies_records->add_monthly_record_update($field,$id);
}
}
echo json_encode($result);
}
CI_Model :
public function add_monthly_record($data)
{
$this->db->insert_batch('monthly_record', $data);
$first_insert_id = $this->db->insert_id();
$total_affected_rows = $this->db->affected_rows();
return [$first_insert_id, $total_affected_rows];
}
AS #q81 mentioned, you would split the batches (as you see fit or depending on system resources) like this:
$insert_batch = array();
$maximum_items = 100;
$i = 1;
while ($condition == true) {
// code to add data into $insert_batch
// ...
// insert the batch every n items
if ($i == $maximum_items) {
$this->db->insert_batch('table', $insert_batch); // insert the batch
$insert_batch = array(); // empty batch array
$i = 0;
}
$i++;
}
// the last $insert_batch
if ($insert_batch) {
$this->db->insert_batch('table', $insert_batch);
}
Edit:
while insert batch already splits the batches, the reason why you have "number of items inserted different from the number of items given" might be because the allowed memory size is reached. this happened to me too many times.
I'm trying to update multiple records in codeigniter using update_batch, but it doesn't work. here's my code
public function update {
$id = $this->input->post('id');
$id_sumber = $this->input->post('id_sumber');
$nominal = $this->input->post('nominal');
$jumlah = count($id);
$data = array();
for ($x=0; $x< $jumlah; $x++){
$data[] = array(
'id' => $id[$x],
'id_sumber' => $id_sumber[$x],
'nominal' => $nominal[$x]
);
}
$this->db->update_batch('road_map',$data,'id');
}
change this line:
$this->db->update_batch('road_map',$data,'id');
Id must be array of where condition.
I know basic PHP and all I know I've learned on google during the past years.
With that said, I'm developing a new website and I'm experimenting with clean URLs for SEO purposes and multi-regional languages compatibility.
So I have this array:
$list['requests']['en'] = array(
'index' => array(
0,
'subscribe',
'search'
),
'services' => array(
0,
'next' => array(
'service1',
'service2',
'service3'
),
'subscribe',
'search'
),
'service1' => array(
0,
'subscribe'
),
'service2' => array(
1,
'next' => array(
'view'
),
'jump' => 1,
'subscribe',
'search'
),
'service3' => array(
1,
'subscribe',
),
'view' => array(
2,
'subscribe'
),
'bad-request' => array(
0,
'subscribe'
)
);
Where $list['requests']['en'][$page][0] is the level of the page in the url and $list['requests']['en'][$page]['next'] is a list of valid pages that can follow.
That array is used to validate a URLs, so this is a valid one: www.website.com/services/service2/view
My real problem is that I want to loop throug that array and follow every page in the 'next' list so I have a function to create files like this: en/services.service1.view.php
I alreday created a chain of loops that do the job, but it's not generic. It's limited to the amount of loops I type in myself. This code for example, only runs throug 4 loops:
if(isset($list['requests'][$lang][$list_keys[$j]]['next'])){
for($l = 0; !empty($list['requests'][$lang][$list_keys[$j]]['next'][$l]) && $l < $for_max; $l++){
$next = $list['requests'][$lang][$list_keys[$j]]['next'][$l];
$file_next = $file[0].'.'.$next;
$file[] = $file_next;
if(isset($list['requests'][$lang][$next]['next'])){
for($n = 0; !empty($list['requests'][$lang][$next]['next'][$n]) && $n < $for_max; $n++){
$next_1 = $list['requests'][$lang][$next]['next'][$n];
$file_next_1 = $file_next.'.'.$next_1;
$file[] = $file_next_1;
if(isset($list['requests'][$lang][$next_1]['next'])){
for($o = 0; !empty($list['requests'][$lang][$next_1]['next'][$o]) && $o < $for_max; $o++){
$next_2 = $list['requests'][$lang][$next_1]['next'][$o];
$file_next_2 = $file_next_1.'.'.$next_2;
$file[] = $file_next_2;
if(isset($list['requests'][$lang][$next_2]['next'])){
for($p = 0; !empty($list['requests'][$lang][$next_2]['next'][$p]) && $p < $for_max; $p++){
$next_3 = $list['requests'][$lang][$next_2]['next'][$p];
$file_next_3 = $file_next_2.'.'.$next_3;
$file[] = $file_next_3;
}
}
}
}
}
}
}
}
This code saves every unique file name from the array chain.
The output would be something like this:
index.php
services.php
services.service1.php
services.service2.php
services.service2.view.php
services.service3.php
...
I've tried to make generic functions to do this but with no success.
Any ideas?
EDIT:
I just came up with an idea to simplify the code with an include. Nevermind my variables, the point here is to make a script that perceives the depth of loops itself.
The hole script for the purpose of context:
<?php
include 'includes/lists/languages.php';
include 'includes/lists/requests.php';
$for_max = 15;
// create requests files for each language
for($i = 0; isset($list['languages'][$i]) && $i < $for_max; $i++){
$lang = $list['languages'][$i];
$requests_keys = array_keys($list['requests'][$lang]);
echo 'LANG: '.$lang.'<br/>';
for($j = 0; isset($list['requests'][$lang][$requests_keys[$j]]) && $j < $for_max; $j++){
if($list['requests'][$lang][$requests_keys[$j]][0] == 0){
$file = array();
$file[] = $requests_keys[$j];
/* NEXT PART LOOP */
$loop = array();
$depth = 0;
$part = array();
$part['next'] = array();
$part['file'] = array();
// these vars are unique for the first loop, then it's generic
$part['next'][$depth-1] = $requests_keys[$j];
$part['file'][$depth-1] = $file[0];
// loop through every 'next' part if it exists in the current part
if(isset($list['requests'][$lang][ $part['next'][$depth-1] ]['next'])){
include '___construct_files.recursive.php';
}
/* CREATE REQUEST FILE */
for($k = 0; $k < count($file); $k++){
$path = 'includes/requests/'.$lang.'/'.$file[$k].'.php';
// string to insert in the file
include '___construct_files.string.php';
// processing
if(!file_exists($path)){
file_put_contents($path, $string);
echo '<br/># created - '.$path.'<br/>';
}else if(file_exists($path)){
echo '<br/># exists - '.$path.'<br/>';
}else{
echo '<br/># error - '.$path.'<br/>';
}
}
}
}
echo '<br/><br/>';
}
?>
The loop is included and verifies if it's needed to be included again in itself (___construct_files.recursive.php):
<?php
for($loop[$depth] = 0; !empty($list['requests'][$lang][ $part['next'][$depth-1] ]['next'][ $loop[$depth] ]) && $loop[$depth] < $for_max; $loop[$depth]++){
$part['next'][$depth] = $list['requests'][$lang][ $part['next'][$depth-1] ]['next'][ $loop[$depth] ];
$part['file'][$depth] = $part['file'][$depth-1].'.'.$part['next'][$depth];
$file[] = $part['file'][$depth];
// if next part is set, increase depth and include loop
if(isset($list['requests'][$lang][ $part['next'][$depth] ]['next'])){
$depth++;
include '___construct_files.recursive.php';
}
}
// decrease depth when higher depth loop ends so the current loop can resume
$depth--;
?>
I'm creating a data.php file which returns a json file to a html file where I fill up a grid with the data from the data.php file.
I need this to be an associative array in the following form:
[
{"CompanyName":"Alfreds Futterkiste","ContactName":"Maria Anders","ContactTitle":"Sales Representative"},
{"CompanyName":"Ana Trujillo Emparedados y helados","ContactName":"Ana Trujillo","ContactTitle":"Owner"},
{"CompanyName":"Antonio Moreno Taquera","ContactName":"Antonio Moreno","ContactTitle":"Owner"}
]
Now the problem is, I want this data.php to be sort of generic, which means I don't know the columnnames nor the the amount of columns.
The only way I get this done, is by using a switch statement but this is not ideal (because I can make a number of cases but what if the table has one more column) nor is it very elegant.
I bet this can be done far better, any ideas ?
I tried using array_push() but that doesn't work with associative arrays.
// get columnnames
for ($i = 0; $i < $result->columnCount(); $i++) {
$col = $result->getColumnMeta($i);
$columns[] = $col['name'];
}
// fill up array
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
switch (count($columns);) {
case 1 :
$records[] = array($columns[0] => $row[$columns[0]]);
break;
case 2 :
$records[] = array($columns[0] => $row[$columns[0]], $columns[1] => $row[$columns[1]]);
break;
case 3 :
$records[] = array($columns[0] => $row[$columns[0]], $columns[1] => $row[$columns[1]], $columns[2] => $row[$columns[2]]);
break;
case ... // and so on
}
}
// send data to client
echo json_encode($records);
change the switch code segment with this one
$arr_tmp = array();
for($i = 0; $i < count($columns); $i++)
{
$arr_tmp[$columns[$i]] = $row[$columns[$i]];
}
$records []= $arr_tmp;
You could iterate over the columns:
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
$values = array();
foreach ($columns as $column) {
values[$column] = $row[$column];
}
records[] = $values;
}