Multi-dimensional array parsed from .csv ->commas causing mysql database insert issues - codeigniter

I am using Codeigniter to parse an uploaded csv file (which is a multi-dimensional array) into a database. I have tried everything to parse the comma values correctly, but the "id" column in mysql comes up short, as it reads "text", and not "text,text,text". Help!?
*For reference:*
print_r($data['csvData']);
Array ( [0] => Array ( [category,id] => text1,"text,text,text" )
[1] => Array ( [category,id] => text2,"text,text,text" )
)
foreach($data['csvData'] as $row) {
foreach ($row as $item) {
$item=explode(",", $item);
$results_array = array(
'category' => $item[0],
'id' => $item[1]
);
$this->db->set($results_array);
$this->db->insert('table', $results_array);
}
}

My uneducated guess:
$item=explode(",", $item); is exploding $item which is text1,"text,text,text", right? So it sees 4 commas, and explodes them. Therefore $item[0] will be "text1, $item[1] will be "text" $item[2] will be "text" and $item[3] will be "text".
You can try to set your delimiter in the csv as something other than a comma, and explode that.
Or you can concatenate the other items before inserting them into the db:
$item = explode(",", $item);
$id_insert = $item[1].$item[2].$item[3];
//if you need to retain the commas in the id:
//$id_insert = $item[1].','.$item[2].','.$item[3];
$results_array = array(
'category' => $item[0],
'id' => $id_insert,
);
$this->db->set($results_array);
$this->db->insert('table', $results_array);

Related

Laravel insert or update multiple rows

