I am using PHP library PhpSpreadsheet and would like to populate a spreadsheet (xlsx) using data from MySQL table using a loop to iterate through the cells and rows, something similar to this:
.------------------------.
|ID first_name last_name |
|1 John Smith |
|2 John Doe |
`------------------------`
My table will have the first row as header (bold text) and the rows below will be the data from MySQL.
Here is the script I wrote for this purpose:
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getStyle('A1:C1')->getFont()->setBold( true );
$header_row_array = ['ID', 'First Name', 'Last Name'];
$spreadsheet->getActiveSheet()->fromArray( $header_row_array, NULL, 'A1' );
global $wpdb;
$query = 'SELECT * FROM custom_table WHERE DATE( ts ) BETWEEN SUBDATE( NOW(), 1) and NOW()';
$rows = $wpdb->get_results( $query, OBJECT );
foreach( $rows as $row ) {
for( $i = 2; $i <= count( $rows ) + 1; $i++ ) {
foreach( range( 'A', 'C' ) as $v ) {
switch( $v ) {
case 'A': {
$value = $row->id;
break;
}
case 'B': {
$value = $row->first_name;
break;
}
case 'C': {
$value = $row->last_name;
break;
}
}
$spreadsheet->getActiveSheet()->setCellValue( $v . $i, $value );
}
}
//echo '<pre>';var_dump( $row );echo '</pre>';
}
$writer = new Xlsx( $spreadsheet );
$writer->save( 'test.xlsx' );
I also think these loops are a crude way to solve this, if you have any idea on improvements please share!
The result I am getting is:
The same row data in every row, as if the outer loop doesn't really loop through the items.
Please advise.
Thanks
I know it's a little late, but I want to share my workaround for this same problem. I start where you are already fetched data from database:
$header_row_array = ['ID', 'First Name', 'Last Name'];
$spreadsheet->getActiveSheet()->fromArray( $header_row_array);
Since it's the first row you insert on the spreadsheet, it's not neccesary pass all the arguments to fromArray(), just the array containing the headers of each colum.
Next thing to do is iterate through $rows. With a fromArray() and one foreach statement you could get this, just adding a counter (not the most elegant solution, but practical).
$count = 2;
foreach($rows as $row){
$spreadsheet->getActiveSheet()->fromArray(array($row->id, $row->first_name, $row->last_name), null, 'A'.$count);
$count++;
}
Like you did when inserted the header row, I just pass the cell of the first colum (A) in the current row (remember $count starts at 2), the method puts the regarding data in the consecuent cells of that same row. The counter starts on 2 because A1 is already used by the header row, so it starts at A2 and sums up from there.
I hope it helps!
The problem came from your loops.
$rows = [
['id'=> 1, 'first_name'=> 'John', 'last_name'=> 'Smith'],
['id'=> 2, 'first_name'=> 'Jane', 'last_name'=> 'Doe'],
];
foreach( $rows as $row ) {
for( $i = 2; $i <= count( $rows ) + 1; $i++ ) {
foreach( range( 'A', 'C' ) as $v ) {
switch( $v ) {
case 'A': {
// $value = $row->id;
$value = $row['id'];
break;
}
case 'B': {
// $value = $row->first_name;
$value = $row['first_name'];
break;
}
case 'C': {
// $value = $row->last_name;
$value = $row['last_name'];
break;
}
}
print $v.$i.' : '. $value . "\n";
}
print '--------' . "\n";
}
}
return
A2 : 1
B2 : John
C2 : Smith
--------
A3 : 1
B3 : John
C3 : Smith
--------
A2 : 2
B2 : Jane
C2 : Doe
--------
A3 : 2
B3 : Jane
C3 : Doe
--------
Edit
For not thinking here is the solution
$i = 2;
foreach( $rows as $row ) {
foreach( range( 'A', 'C' ) as $v ) {
switch( $v ) {
case 'A': {
$value = $row->id;
break;
}
case 'B': {
$value = $row->first_name;
break;
}
case 'C': {
$value = $row->last_name;
break;
}
}
print $v.$i.' : '. $value . "\n";
}
$i++;
}
output
A2 : 1
B2 : John
C2 : Smith
A3 : 2
B3 : Jane
C3 : Doe
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With