Skip to content

Commit

Permalink
New feature: Response Excel format now exports xlsx files
Browse files Browse the repository at this point in the history
  • Loading branch information
c-schmitz committed May 25, 2016
1 parent bb05903 commit af6e540
Show file tree
Hide file tree
Showing 9 changed files with 870 additions and 113 deletions.
2 changes: 1 addition & 1 deletion application/controllers/admin/export.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public function exportresults()
foreach($aFieldMap as $sFieldName=>$fieldinfo)
{
$sCode=viewHelper::getFieldCode($fieldinfo);
$aFields[$sFieldName]=$sCode.' - '.htmlspecialchars(ellipsize(html_entity_decode(viewHelper::getFieldText($fieldinfo)),30,.6,'...'));
$aFields[$sFieldName]=$sCode.' - '.htmlspecialchars(ellipsize(html_entity_decode(viewHelper::getFieldText($fieldinfo)),40,.6,'...'));
$aFieldsOptions[$sFieldName]=array('title'=>viewHelper::getFieldText($fieldinfo),'data-fieldname'=>$fieldinfo['fieldname'],'data-emcode'=>viewHelper::getFieldCode($fieldinfo,array('LEMcompat'=>true))); // No need to filter title : Yii do it (remove all tag)
}

Expand Down
8 changes: 4 additions & 4 deletions application/core/plugins/Authdb/Authdb.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public function beforeLogin()

/**
* Get the onetime password (if set)
*
*
* @return string|null
*/
protected function getOnePass()
Expand Down Expand Up @@ -169,14 +169,14 @@ public function newUserSession()

/**
* Set the onetime password
*
*
* @param type $onepass
* @return Authdb
*/
protected function setOnePass($onepass)
{
$this->_onepass = $onepass;

return $this;
}