Im new in laravel, and im trying to update my navigation tree.
So i want to update my whole tree in one query without foreach.
array(
array('id'=>1, 'name'=>'some navigation point', 'parent'='0'),
array('id'=>2, 'name'=>'some navigation point', 'parent'='1'),
array('id'=>3, 'name'=>'some navigation point', 'parent'='1')
);
I just want to ask - is there posibility in laravel to insert(if new in array) or update my current rows in database?
I want to update all, because i have fields _lft, _right, parent_id in my tree and im using some dragable js plugin to set my navigation structure - and now i want to save it.
I tried to use
Navigation::updateOrCreate(array(array('id' => '3'), array('id'=>'4')), array(array('name' => 'test11'), array('name' => 'test22')));
But it works just for single row, not multiple like i tried to do.
Maybe there is another way to do it?
It's now available in Laravel >= 8.x
The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. The method's third and final argument is an array of columns that should be updated if a matching record already exists in the database:
Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
I wonder why this kind of feature is not yet available in Laravel core (till today). Check out this gist The result of the query string would look like this: here
I am putting the code here just in case the link breaks in the future, I am not the author:
/**
* Mass (bulk) insert or update on duplicate for Laravel 4/5
*
* insertOrUpdate([
* ['id'=>1,'value'=>10],
* ['id'=>2,'value'=>60]
* ]);
*
*
* #param array $rows
*/
function insertOrUpdate(array $rows){
$table = \DB::getTablePrefix().with(new self)->getTable();
$first = reset($rows);
$columns = implode( ',',
array_map( function( $value ) { return "$value"; } , array_keys($first) )
);
$values = implode( ',', array_map( function( $row ) {
return '('.implode( ',',
array_map( function( $value ) { return '"'.str_replace('"', '""', $value).'"'; } , $row )
).')';
} , $rows )
);
$updates = implode( ',',
array_map( function( $value ) { return "$value = VALUES($value)"; } , array_keys($first) )
);
$sql = "INSERT INTO {$table}({$columns}) VALUES {$values} ON DUPLICATE KEY UPDATE {$updates}";
return \DB::statement( $sql );
}
So you can safely have your arrays inserted or updated as:
insertOrUpdate(
array(
array('id'=>1, 'name'=>'some navigation point', 'parent'='0'),
array('id'=>2, 'name'=>'some navigation point', 'parent'='1'),
array('id'=>3, 'name'=>'some navigation point', 'parent'='1')
)
);
Just in case any trouble with the first line in the function you can simply add a table name as a second argument, then comment out the line i.e:
function insertOrUpdate(array $rows, $table){
.....
}
insertOrUpdate(myarrays,'MyTableName');
NB: Be careful though to sanitise your input! and remember the timestamp fields are not touched. you can do that by adding manually to each arrays in the main array.
I've created an UPSERT package for all databases: https://github.com/staudenmeir/laravel-upsert
DB::table('navigation')->upsert(
[
['id' => 1, 'name' => 'some navigation point', 'parent' => '0'],
['id' => 2, 'name' => 'some navigation point', 'parent' => '1'],
['id' => 3, 'name' => 'some navigation point', 'parent' => '1'],
],
'id'
);
Eloquent Style
public function meta(){ // in parent models.
return $this->hasMany('App\Models\DB_CHILD', 'fk_id','local_fk_id');
}
.
.
.
$parent= PARENT_DB::findOrFail($id);
$metaData= [];
foreach ($meta['meta'] as $metaKey => $metaValue) {
if ($parent->meta()->where([['meta_key', '=',$metaKey]] )->exists()) {
$parent->meta()->where([['meta_key', '=',$metaKey]])->update(['meta_value' => $metaValue]);
}else{
$metaData[] = [
'FK_ID'=>$fkId,
'meta_key'=>$metaKey,
'meta_value'=> $metaValue
];
}
}
$Member->meta()->insert($metaData);
No, you can't do this. You can insert() multiple rows at once and you can update() multiple rows using same where() condition, but if you want to use updateOrCreate(), you'll need to use foreach() loop.
I didn't find a way to bulk insert or update in one query. But I have managed with only 3 queries. I have one table name shipping_costs. Here I want to update the shipping cost against the shipping area. I have only 5 columns in this table id, area_id, cost, created_at, updated_at.
// first get ids from table
$exist_ids = DB::table('shipping_costs')->pluck('area_id')->toArray();
// get requested ids
$requested_ids = $request->get('area_ids');
// get updatable ids
$updatable_ids = array_values(array_intersect($exist_ids, $requested_ids));
// get insertable ids
$insertable_ids = array_values(array_diff($requested_ids, $exist_ids));
// prepare data for insert
$data = collect();
foreach ($insertable_ids as $id) {
$data->push([
'area_id' => $id,
'cost' => $request->get('cost'),
'created_at' => now(),
'updated_at' => now()
]);
}
DB::table('shipping_costs')->insert($data->toArray());
// prepare for update
DB::table('shipping_costs')
->whereIn('area_id', $updatable_ids)
->update([
'cost' => $request->get('cost'),
'updated_at' => now()
]);
in your controller
use DB;
public function arrDta(){
$up_or_create_data=array(
array('id'=>2, 'name'=>'test11'),
array('id'=>4, 'name'=>'test22')
);
var_dump($up_or_create_data);
echo "fjsdhg";
foreach ($up_or_create_data as $key => $value) {
echo "key ".$key;
echo "<br>";
echo " id: ".$up_or_create_data[$key]["id"];
echo "<br>";
echo " Name: ".$up_or_create_data[$key]["name"];
if (Navigation::where('id', '=',$up_or_create_data[$key]["id"])->exists()) {
DB::table('your_table_ name')->where('id',$up_or_create_data[$key]["id"])->update(['name' => $up_or_create_data[$key]["name"]]);
}else{
DB::insert('insert into your_table_name (id, name) values (?, ?)', [$up_or_create_data[$key]["id"], $up_or_create_data[$key]["name"]]);
}
}

CSV export in php - csv row as a variable

I want to export a data into CSV file using PHP Laravel.
I used every row as a variable and add to csv at last. It helps me to create custom CSV file collumn header, so I must follow this rule.
What I have done is this-
$tweets = DB::select(DB::raw($query));
foreach ($tweets as $row)
{
$row = get_object_vars($row);
// iterate over each tweet and add it to the csv
$output .= implode(",",
array(
$row['completion_date'],
$row['site_id'],
$row['country'],
$row['state'],
$row['city'],
$row['active_ipp'],
$row['description_of_project'],
$row['total_excess_furniture']
)
); // append each row
$output .="\n"; //Adding New Line
}
$headers = array(
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment;filename="'.Carbon\Carbon::now()->toDateTimeString().'.csv"',
);
return Response::make(rtrim($output, "\n"), 200, $headers);
It is working with some errors.
The errors are, when there is a comma in the object string, it does not work perfectly.
So, I can't use implode I think.
Is there any other solution for adding CSV row as a variable like this?
You can try something along the lines of:
$items = [
[
'field1' => 'string with " quotes',
'field2' => 'string without commas',
],
[
'field1' => 'string without quotes',
'field2' => 'string, with, commas',
],
];
ob_start();
$buffer = fopen('php://output', 'w+');
foreach($items as $item) {
fputcsv($buffer, [
$item['field1'],
$item['field2'],
]);
}
$output = ob_get_clean();
fputcsv will deal with commas or quotes in your variables. Instead of writing the output to a file, you can send the output to a buffer and store it to a variable using ob_start and ob_get_clean.

codeignite trying to get property of non-object not resolved

I am attempting to access the result set from a model query in the view. I have the following:
Controller:
$courseId = $this->session->userdata('courseId');
//echo "Course: ".$courseId;
if(isset($courseId) && $courseId != '')
{
$result = $this->Course_model->loadBasicDetailsEdit($courseId);
$data['basicCourseDetails'] = $result;
$this->load->view('course/basicDetails', $data);
}
Model:
function loadBasicDetailsEdit($courseId)
{
$this->db->select('*');
$this->db->where('course_id', $courseId);
$this->db->from('course');
$query = $this->db->get();
if ( $query->num_rows() > 0 )
{
return $query->result();
} else {
return FALSE;
}
}
and in the view I tried to print_r() and got this:
Array ( [0] => stdClass Object ( [course_id] => 8 [title] => Photography [summary] => [description] => [price] => [member_id] => 12 [category] => [audience] => [goals] => [date] => 2013-09-26 [production] => 0 ) )
I tried to access this using $basicCourseDetails->title or $basicCourseDetails['title']
but neither are working. Any hint as to why this is happening?
Regards,
try this:
foreach($basicCourseDetails as $basic){
echo($basic->title);
}
or something like this:
echo($basicCourseDetails[0]->title);
This is an array of objects
Array ( [0] => stdClass Object ( [course_id] => 8 [title] => Photography [summary] => [description] => [price] => [member_id] => 12 [category] => [audience] => [goals] => [date] => 2013-09-26 [production] => 0 ) )
Contains one stdObject in the array, so, first objects is 0, if there were more, then second item could have index 1 and so on. To retrieve data from the first (here is only one) stdobject you may use
echo $basicCourseDetails[0]->title; // title will be printed
You can send data to the view page by this line of code which is mentioned in above question.
$result = $this->Course_model->loadBasicDetailsEdit($courseId);
$data['basicCourseDetails'] = $result;
$this->load->view('course/basicDetails', $data);
But when you will access these data in view then you need to access all data one by one by using foreachloop in the view page.
For example if you have a view page like basic_details.php inside course folder then you need to write code like this to access these data.
foreach ($basicCourseDetails as $key => $value) {
$name = $value->name;
}
The above foreachloop can be written in view page where you want to access data.

JRegistry exists() returns empty array

I was trying to save a form data to DB. In the controller save() function there is a statement
$data = $model->validate($form, $data);
But it always returns empty. I tracked down the problem to the filter() function in /libraries/joomla/form/form.php (comes with joomla package). Here is some code (shortened):
$input = new JRegistry($data);
$output = new JRegistry;
foreach ($fields as $field)
{
// Initialise variables.
$name = (string) $field['name'];
if ($input->exists($name)){
$output->set($name, $this->filterField($field, $input->get($name, (string) field['default'])));
}
}
$input looks like :
JRegistry Object ( [data:protected] => stdClass Object ( [jform] => stdClass Object ( [title] => Utility Model/Patent application [ap_name] => d ...) [option] => com_eipoapplications [task] => save ) )
And each $name in the loop always contain the form element name (like 'title', 'ap_name' ... ).
But the if conditional statement always returns false. Does any one help me know why JRegistry exists() function is not finding the elements?
I think you are having an inconsistency between form and data.
Let's say the form contains a field with name title.
$data array should have a value under key of same name:
$data = array(
'title' => 'Utility Model/Patent application',
'ap_name' => 'd'
);
Or using print_r
Array
(
[title] => Utility Model/Patent application
[ap_name] => d
)
If there's no data for such field, validation is omitted. If all data keys are wrong, function returns empty array.
The question is, how it happened :/

Codeigniter Update Multiple Records with different values

I'm trying to update a certain field with different values for different records.
If I were to use MySql syntax, I think it should have been:
UPDATE products
SET price = CASE id
WHEN '566423' THEN 49.99
WHEN '5681552' THEN 69.99
END
WHERE code IN ('566423','5681552');
But I prefer to use Active Record if it's possible.
My input is a tab delimited text which I convert into an array of the id and the desired value for each record:
$data = array(
array(
'id' => '566423' ,
'price' => 49.99
),
array(
'id' => '5681552' ,
'price' => 69.99
)
);
I thought this is the proper structure for update_batch, but it fails. Here's what I've tried:
function updateMultiple()
{
if($this->db->update_batch('products', $data, 'id'))
{
echo "updated";
}
else
{
echo "failed )-:";
}
}
And I get failed all the time. What am I missing?

Resources