/** * Creates an array with details on a particular response for display purposes * Used in Print answers, Detailed response view and Detailed admin notification email * * @param mixed $iSurveyID * @param mixed $iResponseID * @param mixed $sLanguageCode * @param boolean $bHonorConditions Apply conditions */ function getFullResponseTable($iSurveyID, $iResponseID, $sLanguageCode, $bHonorConditions = true) { $aFieldMap = createFieldMap($iSurveyID, 'full', false, false, $sLanguageCode); //Get response data $idrow = SurveyDynamic::model($iSurveyID)->findByAttributes(array('id' => $iResponseID)); // Create array of non-null values - those are the relevant ones $aRelevantFields = array(); foreach ($aFieldMap as $sKey => $fname) { if (LimeExpressionManager::QuestionIsRelevant($fname['qid']) || $bHonorConditions == false) { $aRelevantFields[$sKey] = $fname; } } $aResultTable = array(); $oldgid = 0; $oldqid = 0; foreach ($aRelevantFields as $sKey => $fname) { if (!empty($fname['qid'])) { $attributes = getQuestionAttributeValues($fname['qid']); if (getQuestionAttributeValue($attributes, 'hidden') == 1) { continue; } } $question = $fname['question']; $subquestion = ''; if (isset($fname['gid']) && !empty($fname['gid'])) { //Check to see if gid is the same as before. if not show group name if ($oldgid !== $fname['gid']) { $oldgid = $fname['gid']; if (LimeExpressionManager::GroupIsRelevant($fname['gid']) || $bHonorConditions == false) { $aResultTable['gid_' . $fname['gid']] = array($fname['group_name'], QuestionGroup::model()->getGroupDescription($fname['gid'], $sLanguageCode)); } } } if (!empty($fname['qid'])) { if ($oldqid !== $fname['qid']) { $oldqid = $fname['qid']; if (isset($fname['subquestion']) || isset($fname['subquestion1']) || isset($fname['subquestion2'])) { $aResultTable['qid_' . $fname['sid'] . 'X' . $fname['gid'] . 'X' . $fname['qid']] = array($fname['question'], '', ''); } else { $answer = getExtendedAnswer($iSurveyID, $fname['fieldname'], $idrow[$fname['fieldname']], $sLanguageCode); $aResultTable[$fname['fieldname']] = array($question, '', $answer); continue; } } } else { $answer = getExtendedAnswer($iSurveyID, $fname['fieldname'], $idrow[$fname['fieldname']], $sLanguageCode); $aResultTable[$fname['fieldname']] = array($question, '', $answer); continue; } if (isset($fname['subquestion'])) { $subquestion = "[{$fname['subquestion']}]"; } if (isset($fname['subquestion1'])) { $subquestion = "[{$fname['subquestion1']}]"; } if (isset($fname['subquestion2'])) { $subquestion .= "[{$fname['subquestion2']}]"; } $answer = getExtendedAnswer($iSurveyID, $fname['fieldname'], $idrow[$fname['fieldname']], $sLanguageCode); $aResultTable[$fname['fieldname']] = array($question, $subquestion, $answer); } return $aResultTable; }
/** * This event is fired by when a response is submitted * available for a survey. * @param PluginEvent $event */ public function afterSurveyComplete() { // This method will send a notification email $event = $this->getEvent(); $surveyId = $event->get('surveyId'); // Only process the afterSurveyComplete if the plugin is Enabled for this survey and if the survey is Active if ($this->get('emailCount', 'Survey', $surveyId) < 1 || Survey::model()->findByPk($surveyId)->active != "Y") { // leave gracefully return true; } // Retrieve response and survey properties $responseId = $event->get('responseId'); $response = $this->pluginManager->getAPI()->getResponse($surveyId, $responseId); $sitename = $this->pluginManager->getAPI()->getConfigKey('sitename'); $surveyInfo = getSurveyInfo($surveyId); $adminemail = $surveyInfo['adminemail']; $bounce_email = $surveyInfo['bounce_email']; $isHtmlEmail = $surveyInfo['htmlemail'] == 'Y'; $baseLang = $surveyInfo['language']; for ($i = 1; $i <= $this->get('emailCount', 'Survey', $surveyId); $i++) { // Let's check if there is at least a valid destination email address $aTo = array(); $aAttachTo = array(); $aDestEmail = explode(';', $this->pluginManager->getAPI()->EMevaluateExpression($this->get('emailDestinations_' . $i, 'Survey', $surveyId))); $aDestEmail = array_map('trim', $aDestEmail); $aUploadQuestions = explode(';', $this->pluginManager->getAPI()->EMevaluateExpression($this->get('emailAttachFiles_' . $i, 'Survey', $surveyId))); $aUploadQuestions = array_map('trim', $aUploadQuestions); // prepare an array of valid destination email addresses foreach ($aDestEmail as $destemail) { if (validateEmailAddress($destemail)) { $aTo[] = $destemail; } } // prepare an array of valid attached files from upload-questions foreach ($aUploadQuestions as $uploadQuestion) { $sgqa = 0; $qtype = ''; if (isset($response[$uploadQuestion])) { // get SGQA code from question-code. Ther might be a better way to do this though... $sgqa = $this->pluginManager->getAPI()->EMevaluateExpression('{' . $uploadQuestion . '.sgqa}'); $qtype = $this->pluginManager->getAPI()->EMevaluateExpression('{' . $uploadQuestion . '.type}'); } // Only add the file if question is relevant if ($sgqa != 0 && $qtype == "|" && \LimeExpressionManager::QuestionIsRelevant($sgqa)) { $aFiles = json_decode($response[$uploadQuestion]); if (!is_null($aFiles) && is_array($aFiles)) { foreach ($aFiles as $file) { if (property_exists($file, 'name') && property_exists($file, 'filename')) { $name = $file->name; $filename = $file->filename; $aAttachTo[] = array(0 => $this->pluginManager->getAPI()->getConfigKey('uploaddir') . "/surveys/{$surveyId}/files/" . $filename, 1 => $name); } } } } } if (count($aTo) >= 1) { // Retrieve the language to use for the notification email $emailLang = $this->get('emailLang_' . $i, 'Survey', $surveyId); if ($emailLang == '--') { // in this case let's select the language used when submitting the response $emailLang = $response['startlanguage']; } $subjectTemplate = $this->get("emailSubject_{$i}_{$emailLang}", 'Survey', $surveyId); if ($subjectTemplate == "") { // If subject is not translated, use subject and body from the baseLang $emailLang = $baseLang; $subjectTemplate = $this->get("emailSubject_{$i}_{$emailLang}", 'Survey', $surveyId); } // Process the email subject and body through ExpressionManager $subject = $this->pluginManager->getAPI()->EMevaluateExpression($subjectTemplate); // Prepare an {ANSWERTABLE} variable if ($surveyInfo['datestamp'] == 'N') { //$aFilteredFields=array('id', 'submitdate', 'lastpage', 'startlanguage'); // Let's filter submitdate if survey is not datestampped $aFilteredFields = array('submitdate'); } else { //$aFilteredFields=array('id', 'lastpage', 'startlanguage'); $aFilteredFields = array(); } $replacementfields = array('ANSWERTABLE' => $this->translateAnswerTable($surveyId, $responseId, $emailLang, $isHtmlEmail, $aFilteredFields)); // Process emailBody through EM and replace {ANSWERTABLE} $body = \LimeExpressionManager::ProcessString($this->get("emailBody_{$i}_{$emailLang}", 'Survey', $surveyId), NULL, $replacementfields); // At last it's time to send the email SendEmailMessage($body, $subject, $aTo, $adminemail, $sitename, $isHtmlEmail, $bounce_email, $aAttachTo); } // END BLOCK 'if' aTo[] not emtpy } // END BLOCK 'for' emailCount }
/** * checkUploadedFileValidity used in SurveyRuntimeHelper */ function checkUploadedFileValidity($surveyid, $move, $backok = null) { global $thisstep; $clang = Yii::app()->lang; if (!isset($backok) || $backok != "Y") { $fieldmap = createFieldMap($surveyid, 'full', false, false, $_SESSION['survey_' . $surveyid]['s_lang']); if (isset($_POST['fieldnames']) && $_POST['fieldnames'] != "") { $fields = explode("|", $_POST['fieldnames']); foreach ($fields as $field) { if ($fieldmap[$field]['type'] == "|" && !strrpos($fieldmap[$field]['fieldname'], "_filecount")) { $validation = getQuestionAttributeValues($fieldmap[$field]['qid']); $filecount = 0; $json = $_POST[$field]; // if name is blank, its basic, hence check // else, its ajax, don't check, bypass it. if ($json != "" && $json != "[]") { $phparray = json_decode(stripslashes($json)); if ($phparray[0]->size != "") { // ajax $filecount = count($phparray); } else { // basic for ($i = 1; $i <= $validation['max_num_of_files']; $i++) { if (!isset($_FILES[$field . "_file_" . $i]) || $_FILES[$field . "_file_" . $i]['name'] == '') { continue; } $filecount++; $file = $_FILES[$field . "_file_" . $i]; // File size validation if ($file['size'] > $validation['max_filesize'] * 1000) { $filenotvalidated = array(); $filenotvalidated[$field . "_file_" . $i] = sprintf($clang->gT("Sorry, the uploaded file (%s) is larger than the allowed filesize of %s KB."), $file['size'], $validation['max_filesize']); $append = true; } // File extension validation $pathinfo = pathinfo(basename($file['name'])); $ext = $pathinfo['extension']; $validExtensions = explode(",", $validation['allowed_filetypes']); if (!in_array($ext, $validExtensions)) { if (isset($append) && $append) { $filenotvalidated[$field . "_file_" . $i] .= sprintf($clang->gT("Sorry, only %s extensions are allowed!"), $validation['allowed_filetypes']); unset($append); } else { $filenotvalidated = array(); $filenotvalidated[$field . "_file_" . $i] .= sprintf($clang->gT("Sorry, only %s extensions are allowed!"), $validation['allowed_filetypes']); } } } } } else { $filecount = 0; } if (isset($validation['min_num_of_files']) && $filecount < $validation['min_num_of_files'] && LimeExpressionManager::QuestionIsRelevant($fieldmap[$field]['qid'])) { $filenotvalidated = array(); $filenotvalidated[$field] = $clang->gT("The minimum number of files has not been uploaded."); } } } } if (isset($filenotvalidated)) { if (isset($move) && $move == "moveprev") { $_SESSION['survey_' . $surveyid]['step'] = $thisstep; } if (isset($move) && $move == "movenext") { $_SESSION['survey_' . $surveyid]['step'] = $thisstep; } return $filenotvalidated; } } if (!isset($filenotvalidated)) { return false; } else { return $filenotvalidated; } }
/** * Unit test Relevance using a simplified syntax to represent questions. */ static function UnitTestRelevance() { // Tests: varName~relevance~inputType~message $tests = <<<EOT name~1~text~What is your name? age~1~text~How old are you (must be 16-80)? badage~1~expr~{badage=((age<16) || (age>80))} agestop~!is_empty(age) && ((age<16) || (age>80))~message~Sorry, {name}, you are too {if((age<16),'young',if((age>80),'old','middle-aged'))} for this test. kids~!((age<16) || (age>80))~yesno~Do you have children (Y/N)? kidsO~!is_empty(kids) && !(kids=='Y' or kids=='N')~message~Please answer the question about whether you have children with 'Y' or 'N'. wantsKids~kids=='N'~yesno~Do you hope to have kids some day (Y/N)? wantsKidsY~wantsKids=='Y'~message~{name}, I hope you are able to have children some day! wantsKidsN~wantsKids=='N'~message~{name}, I hope you have a wonderfully fulfilling life! wantsKidsO~!is_empty(wantsKids) && !(wantsKids=='Y' or wantsKids=='N')~message~Please answer the question about whether you want children with 'Y' or 'N'. parents~1~expr~{parents = (!badage && kids=='Y')} numKids~kids=='Y'~text~How many children do you have? numKidsValidation~parents and strlen(numKids) > 0 and numKids <= 0~message~{name}, please check your entries. You said you do have children, {numKids} of them, which makes no sense. kid1~numKids >= 1~text~How old is your first child? kid2~numKids >= 2~text~How old is your second child? kid3~numKids >= 3~text~How old is your third child? kid4~numKids >= 4~text~How old is your fourth child? kid5~numKids >= 5~text~How old is your fifth child? sumage~1~expr~{sumage=sum(kid1.NAOK,kid2.NAOK,kid3.NAOK,kid4.NAOK,kid5.NAOK)} report~numKids > 0~message~{name}, you said you are {age} and that you have {numKids} kids. The sum of ages of your first {min(numKids,5)} kids is {sumage}. EOT; $vars = array(); $varsNAOK = array(); $varSeq = array(); $testArgs = array(); $argInfo = array(); LimeExpressionManager::SetDirtyFlag(); $LEM =& LimeExpressionManager::singleton(); LimeExpressionManager::StartProcessingPage(true); LimeExpressionManager::StartProcessingGroup(1); // pretending this is group 1 // collect variables $i = 0; foreach (explode("\n", $tests) as $test) { $args = explode("~", $test); $type = $args[1] == 'expr' ? '*' : $args[1] == 'message' ? 'X' : 'S'; $vars[$args[0]] = array('sgqa' => $args[0], 'code' => '', 'jsName' => 'java' . $args[0], 'jsName_on' => 'java' . $args[0], 'readWrite' => 'Y', 'type' => $type, 'relevanceStatus' => '1', 'gid' => 1, 'gseq' => 1, 'qseq' => $i, 'qid' => $i); $varSeq[] = $args[0]; $testArgs[] = $args; $LEM->questionId2questionSeq[$i] = $i; $LEM->questionId2groupSeq[$i] = 1; $LEM->questionSeq2relevance[$i] = array('relevance' => htmlspecialchars(preg_replace('/[[:space:]]/', ' ', $args[1]), ENT_QUOTES), 'qid' => $i, 'qseq' => $i, 'gseq' => 1, 'jsResultVar' => 'java' . $args[0], 'type' => $type, 'hidden' => false, 'gid' => 1); ++$i; } $LEM->knownVars = $vars; $LEM->gRelInfo[1] = array('gid' => 1, 'gseq' => 1, 'eqn' => '', 'result' => 1, 'numJsVars' => 0, 'relevancejs' => '', 'relevanceVars' => '', 'prettyPrint' => ''); $LEM->ProcessAllNeededRelevance(); // collect relevance $alias2varName = array(); $varNameAttr = array(); for ($i = 0; $i < count($testArgs); ++$i) { $testArg = $testArgs[$i]; $var = $testArg[0]; $rel = LimeExpressionManager::QuestionIsRelevant($i); $question = LimeExpressionManager::ProcessString($testArg[3], $i, NULL, true, 1, 1); $jsVarName = 'java' . str_replace('#', '_', $testArg[0]); $argInfo[] = array('num' => $i, 'name' => $jsVarName, 'sgqa' => $testArg[0], 'type' => $testArg[2], 'question' => $question, 'relevance' => $testArg[1], 'relevanceStatus' => $rel); $alias2varName[$var] = array('jsName' => $jsVarName, 'jsPart' => "'" . $var . "':'" . $jsVarName . "'"); $alias2varName[$jsVarName] = array('jsName' => $jsVarName, 'jsPart' => "'" . $jsVarName . "':'" . $jsVarName . "'"); $varNameAttr[$jsVarName] = "'" . $jsVarName . "':{" . "'jsName':'" . $jsVarName . "','jsName_on':'" . $jsVarName . "','sgqa':'" . substr($jsVarName, 4) . "','qid':" . $i . ",'gid':" . 1 . "}"; } $LEM->alias2varName = $alias2varName; $LEM->varNameAttr = $varNameAttr; LimeExpressionManager::FinishProcessingGroup(); LimeExpressionManager::FinishProcessingPage(); print <<<EOD <script type='text/javascript'> <!-- var LEMradix='.'; function checkconditions(value, name, type, evt_type) { if (typeof evt_type === 'undefined') { evt_type = 'onchange'; } ExprMgr_process_relevance_and_tailoring(evt_type,name,type); } // --> </script> EOD; print LimeExpressionManager::GetRelevanceAndTailoringJavaScript(); // Print Table of questions print "<h3>This is a test of dynamic relevance.</h3>"; print "Enter your name and age, and try all the permutations of answers to whether you have or want children.<br />\n"; print "Note how the text and sum of ages changes dynamically; that prior answers are remembered; and that irrelevant values are not included in the sum of ages.<br />"; print "<table class='table' border='1'><tr><td>"; foreach ($argInfo as $arg) { $rel = LimeExpressionManager::QuestionIsRelevant($arg['num']); print "<div id='question" . $arg['num'] . ($rel ? "'" : "' style='display: none'") . ">\n"; print "<input type='hidden' id='display" . $arg['num'] . "' name='" . $arg['num'] . "' value='" . ($rel ? 'on' : '') . "'/>\n"; if ($arg['type'] == 'expr') { // Hack for testing purposes - rather than using LimeSurvey internals to store the results of equations, process them via a hidden <div> print "<div style='display: none' id='hack_" . $arg['name'] . "'>" . $arg['question']; print "<input type='hidden' id='" . $arg['name'] . "' name='" . $arg['name'] . "' value=''/></div>\n"; } else { print "<table class='table' border='1' width='100%'>\n<tr>\n<td>[Q" . $arg['num'] . "] " . $arg['question'] . "</td>\n"; switch ($arg['type']) { case 'yesno': case 'text': print "<td><input type='text' id='" . $arg['name'] . "' name='" . $arg['sgqa'] . "' value='' onchange='checkconditions(this.value, this.name, this.type)'/></td>\n"; break; case 'message': print "<input type='hidden' id='" . $arg['name'] . "' name='" . $arg['sgqa'] . "' value=''/>\n"; break; } print "</tr>\n</table>\n"; } print "</div>\n"; } print "</table>"; LimeExpressionManager::SetDirtyFlag(); // so subsequent tests don't try to access these variables }