php : csv import to multiple table is taking too long - php

i am using csv importer library to load bulk of products into mysql database with codeigniter. csv file has some column names from one table like name, price and some column names from another table like categories. it inserts name and price to first table and categories will be inserted after we got id from first table, so category will go with id of the product. but this is taking too long to process the csv file (1000 entries = 2 minutes). the code i have put is
$csv_file_data = $this->csvimport->get_array($_FILES['csv']['tmp_name']);
foreach ($csv_file_data as $csv_data) {
$required = array(
'name' => $csv_data['name'],
'price' => $csv_data['price']
);
foreach ($required as $key => $value) {
$this->db->set($key, $value);
}
$categories= array();
foreach ($csv_data as $key => $value) {
if(strstr($key, 'categories')) {
$category = explode('|', $value);
for($i = 0; $i < sizeof($category); $i++) {
array_push($categories, $category[$i]);
}
}
}
$this->db->insert('first_table');
$id = $this->db->insert_id();
foreach ($categories as $metatag) {
$this->db->set('productid', $id);
$this->db->set('category', $metatag);
$this->db->insert('second_table');
}
}
but it is taking too long to process only 1000 entries, how to optimize this to process 5000 entries in less than 20-30 seconds ?

I believe this is what you're after ...
$csv_file_data = $this->csvimport->get_array($_FILES['csv']['tmp_name']);
foreach ($csv_file_data as $csv_data) {
$required = array(
'name' => $csv_data['name'],
'price' => $csv_data['price']
);
$this->db->set($required);
$categories = array();
foreach ($csv_data as $key => $value) {
if (strstr($key, 'categories')) {
$category = explode('|', $value);
for ($i = 0; $i < sizeof($category); $i++) {
$categories[] = $category[$i];
}
}
}
$this->db->insert('first_table');
$bulk = array();
$id = $this->db->insert_id();
foreach ($categories as $metatag) {
$bulk[] = array(
'category' => $metatag,
'productid' => $id,
);
}
$this->db->insert_batch('table2', $bulk);
}
Note the use of insert_batch which will dramatically improve your speed and also you can give set() an array.

Can you try a version like this and tell me if this is working and return me the time for 100 rows ?
$bulk = [];
$csv_file_data = $this->csvimport->get_array($_FILES['csv']['tmp_name']);
$required = [];
foreach ($csv_file_data as $csv_data) {
$bulk = [];
$id = $this->db->insert_id();
$required[] = [
'name' => $csv_data['name'],
'price' => $csv_data['price'],
];
foreach ($csv_data as $key => $value) {
if (false !== strpos($key, 'categories')) {
$category = explode('|', $value);
foreach ($category as $metatag) {
$bulk[] = [
'category' => $metatag,
'productid' => $id,
];
}
}
}
}
$this->db->insert_batch('first_table', $required);
$this->db->insert_batch('second_table', $bulk);

Related

How to write category and subcategory with foreach?

I have a database category table , With 3 fields id,name,cate . And I put it into array
$select = $this->db->get_where('cate',array('cate >'=> 0))->result_array();
I want to write a foreach that
if (cate == 1) : This is the main menu
else if (cate == main menu id) : this is subcategory
Here is what I have tried
foreach ($select as $key => $value) {
$id = $value['id'];
$name = $value['name'];
$cate = $value['cate'];
}
I'm sorry for my poor English
it's my solution:
$categoriesHierchy = [];
foreach ($categories as $mainCategory) {
$childNode = [
'id' => $mainCategory->getID(),
'polishName' => $mainCategory->getPolishName(),
'children' => findChildrenOfCategory($mainCategory)
];
array_push($categoriesHierchy, $childNode);
}
public function findChildrenOfCategory($category)
{
$children = [];
if (count($category->getChildren()) > 0) {
foreach ($category->getChildren() as $child) {
$childCategories = findChildrenOfCategory($child);
$childNode = [
'id' => $child->getID(),
'polishName' => $child->getPolishName(),
'children' => $childCategories
];
array_push($children, $childNode);
}
}
return $children;
}
foreach ($select as $value) { //selecting each row/element
$cate = $value['cate']; //grabbing column values
$name = $value['name'];
If($cate == 1){ //no need of cate == main cate id
echo $name." is a main";
}else{
echo $name." is a sub";
}
}

Dumping tables into json from external page