Expand All @@ -186,7 +186,7 @@ public function listExportOptions()
{
$event = $this->getEvent();
$type = $event->get('type');

switch ($type) {
case 'csv':
$event->set('label', gT("CSV"));
Expand Down
58 changes: 14 additions & 44 deletions application/helpers/admin/export/ExcelWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ExcelWriter extends Writer
private $separator;
private $hasOutputHeader;
private $rowCounter;
private $forceDownload=true;

//Indicates if the Writer is outputting to a file rather than sending via HTTP.
private $outputToFile = false;
Expand All @@ -25,7 +26,7 @@ class ExcelWriter extends Writer
*/
public function __construct($filename = null)
{
require_once(APPPATH.'/third_party/pear/Spreadsheet/Excel/Xlswriter.php');
require_once(APPPATH.'/third_party/xlsx_writer/xlsxwriter.class.php');
$this->separator = '~|';
$this->hasOutputHeader = false;
$this->rowCounter = 0;
Expand All @@ -35,64 +36,33 @@ public function init(SurveyObj $survey, $sLanguageCode, FormattingOptions $oOpti
{
parent::init($survey, $sLanguageCode, $oOptions);

if ($oOptions->output=='file')
{
$this->workbook = new xlswriter($this->filename);
$this->outputToFile = true;
}
else
{
$this->workbook = new xlswriter;
}
$this->workbook->setTempDir(Yii::app()->getConfig("tempdir"));

if ($oOptions->output=='display') {
$this->workbook->send('results-survey'.$survey->id.'.xls');

}
$this->workbook = new XLSXWriter();
$worksheetName = $survey->languageSettings['surveyls_title'];
$worksheetName=substr(str_replace(array('*', ':', '/', '\\', '?', '[', ']'),array(' '),$worksheetName),0,31); // Remove invalid characters

$this->workbook->setVersion(8);
$sheet =$this->workbook->addWorksheet($worksheetName); // do not translate/change this - the library does not support any special chars in sheet name
$sheet->setInputEncoding('utf-8');
$this->currentSheet = $sheet;
$this->currentSheet = $worksheetName;
$this->forceDownload=!($oOptions->output=='file');
}

protected function outputRecord($headers, $values, FormattingOptions $oOptions)
{
if (!$this->hasOutputHeader)
{
$columnCounter = 0;
foreach ($headers as $header)
{
$this->currentSheet->write($this->rowCounter,$columnCounter,str_replace('?', '-', $this->excelEscape($header)));
$columnCounter++;
}
$this->workbook->writeSheetRow($this->currentSheet, $headers );
$this->hasOutputHeader = true;
$this->rowCounter++;
}
$columnCounter = 0;
foreach ($values as $value)
{
$this->currentSheet->write($this->rowCounter, $columnCounter, $this->excelEscape($value));
$columnCounter++;
}
$this->rowCounter++;
}

private function excelEscape($value)
{
if ((substr($value, 0, 1) == '=') || (substr($value, 0, 1) == '@'))
{
$value = '"'.$value.'"';
}
return $value;
$this->workbook->writeSheetRow($this->currentSheet, $values );
}

public function close()
{
$this->workbook->close();
$this->workbook->writeToFile($this->filename);
if ($this->forceDownload){
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition: attachment; filename=\"Excel.xlsx\"");
header('Content-Length: ' . filesize($this->filename));
readfile($this->filename);
}
return $this->workbook;
}
}
16 changes: 7 additions & 9 deletions application/helpers/admin/export/Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ abstract class Writer implements IWriter
protected $sLanguageCode;
protected $translator;
public $filename;

public $webfilename;

protected function translate($key, $sLanguageCode)
{
return $this->translator->translate($key, $sLanguageCode);
Expand All @@ -30,10 +31,7 @@ public function init(SurveyObj $oSurvey, $sLanguageCode, FormattingOptions $oOpt
{
$this->languageCode = $sLanguageCode;
$this->translator = new Translator();
if ($oOptions->output == 'file') {
$sRandomFileName=Yii::app()->getConfig("tempdir") . DIRECTORY_SEPARATOR . randomChars(40);
$this->filename = $sRandomFileName;
}
$this->filename = Yii::app()->getConfig("tempdir") . DIRECTORY_SEPARATOR . randomChars(40);
}

/**
Expand Down Expand Up @@ -93,7 +91,7 @@ public function getFullHeading(SurveyObj $oSurvey, FormattingOptions $oOptions,

/**
* Return the subquestion part, if not empty : add a space before it.
*
*
* @param Survey $oSurvey
* @param FormattingOptions $oOptions
* @param string $fieldName
Expand All @@ -114,7 +112,7 @@ public function getFullFieldSubHeading(SurveyObj $oSurvey, FormattingOptions $oO

/**
* Return the question text part without any subquestion
*
*
* @param Survey $oSurvey
* @param FormattingOptions $oOptions
* @param string $fieldName
Expand Down Expand Up @@ -300,7 +298,7 @@ final public function write(SurveyObj $oSurvey, $sLanguageCode, FormattingOption
}
//Output the results.
$sFile='';

// If empty survey, prepare an empty responses array, and output just 1 empty record with header.
if ($oSurvey->responses->rowCount == 0)
{
Expand All @@ -310,7 +308,7 @@ final public function write(SurveyObj $oSurvey, $sLanguageCode, FormattingOption
}
$this->outputRecord($headers, $elementArray, $oOptions);
}

// If no empty survey, render/export responses array.
foreach($oSurvey->responses as $response)
{
Expand Down
20 changes: 20 additions & 0 deletions application/third_party/xlsx_writer/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The MIT License (MIT)

Copyright (c) 2013 Mark Jones

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
78 changes: 78 additions & 0 deletions application/third_party/xlsx_writer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
PHP_XLSXWriter
==============

This library is designed to be lightweight, and have relatively low memory usage.

It is designed to output an Excel spreadsheet in with (Office 2007+) xlsx format, with just basic features supported:
* supports PHP 5.2.1+
* takes UTF-8 encoded input
* multiple worksheets
* supports currency/date/numeric cell formatting, simple formulas

Give this library a try, if you find yourself [running out of memory writing spreadsheets with PHPExcel](http://www.zedwood.com/article/php_xlsxwriter-performance-comparison).

Simple PHP CLI example:
```php
$data = array(
array('year','month','amount'),
array('2003','1','220'),
array('2003','2','153.5'),
);

$writer = new XLSXWriter();
$writer->writeSheet($data);
$writer->writeToFile('output.xlsx');
```

Multiple Sheets:
```php
$data1 = array(
array('5','3'),
array('1','6'),
);
$data2 = array(
array('2','7','9'),
array('4','8','0'),
);

$writer = new XLSXWriter();
$writer->setAuthor('Doc Author');
$writer->writeSheet($data1,'Sheet1');
$writer->writeSheet($data2,'Sheet2');
echo $writer->writeToString();
```

Simple/Advanced Cell Formats:
```php
//simple formats: date, datetime, integer, dollar, euro, string
$header = array(
'created'=>'date',
'product_id'=>'integer',
'quantity'=>'#,##0',
'amount'=>'dollar',
'description'=>'string',
'tax'=>'[$$-1009]#,##0.00;[RED]-[$$-1009]#,##0.00',
);
$data = array(
array('2015-01-01',873,1,'44.00','misc','=D2*0.05'),
array('2015-01-12',324,2,'88.00','none','=D3*0.05'),
);

$writer = new XLSXWriter();
$writer->writeSheet($data,'Sheet1', $header);
$writer->writeToFile('example.xlsx');
```

Load test with 50000 rows: (runs fast, with low memory usage)
```php
include_once("xlsxwriter.class.php");
$header = array('c1'=>'string','c2'=>'string','c3'=>'string','c4'=>'string');
$writer = new XLSXWriter();
$writer->writeSheetHeader('Sheet1', $header );//optional
for($i=0; $i<50000; $i++)
{
$writer->writeSheetRow('Sheet1', array(rand()%10000,rand()%10000,rand()%10000,rand()%10000) );
}
$writer->writeToFile('output.xlsx');
echo '#'.floor((memory_get_peak_usage())/1024/1024)."MB"."\n";
```

0 comments on commit af6e540

Please sign in to comment.