1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/limesurvey_ynh.git synced 2024-09-03 19:36:32 +02:00
limesurvey_ynh/sources/application/helpers/admin/export/Writer.php

458 lines
No EOL
16 KiB
PHP

<?php
/**
* Contains functions and properties that are common to all writers.
* All extending classes must implement the internalWrite(...) method and
* have access to functionality as described below:
*
* TODO Write more docs here
*/
abstract class Writer implements IWriter
{
protected $sLanguageCode;
protected $translator;
public $filename;
protected function translate($key, $sLanguageCode)
{
return $this->translator->translate($key, $sLanguageCode);
}
/**
* An initialization method that implementing classes can override to gain access
* to any information about the survey, language, or formatting options they
* may need for setup.
*
* @param Survey $survey
* @param mixed $sLanguageCode
* @param FormattingOptions $oOptions
*/
public function init(SurveyObj $survey, $sLanguageCode, FormattingOptions $oOptions)
{
$this->languageCode = $sLanguageCode;
$this->translator = new Translator();
if ($oOptions->output == 'file') {
$sRandomFileName=Yii::app()->getConfig("tempdir") . DIRECTORY_SEPARATOR . randomChars(40);
$this->filename = $sRandomFileName;
}
}
/**
* Returns an abbreviated heading for the survey's question that matches
* the $fieldName parameter (or false if a match is not found).
*
* @param Survey $survey
* @param string $fieldName
* @return string
*/
public function getAbbreviatedHeading(SurveyObj $survey, $fieldName)
{
if (isset($survey->fieldMap[$fieldName])) {
$question = $survey->fieldMap[$fieldName];
$heading = $question['question'];
$heading = $this->stripTagsFull($heading);
$heading = mb_substr($heading, 0, 15).'.. ';
$aid = $survey->fieldMap[$fieldName]['aid'];
if (!empty($aid))
{
$heading .= '['.$this->stripTagsFull($aid).']';
}
return $heading;
} else {
// Token field
if (isset($survey->tokenFields[$fieldName])) {
return $survey->tokenFields[$fieldName]['description'];
}
return $fieldName;
}
}
/**
* Returns a full heading for the question that matches the $fieldName.
* False is returned if no matching question is found.
*
* @param Survey $survey
* @param FormattingOptions $oOptions
* @param string $fieldName
* @return string (or false)
*/
public function getFullHeading(SurveyObj $survey, FormattingOptions $oOptions, $fieldName)
{
if (isset($survey->fieldMap[$fieldName])) {
$question = $survey->fieldMap[$fieldName];
$heading = $question['question'];
$heading = $this->stripTagsFull($heading);
$heading.=$this->getFullFieldSubHeading($survey, $oOptions, $fieldName);
return $heading;
} else {
// Token field
if (isset($survey->tokenFields[$fieldName])) {
return $survey->tokenFields[$fieldName]['description'];
}
return $fieldName;
}
}
public function getCodeHeading(SurveyObj $survey, FormattingOptions $oOptions, $fieldName)
{
$question = $survey->fieldMap[$fieldName];
$heading = $question['title'];
$heading = $this->stripTagsFull($heading);
$heading.=$this->getCodeFieldSubHeading($survey, $oOptions, $fieldName);
return $heading;
}
public function getCodeFieldSubHeading(SurveyObj $survey, FormattingOptions $oOptions, $fieldName)
{
$field = $survey->fieldMap[$fieldName];
$answerCode = $field['aid'];
$questionId = $field['qid'];
$fieldType = $field['type'];
$subHeading = '';
switch ($fieldType)
{
case 'R':
$subHeading .= ' ['.$this->translate('Ranking', $this->languageCode).' '.
$answerCode.']';
break;
case 'L':
case '!':
if ($answerCode == 'other')
{
$subHeading .= ' '.$this->getOtherSubHeading();
}
break;
case 'O':
if ($answerCode == 'comment')
{
$subHeading .= ' '.$this->getCommentSubHeading();
}
break;
case 'M':
case 'P':
//This section creates differing output from the old code base, but I do think
//that it is more correct than the old code.
$isOther = ($answerCode == 'other');
$isComment = (mb_substr($answerCode, -7, 7) == 'comment');
if ($isComment)
{
$isOther = (mb_substr($answerCode, 0, -7) == 'other');
}
if ($isOther)
{
$subHeading .= ' '.$this->getOtherSubHeading();
}
else
{
$subHeading .= ' ['.$answerCode.']';
}
break;
case ':':
case ';':
list($scaleZeroTitle, $scaleOneTitle) = explode('_', $answerCode);
$subHeading .= ' ['.$scaleZeroTitle.']['.$scaleOneTitle.']';
break;
case '1':
$answerScale = substr($fieldName, -1) + 1;
$subQuestions = $survey->getSubQuestionArrays($questionId);
foreach ($subQuestions as $question)
{
if ($question['title'] == $answerCode && $question['scale_id'] == 0)
{
$subHeading = ' ['.flattenText($question['title'], true,true).'][Scale '.$answerScale.']';
}
}
break;
default:
if (!empty($answerCode))
{
$subHeading .= ' ['.$answerCode.']';
}
}
//rtrim the result since it could be an empty string ' ' which
//should be removed.
return rtrim($subHeading);
}
public function getFullFieldSubHeading(SurveyObj $survey, FormattingOptions $oOptions, $fieldName)
{
$field = $survey->fieldMap[$fieldName];
$answerCode = $field['aid'];
$questionId = $field['qid'];
$fieldType = $field['type'];
$subHeading = '';
switch ($fieldType)
{
case 'R':
$subHeading .= ' ['.$this->translate('Ranking', $this->languageCode).' '.
$answerCode.']';
break;
case 'L':
case '!':
if ($answerCode == 'other')
{
$subHeading .= ' '.$this->getOtherSubHeading();
}
break;
case 'O':
if ($answerCode == 'comment')
{
$subHeading .= ' '.$this->getCommentSubHeading();
}
break;
case 'M':
case 'P':
//This section creates differing output from the old code base, but I do think
//that it is more correct than the old code.
$isOther = ($answerCode == 'other');
$isComment = (mb_substr($answerCode, -7, 7) == 'comment');
if ($isComment)
{
$isOther = (mb_substr($answerCode, 0, -7) == 'other');
}
if ($isOther)
{
$subHeading .= ' '.$this->getOtherSubHeading();
}
else
{
$sqs = $survey->getSubQuestionArrays($questionId);
foreach ($sqs as $sq)
{
if (!$isComment && $sq['title'] == $answerCode)
{
$value = $sq['question'];
}
}
if (!empty($value))
{
$subHeading .= ' ['.$this->stripTagsFull($value).']';
}
}
if (isset($isComment) && $isComment == true)
{
$subHeading .= ' '.$this->getCommentSubHeading();
$comment = false;
}
break;
case ':':
case ';':
$subHeading .= ' ['.$this->stripTagsFull($field['subquestion1']).']['.$this->stripTagsFull($field['subquestion2']).']';
break;
case '1':
$answerScale = substr($fieldName, -1) + 1;
$subQuestions = $survey->getSubQuestionArrays($questionId);
foreach ($subQuestions as $question)
{
if ($question['title'] == $answerCode && $question['scale_id'] == 0)
{
$subHeading = ' ['.flattenText($question['question'], true,true).'][Scale '.$answerScale.']';
}
}
break;
default:
$subQuestion = null;
$subQuestions = $survey->getSubQuestionArrays($questionId);
foreach ($subQuestions as $question)
{
if ($question['title'] == $answerCode)
{
$subQuestion = $question;
}
}
if (!empty($subQuestion) && !empty($subQuestion['question']))
{
$subHeading .= ' ['.$this->stripTagsFull($subQuestion['question']).']';
}
}
//rtrim the result since it could be an empty string ' ' which
//should be removed.
return rtrim($subHeading);
}
private function getOtherSubHeading()
{
return '['.$this->translate('Other', $this->languageCode).']';
}
private function getCommentSubHeading()
{
return '- comment';
}
/**
* Performs a transformation of the response value based on the value, the
* type of field the value is a response for, and the FormattingOptions.
* All transforms should be processed during the execution of this function!
*
* The final step in the transform is to apply a stripTagsFull on the $value.
* This occurs for ALL values whether or not any other transform is applied.
*
* @param string $value
* @param string $fieldType
* @param FormattingOptions $oOptions
* @param string $column The name of the column
* @return string
*/
protected function transformResponseValue($value, $fieldType, FormattingOptions $oOptions, $column = null)
{
//The following if block handles transforms of Ys and Ns.
if (($oOptions->convertN || $oOptions->convertY) &&
isset($fieldType) &&
($fieldType == 'M' || $fieldType == 'P' || $fieldType == 'Y'))
{
if (($value == 'N' || ($value == '' && !is_null($value))) && $oOptions->convertN)
{
//echo "Transforming 'N' to ".$oOptions->nValue.PHP_EOL;
return $oOptions->nValue;
}
else if ($value == 'Y' && $oOptions->convertY)
{
//echo "Transforming 'Y' to ".$oOptions->yValue.PHP_EOL;
return $oOptions->yValue;
}
}
//This spot should only be reached if no transformation occurs.
return $value;
}
/**
* This method is made final to prevent extending code from circumventing the
* initialization process that must take place prior to any of the translation
* infrastructure to work.
*
* The inialization process is dependent upon the survey being passed into the
* write function and so must be performed when the method is called and not
* prior to (such as in a constructor).
*
* All extending classes must implement the internalWrite function which is
* the code that is called after all initialization is completed.
*
* @param Survey $survey
* @param string $sLanguageCode
* @param FormattingOptions $oOptions
* @param boolean $bOutputHeaders Set if header should be given back
*/
final public function write(SurveyObj $survey, $sLanguageCode, FormattingOptions $oOptions, $bOutputHeaders=true)
{
//Output the survey.
$headers = array();
if ($bOutputHeaders)
{
foreach ($oOptions->selectedColumns as $column)
{
//Survey question field, $column value is a field name from the getFieldMap function.
switch ($oOptions->headingFormat)
{
case 'abbreviated':
$value = $this->getAbbreviatedHeading($survey, $column);
break;
case 'full':
$value = $this->getFullHeading($survey, $oOptions, $column);
break;
default:
case 'code':
if (isset($survey->fieldMap[$column])) {
$value = viewHelper::getFieldCode($survey->fieldMap[$column]);
} else {
// Token field
$value = $column;
}
break;
}
if ($oOptions->headerSpacesToUnderscores)
{
$value = str_replace(' ', '_', $value);
}
//$this->output.=$this->csvEscape($value).$this->separator;
$headers[] = $value;
}
}
//Output the results.
$sFile='';
foreach($survey->responses as $response)
{
$elementArray = array();
foreach ($oOptions->selectedColumns as $column)
{
$value = $response[$column];
if (isset($survey->fieldMap[$column]) && $survey->fieldMap[$column]['type']!='answer_time' && $survey->fieldMap[$column]['type']!='page_time' && $survey->fieldMap[$column]['type']!='interview_time')
{
switch ($oOptions->answerFormat) {
case 'long':
$elementArray[] = $this->transformResponseValue(
$survey->getFullAnswer($column, $value, $this->translator, $this->languageCode),
$survey->fieldMap[$column]['type'],
$oOptions,
$column);
break;
default:
case 'short':
$elementArray[] = $this->transformResponseValue(
$value,
$survey->fieldMap[$column]['type'],
$oOptions,
$column);
break;
}
}
else //Token table value
{
$elementArray[]=$value;
}
}
if ($oOptions->output=='display')
{
$this->outputRecord($headers, $elementArray, $oOptions);
} else {
$sFile.=$this->outputRecord($headers, $elementArray, $oOptions);
}
}
return $sFile;
}
protected function stripTagsFull($string)
{
$string=str_replace('-oth-','',$string);
return flattenText($string,false,true,'UTF-8',false);
}
/**
* This method will be called once for every row of data that needs to be
* output.
*
* Implementations must use the data from these method calls to construct
* proper output for their output type and the given FormattingOptions.
*
* @param array $headers
* @param array $values
* @param FormattingOptions $oOptions
*/
abstract protected function outputRecord($headers, $values, FormattingOptions $oOptions);
}