I will write my requirements and how I write code to achieve it.
I have to generate and save excel file on server with specific styles and formulae. Which user will later download. User will have to select which columns he want when generating excel.
logic I wrote
I placed an excel file with similar styling already on server but with empty cells which I will fill later. That way I can avoid code of styling all those required cells.
Then I am filling all the columns with data from database. Now I read list of columns that needs to be deleted in a posted array and deleting in reverse order to make sure I delete right columns. This works but It takes too much time to delete each column. it is taking atleast 4 to 5 mins to delete single column if column number increases , deleting time is increasing exponentially.
Code
$objReader = PHPExcel_IOFactory::createReader('Excel5');
$objPHPExcel = $objReader->load($inputFileName);
$objPHPExcel->getProperties()->setCreator(user_data('name'))
->setLastModifiedBy(user_data('name'))
->setTitle("Grid file")
->setSubject("Grid file")
->setDescription("Grid file")
->setKeywords("Grid file")
->setCategory("Grids");
$col = 0;
$worksheet = $objPHPExcel->getActiveSheet();
for ($i = 19; $i < count($grid_items) + 19; $i++) {
$col = 0;
foreach ($grid_items[$i - 19] as $columnname => $value) {
$coval = PHPExcel_Cell::stringFromColumnIndex($col) . ($i);
$worksheet->setCellValue($coval, $value);
$col++;
}
}
$worksheet->removeColumnByIndex(11);
$worksheet->removeColumnByIndex(12);
$worksheet->removeColumnByIndex(13);
$worksheet->removeColumnByIndex(14);
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$finalFilename = 'Master_Grid_excel_' . $this->job_id . '-' . date('Y-m-d-H-i-s') . '.xls';
$objWriter->save(SITE_ROOT . 'uploads/rfp/' . $finalFilename);
return ;
Well removeColumn() is computationally intensive anyway; but you are calling it 4 times when you only need to call it once. The removeColumn() and removeColumnByIndex() methods accept an optional second argument specifying the number of columns to remove, defaulting to 1; but if you want to remove a number of consecutive columns (such as 11, 12, 13 and 14) then you can do:
$worksheet->removeColumnByIndex(11, 4);
and that 1 call will be 4 times faster than 4 individual calls.
Note that the same additional argument applies to removing rows as well as columns; and to inserting columns and rows as well.
However: if you modified the logic of your
foreach ($grid_items[$i - 19] as $columnname => $value) {
loop so that it didn't write those columns in the first place, and you removed any unnecessary columns to eliminate the header line entries before that loop; then you wouldn't be executing the removeColumn() against a fully populated spreadsheet.
when you run $worksheet->removeColumnByIndex(11) and next column is 12 change to =>11
so you can try to use ..php function array_reverse() big=>small
$d= array_reverse(sort($chk));
foreach ($d as $v){
$worksheet->removeColumnByIndex($v);
}
Related
I am trying to read and parse and excel and some unclear things come into play as usual for me.
Here is what i have:
while (true)
{
comVariantCell1 = cells.item(row, 1).value().variantType();
comVariantCell2 = cells.item(row, 2).value().variantType();
//if an empty cell is found, processing will stop and user will get an error message in order to solve the inconsistency.
if (comVariantCell1 != COMVariantType::VT_EMPTY && comVariantCell2 != COMVariantType::VT_EMPTY)
{
//both cells have values, check their types.
importedLine = conNull();
progress1.setText(strfmt("Importing row %1", row));
if (cells.item(row, 1).value().variantType() == COMVariantType::VT_BSTR)
{
importedLine += cells.item(row, 1).value().bStr();
}
else
{
importedLine += cells.item(row, 1).value().double();
}
importedLine += cells.item(row, 2).value().double();
importedLinesCollection += [importedLine]; //conIns(importedLinesCollection, row - 1, (importedLine));
row++;
}
else
{
info (strFmt("Empty cell found at line %1 - import will not continue and no records were saved.", row));
break;
}
}
Excel format:
Item number Transfer Qty
a100 50.5
a101 10
a102 25
This worked well to check if the cell type is string: COMVariantType::VT_BSTR
but what should i use to check for a real or integer value ?
I am pretty sure in this case, the quantity will be not contain real values but anyway, it could be useful in the future to make the difference between these two types.
I have to mention that, even if i have an int value and I use cells.item(row, 1).value().int() it won't work. I can't see why.
Why do i want to make the difference? Because if it's forbidden to have real values in the quantity column ( at least in my case ), i want to check that and give the user the opportunity to put a correct value in that place and maybe further investigate why that happened to be there.
Take a look on how it is done in \Classes\SysDataExcelCOM\readRow.
It is basically using switch to test the type. This is really boring!
Also take a look on ExcelIO, a class I made some years ago. It reads Excel and returns each row as a container. This is a more high-level approach.
As a last resort you could save the Excel as a tab separated file. Then use TextIO to read the content. This will be at least 10 times faster than using Excel!
I wrote a function where two insert query have. One is executed and inserting data properly. But next one is not executing. And I cant check the value i want to insert if it is set or not. How to do the stuff? EXPERT's have a look kindly. My function is given below:
add_action( 'save_post', 'cs_product_save' );
function cs_product_save( $post_id ){
global $wpdb;
$cs_product_array = $_POST['cs_product'];
$cs_product_count = count($cs_product_array);
$event_start_date = $_POST['event_start_date'];
$event_end_date = $_POST['event_end_date'];
$event_start_time = $_POST['event_start_time'];
$event_end_time = $_POST['event_end_time'];
$event_all_day = $_POST['event_all_day'];
$event_phone = $_POST['event_phone'];
$event_location = $_POST['event_location'];
$event_map = $_POST['event_map'];
$table_cause_product = "wp_cause_woocommerce_product";
$table_event_info = "wp_cause_info";
for( $i=0; $i < $cs_product_count; $i++ ){
$wpdb->insert($table_cause_product,array(
'cause_ID'=>$post_id,
'product_ID'=>$cs_product_array[$i],
'status'=>'1'
),array('%d','%d','%d'));
}
$wpdb->insert($table_event_info,array(
'cause_ID'=>$post_id,
'event_start_date'=>$event_start_date,
'event_end_date'=>$event_end_date,
'event_start_time'=>$event_start_time,
'event_end_time'=>$event_end_time,
'event_all_day'=>$event_all_day,
'event_phone'=>$event_phone,
'event_location'=>$event_location,
'event_map'=>$event_map
),array('%d','%s','%s','%s','%s','%d','%s','%s','%d'));
}
I don't see any problem here with your code. But be sure to double check your code.
The issues my be with the name of your database table names. Are you sure that $table_cause_product and $table_event_info holds the actual name of the tables? I would recommend to use $wpdb->prefix instead of harcoding table names.
In my case I would check the function in several parts.
Check the $_POST actually holds the data I want.
Use $result = $wpdb->insert( $table, $data, $format ); in all cases for debug purpose as the $result would hold the result of the operation. If its is false then I would be sure that there is definitely something wrong with the operation.
Finally I would use a wp_die() (though its not a standard way to do, but it suffices my purpose) so that I can see the dumped variable data.
One major issue you might face with your code that if the post is edited after saving then it might insert another row for same post data. Again if the post is being autosaved, you need some safeguard. I would recommend a where clause here to check the row already exists or not. If exists then you can simply update the row, or else insert the data.
Hope this might help you.
Is it possible to fetch a post with content under 140 characters or 25 words ?
if possible how to do it
here is my random post code
// Random post link
function randomPostlink(){
$RandPostQuery = new WP_Query(array('post_type'=>array('tip'),'posts_per_page' => 1,'orderby'=>'rand'));
while ( $RandPostQuery->have_posts() ) : $RandPostQuery->the_post();
echo the_permalink();
endwhile;
wp_reset_postdata();
}
Character count is easy, you can just add the condition AND CHAR_LENGTH(post_content) < 140 to your where clause.
Word count is more difficult because there is no built in MySQL function for counting words. You can find simple solutions that don't work in every use case as well as complete solutions that use stored functions. I'll use a simple solution for the sake of example.
What you need to do is add a filter to the where clause and apply your additional conditions there:
add_filter( 'posts_where', 'venki_post_length_limit' );
function venki_post_length_limit($where = '') {
remove_filter( 'posts_where', 'venki_post_length_limit' );
$where .= ' AND (
CHAR_LENGTH(post_content) < 140 OR
(LENGTH(post_content) - LENGTH(REPLACE(post_content, ' ', ''))+1) < 25
) ';
return $where;
}
Notice that I remove the filter as soon as the function is called. This is so you don't apply this same condition to every query.
You should also be aware that both of those conditions are costly compared to a simple lookup on a column value (especially the word count). Neither can utilize indexes. If you have a large number of posts you may run into performance issues if you're running this query frequently. A better solution might be to calculate the word and character count when the post is created/updated and store that as meta data.
I'm new to PHPExcel and somehow I got the same data duplicated in the Excel spreadsheet using the following code:
<?php
$roster_sql = "SELECT * FROM EMPLOYEE";
$roster_result = mysql_query($roster_sql) or die(mysql_error());
// Populate 2D Array
$kcount = 0;
while($sheet_array = mysql_fetch_array($roster_result))
{
$sheet[$kcount] = $sheet_array;
$kcount++;
}
$rowID = 1;
foreach($sheet as $rowArray)
{
$columnID = 'A';
foreach($rowArray as $columnValue)
{
$objPHPExcel->getActiveSheet()->setCellValue($columnID.$rowID, $columnValue);
$columnID++;
}
$rowID++;
}
?>
The generated spreadsheet has each cell value duplicated in the column. Did I populate the array incorrectly or is there something wrong when I write out the array?
Further, how do I write the header row in the same spreadsheet without hard coding the column names from the SQL?
Thanks for your help.
Default behaviour for mysql_fetch_array() is to return an array with both enumerated and associative values for each column. i.e. the $result_type argument is MYSQL_BOTH.
If you only want either an associative or an enumerated result (but not both), then you need to specify this, e.g.
while($sheet_array = mysql_fetch_array($roster_result, MYSQL_ASSOC))
or
while($sheet_array = mysql_fetch_array($roster_result, MYSQL_NUM))
or use one of the related functions, e.g.
while($sheet_array = mysql_fetch_assoc($roster_result))
or
while($sheet_array = mysql_fetch_row($roster_result))
EDIT
If you want to write out the column names as a header, then you need to call something like mysql_list_fields() to get the list of columns for the table
Or alternatively, retrieve your data as an associative array, and then the key values will be your column names
It's a pretty specific use, but it can come in handy.
Imagine you have a different values to stack, some data varying a lot and some being almost constant.
If you use the default order and the variable data is stacked under the constant data, the variable data will make the constant data have a very variable base.
So if you stack first at bottom the less variable data, it could help.
Example: These two graphs show how to improve readibility by stacking deeper data that move the less, i.e. has the smaller standard deviation.
Default graphing could lead to bad readibility
Improved readibility when sorting by standard deviation
use rrdtool graph with PRINT command to get the standard deviation of the data sources (stdev_array)
sort stdev_array
graph by stacking in the order of stdev_array
Here is the code in PHP but any language can do it.
I'm using RRDtool 1.4.5
Don't forget to define $rrd_path (path to rrd file), $img_path (path where to write the image), $data_sources (an array of DS names, depends on how you build your RRD), $rrd_colors (an array of hexa colors).
$rrd_colors_count = count($rrd_colors);
$stdev_command = "rrdtool graph /dev/null ";
foreach ($data_sources as $index => $ds_name)
{
$stdev_command .= "DEF:serv$index=$rrd_path:$ds_name:AVERAGE ";
$stdev_command .= "VDEF:stdev$index=serv$index,STDEV PRINT:stdev$index:%lf ";
}
exec($stdev_command, $stdev_order, $ret);
if ($ret === 0)
{
array_shift($stdev_order); // remove first useless line "0x0" (may depend on your rrdtool version?)
asort($stdev_order); // sort by standard deviation keeping the indexes
}
else $stdev_order = $data_sources; // backup in case $stdev_command failed
$graph_command = "rrdtool graph $img_path ";
$graph_command .= "AREA:0 ";
foreach ($stdev_order as $index => $useless)
{
$ds_name = $data_sources[$index];
$graph_command .= "DEF:line$index=$rrd_path:$ds_name:AVERAGE ";
$graph_command .= "STACK:line$index" . $rrd_colors[$index%$rrd_colors_count].' ';
}
exec($graph_command, $out, $ret);
// check $ret (and $out) to see if all is good