BUGFIX: rewrite the export function to fix the bug that multiplied columns when adding rows, and to use built-in php csv functions.

This commit is contained in:
Mateusz Uzdowski 2010-10-07 21:37:21 +00:00
parent 8b4e3b9962
commit 14ff7759a7
2 changed files with 43 additions and 84 deletions

View File

@ -83,81 +83,49 @@ class SubmittedFormReportField extends FormField {
$udf = DataObject::get_by_id("UserDefinedForm", $SQL_ID); $udf = DataObject::get_by_id("UserDefinedForm", $SQL_ID);
if($udf) { if($udf) {
$csvHeaderNames = array();
$csvHeaderTitle = array();
$submissions = $udf->Submissions("", "\"ID\""); $submissions = $udf->Submissions("", "\"ID\"");
if($submissions && $submissions->exists()) { if($submissions && $submissions->exists()) {
$data = array();
$csvHeaders = array();
// Get all the submission IDs (so we know what names/titles to get - helps for sites with many UDF's) // Create CSV rows out of submissions. Fields on those submissions will become columns.
$inClause = array();
foreach($submissions as $submission) { foreach($submissions as $submission) {
$inClause[] = $submission->ID; $fields = $submission->Values();
}
// Get the CSV header rows from the database $row = array();
foreach($fields as $field) {
// Collect the data
$row[$field->Name] = $field->Value;
$tmp = DB::query(" // Collect unique columns for use in the CSV - we must have a fixed number of columns, but we want to
SELECT DISTINCT \"SubmittedFormField\".\"ID\", \"Name\", \"Title\" // include all fields that have ever existed in this form.
FROM \"SubmittedFormField\" // NOTE: even if the field was used long time ago and only once, it will be included, so expect to see
LEFT JOIN \"SubmittedForm\" ON \"SubmittedForm\".\"ID\" = \"SubmittedFormField\".\"ParentID\" // some empty columns, especially on heavily-edited UDFs.
WHERE \"SubmittedFormField\".\"ParentID\" IN (" . implode(',', $inClause) . ") $csvHeaders[$field->Name] = $field->Title;
GROUP BY \"SubmittedFormField\".\"ID\",\"Name\",\"Title\"
ORDER BY \"SubmittedFormField\".\"ID\"
");
// Sort the Names and Titles from the database query into separate keyed arrays
foreach($tmp as $array) {
$csvHeaderNames[] = $array['Name'];
$csvHeaderTitle[] = $array['Title'];
}
// For every submission...
$i = 0;
foreach($submissions as $submission) {
// Get the rows for this submission (One row = one form field)
$dataRow = $submission->Values();
$rows[$i] = array();
// For every row/field, get all the columns
foreach($dataRow as $column) {
// If the Name of this field is in the $csvHeaderNames array, get an array of all the places it exists
if($index = array_keys($csvHeaderNames, $column->Name)) {
if(is_array($index)) {
// Set the final output array for each index that we want to insert this value into
foreach($index as $idx) {
$rows[$i][$idx] = $column->Value;
}
}
}
} }
$rows[$i]['Submitted'] = $submission->Created; $row['Submitted'] = $submission->Created;
$data[] = $row;
$i++;
} }
// CSV header row // Create the CSV header line first:
$csvData = '"' . implode('","', $csvHeaderTitle) . '"' . ',"Submitted"'."\n"; $csvData = '"' . implode('","', $csvHeaders) . '"' . ',"Submitted"'."\n";
// For every row of data (one form submission = one row) // Now put the collected data under relevant columns
foreach($rows as $row) { foreach($data as $row) {
$csvRowItems = array();
for($i=0;$i<count($csvHeaderNames);$i++) { foreach ($csvHeaders as $columnName=>$columnTitle) {
if (!isset($row[$columnName])) $csvRowItems[] = ""; // This submission did not have that column, insert blank
if(!isset($row[$i]) || !$row[$i]) $csvData .= '"",'; // If there is no data for this column, output it as blank instead else $csvRowItems[] = $row[$columnName];
else {
$tmp = str_replace('"', '""', $row[$i]);
$csvData .= '"' . $tmp . '",';
}
} }
$csvRowItems[] = $row['Submitted'];
// Start a new row for each submission (re-check we have 'Submitted' in this entry) // Encode the row
if(isset($row['Submitted'])) $csvData .= '"'.$row['Submitted'].'"'."\n"; $fp = fopen('php://memory', 'r+');
else $csvData .= "\n"; fputcsv($fp, $csvRowItems, ',', '"');
rewind($fp);
$csvData .= fgets($fp);
fclose($fp);
} }
} else { } else {
user_error("No submissions to export.", E_USER_ERROR); user_error("No submissions to export.", E_USER_ERROR);

View File

@ -50,28 +50,19 @@ class SubmittedFormTest extends FunctionalTest {
// export it back to an array (rather than string) // export it back to an array (rather than string)
$exportLines = explode("\n", $export); $exportLines = explode("\n", $export);
array_pop($exportLines); // Remove trailing empty line
$data = array(); $data = array();
array_pop($exportLines);
foreach($exportLines as $line) { foreach($exportLines as $line) {
$line = explode("\",\"", $line); $data[] = str_getcsv($line);
$clean = array();
foreach($line as $part) {
$clean[] = trim($part, "\"");
}
$data[] = $clean;
} }
// check the headers are fine // check the headers are fine and include legacy field
$this->assertEquals($data[0], array( $this->assertEquals($data[0], array(
'Submitted Title','Submitted Title 2','Submitted' 'Submitted Title','Submitted Title 2','Submitted'
)); ));
// check the number of records in the export // check the number of records in the export
$this->assertEquals(count($data), 12); $this->assertEquals(count($data), 12);
$this->assertEquals($data[1][0], 'Value 1'); $this->assertEquals($data[1][0], 'Value 1');