I have this partially working. I need to grab the data of each player, and present a variable for each "cricket" and "x01" games. I am able to grab the data from the top table, however the 2nd one is not showing any data in my code. I am probably missing something simple, but I can't figure it out.
I want the output to show like this. The part under the line break is what I am missing.
"Howard Hill": {
"name": "Howard Hill",
"team": "Team 2",
"ppd_01": "34.54",
"games_01": "153",
"wins_01": "999",
"assists_01": "69",
"sspre_01": "7.876",
"mpr_crk": "9.99",
"games_crk": "999",
"wins_crk": "999",
"assists_crk": "99",
"sspre_crk": "9.999"
}
Here is my code
<?php
ini_set('default_socket_timeout', 180); // 900 Seconds = 15 Minutes
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(file_get_contents('http://freerdarts.com/past_stats/tues-2018-player-standings.html'));
$doc->strictErrorChecking = false;
$pre = [];
foreach ($doc->getElementsByTagName('table') as $table) {
foreach ($table->getElementsByTagName('tr') as $i => $tr) {
$y = 0;
foreach ($tr->childNodes as $td) {
$text = trim($td->nodeValue);
if ($y > 7) {
unset($pre[$i]);
continue;
}
if (empty($text)) {
continue;
}
$pre[$i][] = $text;
$y++;
}
}
}
// normalise
$pstats = [];
foreach ($pre as $row) {
$pstats[$row[0]] = [
'name' => $row[0],
'team' => $row[1],
'ppd_01' => $row[2],
'games_01' => $row[3],
'wins_01' => $row[4],
'sspre_01' => $row[5],
];
}
echo '<pre>'.json_encode($pstats, JSON_PRETTY_PRINT).'</pre>';
//echo $pstats['Scott Sandberg']['01'];
?>
One problem you're facing is that you're not getting the proper table that needs parsing.
Take note there are multiple tables inside that page.
You need to point out inside the loop that you're skipping other tables in the HTML page and only choose to process the score report table, nothing else:
if (strpos($table->getAttribute('class'), 'report') === false) {
continue;
}
So after getting other tables out of the way, you can start processing the data inside the specific table results that you want to store.
Another thing to point out is you need to skip the headers inside the table. You don't need to anyways.
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
After that, its just a matter of looping on each <td>.
One gotcha on the tables is that one table has six 6 columns. Another one has 7 so first gather all <td> values. After gathering just unset it from the gathered data so that you have a uniform column layout structure. (I assume you're trying to skip out assists)
Here's the full code:
$pre = []; // initialize container
$keys = ['name', 'team', 'ppd', 'games', 'wins', 'sspre']; // keys needed to be used in the json
foreach ($doc->getElementsByTagName('table') as $table) { // loop all found tables
if (strpos($table->getAttribute('class'), 'report') === false) {
continue; // if its not the report table, skip
}
foreach ($table->getElementsByTagName('tr') as $i => $tr) { // loop each row of report table
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
$row_values = []; // initialize container for each row
foreach ($tr->childNodes as $td) { // loop each cell
$text = trim($td->nodeValue); //
if ($text === '') continue;
$row_values[] = $text;
}
// unset assist if this table has 7 columns
if (count($row_values) === 7) unset($row_values[5]);
$row_values = array_combine($keys, $row_values); // combine the keys and values
$pre[$row_values['name']] = $row_values; // push them inside
}
}
// finally encode in the end
echo json_encode($pre);
Here's the sample output
I have modified #Ghost code. Try below code.
<?php
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML(file_get_contents('http://freerdarts.com/past_stats/tues-2018-player-standings.html'));
$doc->strictErrorChecking = false;
$pre = [];
$keys = ['name', 'team', 'ppd', 'games', 'wins', 'sspre'];
$keys2 = ['name', 'mpr', 'games', 'wins','assists', 'sspre'];
foreach ($doc->getElementsByTagName('table') as $k => $table) {
if (strpos($table->getAttribute('class'), 'report') === false) {
continue;
}
foreach ($table->getElementsByTagName('tr') as $i => $tr) {
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
$row_values = [];
foreach ($tr->childNodes as $td) {
$text = trim($td->nodeValue);
if ($text === '') continue;
$row_values[] = $text;
}
if($k == 1 ){
$row_values = array_combine($keys, $row_values);
}elseif($k == 2 ){
unset($row_values[1]);
$row_values = array_combine($keys2, $row_values);
}
$pre[$row_values['name']][] = $row_values;
}
}
$new_arr = [];
foreach($pre as $name => $row){
$new_arr[$name] = [
"name"=> $name,
"team"=> $row[0]['team'],
"ppd_01" => $row[0]['ppd'],
"games_01" => $row[0]['games'],
"wins_01" => $row[0]['wins'],
"sspre_01" => $row[0]['sspre'],
"mpr_crk" => $row[1]['mpr'],
"games_crk" => $row[1]['games'],
"wins_crk" => $row[1]['wins'],
"assists_crk" => $row[1]['assists'],
"sspre_crk" => $row[1]['sspre']
];
}
echo '<pre>'.json_encode($new_arr, JSON_PRETTY_PRINT).'</pre>';
Here is sample output
https://www.tehplayground.com/Du5rId3iRx3NH6UL
It seems to me that you want to combine the x01 table values with the crk table values under the same name. Here is the code that I think you are looking for with an example.
$x01 = [];
$crk = [];
$keys_01 = ['name', 'team', 'ppd_01', 'games_01', 'wins_01', 'sspre_01'];
$keys_crk = ['name', 'team', 'mpr_crk', 'games_crk', 'wins_crk', 'assists_crk', 'sspre_crk'];
$table_num = 1;
foreach ($doc->getElementsByTagName('table') as $table) {
if (strpos($table->getAttribute('class'), 'report') === false) {
continue;
}
foreach ($table->getElementsByTagName('tr') as $i => $tr) {
if ($tr->parentNode->nodeName === 'thead') continue; // skip headers
$row_values = [];
foreach ($tr->childNodes as $td) {
$text = trim($td->nodeValue);
if ($text === '') continue;
$row_values[] = $text;
}
// build x01 array
if ($table_num === 1) {
$row_values = array_combine($keys_01, $row_values);
$x01[$row_values['name']] = $row_values;
// build crk array
} else {
$row_values = array_combine($keys_crk, $row_values);
$crk[$row_values['name']] = $row_values;
}
}
$table_num++;
}
$combined = array_merge_recursive($x01, $crk);
// after arrays are merged, remove duplicate values
foreach ($combined as $name => $value) {
if ($value['name']) {
$combined[$name]['name'] = $name;
}
if ($value['team']) {
$combined[$name]['team'] = $value['team'][0];
}
}
echo json_encode($combined, JSON_PRETTY_PRINT);

How to compare two values from different foreach loop in PHP?

Here is My codes,
My question is if $company_id from foreach one equal to $Company_id from foreach two then echo company_name.
$ids = array();
$x = array();
$a = array();
foreach($companieslist as $keys=>$company) {
$x[$company->company_id] = [
'id' => $company->company_id,
'name' => $company->company_name
];
}
$entry = $a[$id];
foreach($uploads as $keys=>$general){
$ids[] = $general->Contract_Id;
$c_id = $general->Company_id;
....
Just talking from the performance side, what you should do is extract the company ids from the second batch to an array first, like this
$companies = array();
foreach ( $uploads as $keys => $general ) {
array_push( $companies, $general->Company_id );
}
Now, in the first foreach loop, you can just check if the company id exists in this $companies array, and then decide what to do
foreach($companieslist as $keys=>$company){
if(in_array($company->company_id,$companies)){
echo "Found {$company->company_id}<br/>\n";
}
}

Create array nested PHP

Hi all' I have a page into PHP where I retrieve XML data from a server and I want to store this data into an array.
This is my code:
foreach ($xml->DATA as $entry){
foreach ($entry->HOTEL_DATA as $entry2){
$id = (string)$entry2->attributes()->HOTEL_CODE;
$hotel_array2 = array();
$hotel_array2['id'] = $entry2->ID;
$hotel_array2['name'] = utf8_decode($entry2->HOTEL_NAME);
$i=0;
foreach($entry2->ROOM_DATA as $room){
$room_array = array();
$room_array['id'] = (string)$room->attributes()->CCHARGES_CODE;
$hotel_array2['rooms'][$i] = array($room_array);
$i++;
}
array_push($hotel_array, $hotel_array2);
}
}
In this mode I have the array hotel_array which all hotel with rooms.
The problem is that: into my XML I can have multiple hotel with same ID (the same hotel) with same information but different rooms.
If I have an hotel that I have already inserted into my hotel_array I don't want to insert a new array inside it but I only want to take its rooms array and insert into the exisiting hotel.
Example now my situation is that:
hotel_array{
[0]{
id = 1,
name = 'test'
rooms{
id = 1
}
}
[0]{
id = 2,
name = 'test2'
rooms{
id = 100
}
}
[0]{
id = 1,
name = 'test'
rooms{
id = 30
}
}
}
I'd like to have this result instead:
hotel_array{
[0]{
id = 1,
name = 'test'
rooms{
[0]{
id = 1
}
[1]{
id = 30
}
}
}
[0]{
id = 2,
name = 'test2'
rooms{
id = 100
}
}
}
How to create an array like this?
Thanks
first thing is it helps to keep the hotel id as the index on hotel_array when your creating it.
foreach ($xml->DATA as $entry){
foreach ($entry->HOTEL_DATA as $entry2){
$id = (string)$entry2->attributes()->HOTEL_CODE;
$hotel_array2 = array();
$hotel_array2['id'] = $entry2->ID;
$hotel_array2['name'] = utf8_decode($entry2->HOTEL_NAME);
$i=0;
foreach($entry2->ROOM_DATA as $room){
$room_array = array();
$room_array['id'] = (string)$room->attributes()->CCHARGES_CODE;
$hotel_array2['rooms'][$i] = array($room_array);
$i++;
}
if (!isset($hotel_array[$hotel_array2['id']])) {
$hotel_array[$hotel_array2['id']] = $hotel_array2;
} else {
$hotel_array[$hotel_array2['id']]['rooms'] = array_merge($hotel_array[$hotel_array2['id']]['rooms'], $hotel_array2['rooms']);
}
}
}
Whilst this is the similar answer to DevZer0 (+1), there is also quite a bit that can be done to simplify your workings... there is no need to use array_merge for one, or be specific about $i within your rooms array.
$hotels = array();
foreach ($xml->DATA as $entry){
foreach ($entry->HOTEL_DATA as $entry2){
$id = (string) $entry2->attributes()->HOTEL_CODE;
if ( empty($hotels[$id]) ) {
$hotels[$id] = array(
'id' => $id,
'name' => utf8_decode($entry2->HOTEL_NAME),
'rooms' => array(),
);
}
foreach($entry2->ROOM_DATA as $room){
$hotels[$id]['rooms'][] = array(
'id' => (string) $room->attributes()->CCHARGES_CODE;
);
}
}
}
Just in case it helps...
And this :)
$hotel_array = array();
foreach ($xml->DATA as $entry)
{
foreach ($entry->HOTEL_DATA as $entry2)
{
$hotel_code = (string) $entry2->attributes()->HOTEL_CODE;
if (false === isset($hotel_array[$hotel_code]))
{
$hotel = array(
'id' => $entry2->ID,
'code' => $hotel_code,
'name' => utf8_decode($entry2->HOTEL_NAME)
);
foreach($entry2->ROOM_DATA as $room)
{
$hotel['rooms'][] = array(
'id' => (string)$room->attributes()->CCHARGES_CODE,
);
}
$hotel_array[$hotel_code] = $hotel;
}
}
}

Kohana 3.2 'advance' ORM joins

This is Database ERD that I use in application. I'm using Kohana 3.2. What I want to achieve is to generate menu for currently logged user. Each user can have many roles, so based on that user should get menu populated with modules (that are in relation with menu and user).
I have achieve this through several foreach loops. Is it possible to do this using ORM ?
*Table 'Modules' represents menu items.
Edit: this is my current code.
$conf_modules = Kohana::$config->load('modules');
$user_roles = $user->roles->find_all();
$result = array();
$array = array();
foreach($user_roles as $user_role)
{
$menus = $user_role->menus->find_all();
$modules = $user_role->modules->find_all();
}
foreach($menus as $menu)
{
$m = $menu->modules->find_all();
$result[]['name'] = $menu->name;
foreach ($m as $a)
{
foreach ($modules as $module)
{
if($a->name == $module->name)
{
foreach ($conf_modules as $key => $value)
{
if($module->name == $key)
{
$array = array(
'module_name' => $module->name,
'text' => $module->display_desc,
'url' => $value['url'],
);
}
}
}
}
array_push($result, $array);
}
}
I think this should be good solution.
$user = Auth::instance()->get_user();
$user_roles = $user->roles->find_all();
$conf_modules = Kohana::$config->load('modules');
$role_modules = ORM::factory('module')
->join('roles_modules')
->on('roles_modules.module_id','=','module.id')
->where('role_id','IN',$user_roles->as_array(NULL,'id'))
->find_all();
$role_menus = ORM::factory('menu')
->join('roles_menus')
->on('roles_menus.menu_id','=','menu.id')
->where('role_id','IN',$user_roles->as_array(NULL,'id'))
->find_all();
$result = array();
foreach ($role_menus as $role_menu)
{
$menu_modules = $role_menu->modules->find_all();
if ( ! isset($result[$role_menu->name]))
$result[$role_menu->name] = array('name' => $role_menu->name);
foreach ($menu_modules as $menu_module)
{
foreach ($role_modules as $role_module)
{
if($menu_module->name == $role_module->name)
{
foreach ($conf_modules as $key => $value)
{
if ($key == $role_module->name)
{
$result[$role_menu->name]['modules'][]['data'] = array('name' => $role_module->display_desc, 'url' => $value['url']);
}
}
}
}
}
}
return array_values($result);

Categories