mirror of
https://github.com/YunoHost-Apps/limesurvey_ynh.git
synced 2024-09-03 19:36:32 +02:00
458 lines
No EOL
16 KiB
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);
|
|
} |