mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
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:
parent
8b4e3b9962
commit
14ff7759a7
@ -76,88 +76,56 @@ class SubmittedFormReportField extends FormField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$now = Date("Y-m-d_h.i.s");
|
$now = Date("Y-m-d_h.i.s");
|
||||||
$fileName = "export-$now.csv";
|
$fileName = "export-$now.csv";
|
||||||
$separator = ",";
|
$separator = ",";
|
||||||
|
|
||||||
$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();
|
||||||
// Get all the submission IDs (so we know what names/titles to get - helps for sites with many UDF's)
|
$csvHeaders = array();
|
||||||
$inClause = array();
|
|
||||||
|
// Create CSV rows out of submissions. Fields on those submissions will become columns.
|
||||||
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) {
|
||||||
$tmp = DB::query("
|
// Collect the data
|
||||||
SELECT DISTINCT \"SubmittedFormField\".\"ID\", \"Name\", \"Title\"
|
$row[$field->Name] = $field->Value;
|
||||||
FROM \"SubmittedFormField\"
|
|
||||||
LEFT JOIN \"SubmittedForm\" ON \"SubmittedForm\".\"ID\" = \"SubmittedFormField\".\"ParentID\"
|
|
||||||
WHERE \"SubmittedFormField\".\"ParentID\" IN (" . implode(',', $inClause) . ")
|
|
||||||
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;
|
|
||||||
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSV header row
|
|
||||||
$csvData = '"' . implode('","', $csvHeaderTitle) . '"' . ',"Submitted"'."\n";
|
|
||||||
|
|
||||||
// For every row of data (one form submission = one row)
|
|
||||||
foreach($rows as $row) {
|
|
||||||
|
|
||||||
for($i=0;$i<count($csvHeaderNames);$i++) {
|
|
||||||
|
|
||||||
if(!isset($row[$i]) || !$row[$i]) $csvData .= '"",'; // If there is no data for this column, output it as blank instead
|
// Collect unique columns for use in the CSV - we must have a fixed number of columns, but we want to
|
||||||
else {
|
// include all fields that have ever existed in this form.
|
||||||
$tmp = str_replace('"', '""', $row[$i]);
|
// NOTE: even if the field was used long time ago and only once, it will be included, so expect to see
|
||||||
$csvData .= '"' . $tmp . '",';
|
// some empty columns, especially on heavily-edited UDFs.
|
||||||
}
|
$csvHeaders[$field->Name] = $field->Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a new row for each submission (re-check we have 'Submitted' in this entry)
|
$row['Submitted'] = $submission->Created;
|
||||||
if(isset($row['Submitted'])) $csvData .= '"'.$row['Submitted'].'"'."\n";
|
$data[] = $row;
|
||||||
else $csvData .= "\n";
|
}
|
||||||
|
|
||||||
|
// Create the CSV header line first:
|
||||||
|
$csvData = '"' . implode('","', $csvHeaders) . '"' . ',"Submitted"'."\n";
|
||||||
|
|
||||||
|
// Now put the collected data under relevant columns
|
||||||
|
foreach($data as $row) {
|
||||||
|
$csvRowItems = array();
|
||||||
|
foreach ($csvHeaders as $columnName=>$columnTitle) {
|
||||||
|
if (!isset($row[$columnName])) $csvRowItems[] = ""; // This submission did not have that column, insert blank
|
||||||
|
else $csvRowItems[] = $row[$columnName];
|
||||||
|
}
|
||||||
|
$csvRowItems[] = $row['Submitted'];
|
||||||
|
|
||||||
|
// Encode the row
|
||||||
|
$fp = fopen('php://memory', 'r+');
|
||||||
|
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);
|
||||||
@ -228,4 +196,4 @@ class SubmittedFormReportField extends FormField {
|
|||||||
}
|
}
|
||||||
return (Director::is_ajax() || SapphireTest::is_running_test()) ? false : Director::redirectBack();
|
return (Director::is_ajax() || SapphireTest::is_running_test()) ? false : Director::redirectBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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');
|
||||||
|
Loading…
Reference in New Issue
Block a user