/** * This function stores a survey in the database. * * @param array $values * * @return array $return the type of return message that has to be displayed and the message in it * * @author Patrick Cool <*****@*****.**>, Ghent University * @version February 2007 */ public static function store_survey($values) { $_user = api_get_user_info(); $course_id = api_get_course_int_id(); $session_id = api_get_session_id(); $courseCode = api_get_course_id(); $table_survey = Database::get_course_table(TABLE_SURVEY); $shared_survey_id = 0; if (!isset($values['survey_id'])) { // Check if the code doesn't soon exists in this language $sql = 'SELECT 1 FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND code="' . Database::escape_string($values['survey_code']) . '" AND lang="' . Database::escape_string($values['survey_language']) . '"'; $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { Display::addFlash(Display::return_message(get_lang('ThisSurveyCodeSoonExistsInThisLanguage'), 'error')); $return['type'] = 'error'; $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; return $return; } if (!isset($values['anonymous'])) { $values['anonymous'] = 0; } $values['anonymous'] = intval($values['anonymous']); $additional['columns'] = ''; $extraParams = []; if ($values['anonymous'] == 0) { // Input_name_list $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0; $extraParams['show_form_profile'] = $values['show_form_profile']; if ($values['show_form_profile'] == 1) { // Input_name_list $fields = explode(',', $values['input_name_list']); $field_values = ''; foreach ($fields as &$field) { if ($field != '') { if ($values[$field] == '') { $values[$field] = 0; } $field_values .= $field . ':' . $values[$field] . '@'; } } $extraParams['form_fields'] = $field_values; } else { $extraParams['form_fields'] = ''; } } else { // Input_name_list $extraParams['show_form_profile'] = 0; $extraParams['form_fields'] = ''; } if ($values['survey_type'] == 1) { $extraParams['survey_type'] = 1; $extraParams['shuffle'] = $values['shuffle']; $extraParams['one_question_per_page'] = $values['one_question_per_page']; $extraParams['parent_id'] = $values['parent_id']; // Logic for versioning surveys if (!empty($values['parent_id'])) { $versionValue = ''; $sql = 'SELECT survey_version FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND parent_id = ' . intval($values['parent_id']) . ' ORDER BY survey_version DESC LIMIT 1'; $rs = Database::query($sql); if (Database::num_rows($rs) === 0) { $sql = 'SELECT survey_version FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND survey_id = ' . intval($values['parent_id']); $rs = Database::query($sql); $getversion = Database::fetch_array($rs, 'ASSOC'); if (empty($getversion['survey_version'])) { $versionValue = ++$getversion['survey_version']; } else { $versionValue = $getversion['survey_version']; } } else { $row = Database::fetch_array($rs, 'ASSOC'); $pos = api_strpos($row['survey_version']); if ($pos === false) { $row['survey_version'] = $row['survey_version'] + 1; $versionValue = $row['survey_version']; } else { $getlast = explode('\\.', $row['survey_version']); $lastversion = array_pop($getlast); $lastversion = $lastversion + 1; $add = implode('.', $getlast); if ($add != '') { $insertnewversion = $add . '.' . $lastversion; } else { $insertnewversion = $lastversion; } $versionValue = $insertnewversion; } } $extraParams['survey_version'] = $versionValue; } } $params = ['c_id' => $course_id, 'code' => strtolower(CourseManager::generate_course_code($values['survey_code'])), 'title' => $values['survey_title'], 'subtitle' => $values['survey_subtitle'], 'author' => $_user['user_id'], 'lang' => $values['survey_language'], 'avail_from' => $values['start_date'], 'avail_till' => $values['end_date'], 'is_shared' => $shared_survey_id, 'template' => 'template', 'intro' => $values['survey_introduction'], 'surveythanks' => $values['survey_thanks'], 'creation_date' => api_get_utc_datetime(), 'anonymous' => $values['anonymous'], 'session_id' => api_get_session_id(), 'visible_results' => $values['visible_results']]; $params = array_merge($params, $extraParams); $survey_id = Database::insert($table_survey, $params); if ($survey_id > 0) { $sql = "UPDATE {$table_survey} SET survey_id = {$survey_id}\n WHERE iid = {$survey_id}"; Database::query($sql); // Insert into item_property api_item_property_update(api_get_course_info(), TOOL_SURVEY, $survey_id, 'SurveyAdded', api_get_user_id()); } if ($values['survey_type'] == 1 && !empty($values['parent_id'])) { SurveyManager::copy_survey($values['parent_id'], $survey_id); } Display::addFlash(Display::return_message(get_lang('SurveyCreatedSuccesfully'), 'success')); $return['id'] = $survey_id; } else { // Check whether the code doesn't soon exists in this language $sql = 'SELECT 1 FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND code = "' . Database::escape_string($values['survey_code']) . '" AND lang = "' . Database::escape_string($values['survey_language']) . '" AND survey_id !=' . intval($values['survey_id']); $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { Display::addFlash(Display::return_message(get_lang('ThisSurveyCodeSoonExistsInThisLanguage'), 'error')); $return['type'] = 'error'; $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; return $return; } if (!isset($values['anonymous']) || isset($values['anonymous']) && $values['anonymous'] == '') { $values['anonymous'] = 0; } $values['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : null; $values['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : null; $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : null; $extraParams = []; $extraParams['shuffle'] = $values['shuffle']; $extraParams['one_question_per_page'] = $values['one_question_per_page']; $extraParams['shuffle'] = $values['shuffle']; if ($values['anonymous'] == 0) { $extraParams['show_form_profile'] = $values['show_form_profile']; if ($values['show_form_profile'] == 1) { $fields = explode(',', $values['input_name_list']); $field_values = ''; foreach ($fields as &$field) { if ($field != '') { if (!isset($values[$field]) || isset($values[$field]) && $values[$field] == '') { $values[$field] = 0; } $field_values .= $field . ':' . $values[$field] . '@'; } } $extraParams['form_fields'] = $field_values; } else { $extraParams['form_fields'] = ''; } } else { $extraParams['show_form_profile'] = 0; $extraParams['form_fields'] = ''; } $params = ['title' => $values['survey_title'], 'subtitle' => $values['survey_subtitle'], 'author' => $_user['user_id'], 'lang' => $values['survey_language'], 'avail_from' => $values['start_date'], 'avail_till' => $values['end_date'], 'is_shared' => $shared_survey_id, 'template' => 'template', 'intro' => $values['survey_introduction'], 'surveythanks' => $values['survey_thanks'], 'anonymous' => $values['anonymous'], 'session_id' => api_get_session_id(), 'visible_results' => $values['visible_results']]; $params = array_merge($params, $extraParams); Database::update($table_survey, $params, ['c_id = ? AND survey_id = ?' => [$course_id, $values['survey_id']]]); // Update into item_property (update) api_item_property_update(api_get_course_info(), TOOL_SURVEY, $values['survey_id'], 'SurveyUpdated', api_get_user_id()); Display::addFlash(Display::return_message(get_lang('SurveyUpdatedSuccesfully'), 'confirmation')); $return['id'] = $values['survey_id']; } $survey_id = intval($return['id']); // Gradebook $gradebook_option = false; if (isset($values['survey_qualify_gradebook'])) { $gradebook_option = $values['survey_qualify_gradebook'] > 0; } $gradebook_link_type = 8; $link_info = GradebookUtils::is_resource_in_course_gradebook($courseCode, $gradebook_link_type, $survey_id, $session_id); $gradebook_link_id = $link_info ? $link_info->getId() : false; if ($gradebook_option) { if ($survey_id > 0) { $title_gradebook = ''; // Not needed here. $description_gradebook = ''; // Not needed here. $survey_weight = floatval($_POST['survey_weight']); $max_score = 1; if (!$gradebook_link_id) { GradebookUtils::add_resource_to_course_gradebook($values['category_id'], $courseCode, $gradebook_link_type, $survey_id, $title_gradebook, $survey_weight, $max_score, $description_gradebook, 1, $session_id); } else { GradebookUtils::update_resource_from_course_gradebook($gradebook_link_id, $courseCode, $survey_weight); } } } else { // Delete everything of the gradebook for this $linkId GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id); //comenting this line to correctly return the function msg //exit; } return $return; }
/** * @param array $answer * @param string $user_answer * @return array */ public static function check_fill_in_blanks($answer, $user_answer) { // the question is encoded like this // [A] B [C] D [E] F::10,10,10@1 // number 1 before the "@" means that is a switchable fill in blank question // [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10 // means that is a normal fill blank question // first we explode the "::" $pre_array = explode('::', $answer); // is switchable fill blank or not $last = count($pre_array) - 1; $is_set_switchable = explode('@', $pre_array[$last]); $switchable_answer_set = false; if (isset($is_set_switchable[1]) && $is_set_switchable[1] == 1) { $switchable_answer_set = true; } $answer = ''; for ($k = 0; $k < $last; $k++) { $answer .= $pre_array[$k]; } // splits weightings that are joined with a comma $answerWeighting = explode(',', $is_set_switchable[0]); // we save the answer because it will be modified //$temp = $answer; $temp = $answer; $answer = ''; $j = 0; //initialise answer tags $user_tags = $correct_tags = $real_text = array(); // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks (detect '[') if (($pos = api_strpos($temp, '[')) === false) { // adds the end of the text $answer = $temp; $real_text[] = $answer; break; //no more "blanks", quit the loop } // adds the piece of text that is before the blank //and ends with '[' into a general storage array $real_text[] = api_substr($temp, 0, $pos + 1); $answer .= api_substr($temp, 0, $pos + 1); //take the string remaining (after the last "[" we found) $temp = api_substr($temp, $pos + 1); // quit the loop if there are no more blanks, and update $pos to the position of next ']' if (($pos = api_strpos($temp, ']')) === false) { // adds the end of the text $answer .= $temp; break; } $str = $user_answer; preg_match_all('#\\[([^[]*)\\]#', $str, $arr); $str = str_replace('\\r\\n', '', $str); $choice = $arr[1]; $tmp = api_strrpos($choice[$j], ' / '); $choice[$j] = api_substr($choice[$j], 0, $tmp); $choice[$j] = trim($choice[$j]); //Needed to let characters ' and " to work as part of an answer $choice[$j] = stripslashes($choice[$j]); $user_tags[] = api_strtolower($choice[$j]); //put the contents of the [] answer tag into correct_tags[] $correct_tags[] = api_strtolower(api_substr($temp, 0, $pos)); $j++; $temp = api_substr($temp, $pos + 1); } $answer = ''; $real_correct_tags = $correct_tags; $chosen_list = array(); $good_answer = array(); for ($i = 0; $i < count($real_correct_tags); $i++) { if (!$switchable_answer_set) { //needed to parse ' and " characters $user_tags[$i] = stripslashes($user_tags[$i]); if ($correct_tags[$i] == $user_tags[$i]) { $good_answer[$correct_tags[$i]] = 1; } elseif (!empty($user_tags[$i])) { $good_answer[$correct_tags[$i]] = 0; } else { $good_answer[$correct_tags[$i]] = 0; } } else { // switchable fill in the blanks if (in_array($user_tags[$i], $correct_tags)) { $correct_tags = array_diff($correct_tags, $chosen_list); $good_answer[$correct_tags[$i]] = 1; } elseif (!empty($user_tags[$i])) { $good_answer[$correct_tags[$i]] = 0; } else { $good_answer[$correct_tags[$i]] = 0; } } // adds the correct word, followed by ] to close the blank $answer .= ' / <font color="green"><b>' . $real_correct_tags[$i] . '</b></font>]'; if (isset($real_text[$i + 1])) { $answer .= $real_text[$i + 1]; } } return $good_answer; }
/** * Find links by name * To keep consistency, do not call this method but LinkFactory::find_links instead. * @todo can be written more efficiently using a new (but very complex) sql query */ public function find_links($name_mask, $selectcat) { $rootcat = Category::load($selectcat); $links = $rootcat[0]->get_links(api_is_allowed_to_edit() ? null : api_get_user_id(), true); $foundlinks = array(); foreach ($links as $link) { if (!(api_strpos(api_strtolower($link->get_name()), api_strtolower($name_mask)) === false)) { $foundlinks[] = $link; } } return $foundlinks; }
/** * This function stores a survey in the database. * * @param array $values * @return array $return the type of return message that has to be displayed and the message in it * * @author Patrick Cool <*****@*****.**>, Ghent University * @version February 2007 */ static function store_survey($values) { // Table definitions $table_survey = Database::get_course_table(TABLE_SURVEY); $shared_survey_id = 0; $course_id = api_get_course_int_id(); if (!$values['survey_id'] || !is_numeric($values['survey_id'])) { // Check if the code doesn't soon exists in this language $sql = 'SELECT 1 FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND code="' . Database::escape_string($values['survey_code']) . '" AND lang="' . Database::escape_string($values['survey_language']) . '"'; $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { $return['message'] = 'ThisSurveyCodeSoonExistsInThisLanguage'; $return['type'] = 'error'; $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; return $return; } if ($values['anonymous'] == '') { $values['anonymous'] = 0; } $additional['columns'] = ''; $additional['values'] = ''; if ($values['anonymous'] == 0) { // Input_name_list $additional['columns'] .= ', show_form_profile'; $additional['values'] .= ",'" . Database::escape_string($values['show_form_profile']) . "'"; if ($values['show_form_profile'] == 1) { // Input_name_list $fields = explode(',', $values['input_name_list']); $field_values = ''; foreach ($fields as &$field) { if ($field != '') { if ($values[$field] == '') { $values[$field] = 0; } $field_values .= $field . ':' . $values[$field] . '@'; } } $additional['columns'] .= ', form_fields'; $additional['values'] .= ",'" . Database::escape_string($field_values) . "'"; } else { $additional['columns'] .= ', form_fields'; $additional['values'] .= ",''"; } } else { // Input_name_list $additional['columns'] .= ', show_form_profile'; $additional['values'] .= ",'0'"; $additional['columns'] .= ', form_fields'; $additional['values'] .= ",''"; } if ($values['survey_type'] == 1) { $additional['columns'] .= ', survey_type'; $additional['values'] .= ",'1'"; $additional['columns'] .= ', shuffle'; $additional['values'] .= ",'" . Database::escape_string($values['shuffle']) . "'"; $additional['columns'] .= ', one_question_per_page'; $additional['values'] .= ",'" . Database::escape_string($values['one_question_per_page']) . "'"; $additional['columns'] .= ', parent_id'; $additional['values'] .= ",'" . Database::escape_string($values['parent_id']) . "'"; // Logic for versioning surveys if (!empty($values['parent_id'])) { $additional['columns'] .= ', survey_version'; $sql = 'SELECT survey_version FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND parent_id = ' . Database::escape_string($values['parent_id']) . ' ORDER BY survey_version DESC LIMIT 1'; $rs = Database::query($sql); if (Database::num_rows($rs) === 0) { $sql = 'SELECT survey_version FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' survey_id = ' . Database::escape_string($values['parent_id']); $rs = Database::query($sql); $getversion = Database::fetch_array($rs, 'ASSOC'); if (empty($getversion['survey_version'])) { $additional['values'] .= ",'" . ++$getversion['survey_version'] . "'"; } else { $additional['values'] .= ",'" . $getversion['survey_version'] . ".1'"; } } else { $row = Database::fetch_array($rs, 'ASSOC'); $pos = api_strpos($row['survey_version']); if ($pos === false) { //$new_version = substr($row['survey_version'],$pos, count()) $row['survey_version'] = $row['survey_version'] + 1; $additional['values'] .= ",'" . $row['survey_version'] . "'"; } else { $getlast = api_split('\\.', $row['survey_version']); $lastversion = array_pop($getlast); $lastversion = $lastversion + 1; $add = implode('.', $getlast); if ($add != '') { $insertnewversion = $add . '.' . $lastversion; } else { $insertnewversion = $lastversion; } $additional['values'] .= ",'" . $insertnewversion . "'"; } } } } $course_id = api_get_course_int_id(); $sql = "INSERT INTO {$table_survey} (c_id, code, title, subtitle, author, lang, avail_from, avail_till, is_shared, template, intro, surveythanks, creation_date, anonymous" . $additional['columns'] . ", session_id) VALUES (\n\t\t\t\t\t\t{$course_id},\n\t\t\t\t\t\t'" . Database::escape_string(strtolower(CourseManager::generate_course_code(api_substr($values['survey_code'], 0)))) . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['survey_title']) . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['survey_subtitle']) . "',\n\t\t\t\t\t\t'" . api_get_user_id() . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['survey_language']) . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['start_date']) . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['end_date']) . "',\n\t\t\t\t\t\t'" . Database::escape_string($shared_survey_id) . "',\n\t\t\t\t\t\t'template',\n\t\t\t\t\t\t'" . Database::escape_string($values['survey_introduction']) . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['survey_thanks']) . "',\n\t\t\t\t\t\t'" . api_get_utc_datetime() . "',\n\t\t\t\t\t\t'" . Database::escape_string($values['anonymous']) . "'" . $additional['values'] . ",\n\t\t\t\t\t\t" . api_get_session_id() . "\n\t\t\t\t\t\t)"; $result = Database::query($sql); $survey_id = Database::insert_id(); if ($survey_id > 0) { // Insert into item_property api_item_property_update(api_get_course_info(), TOOL_SURVEY, $survey_id, 'SurveyAdded', api_get_user_id()); } if ($values['survey_type'] == 1 && !empty($values['parent_id'])) { self::copy_survey($values['parent_id'], $survey_id); } $return['message'] = 'SurveyCreatedSuccesfully'; $return['type'] = 'confirmation'; $return['id'] = $survey_id; } else { // Check whether the code doesn't soon exists in this language $sql = 'SELECT 1 FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND code="' . Database::escape_string($values['survey_code']) . '" AND lang="' . Database::escape_string($values['survey_language']) . '" AND survey_id!=' . intval($values['survey_id']); $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { $return['message'] = 'ThisSurveyCodeSoonExistsInThisLanguage'; $return['type'] = 'error'; $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; return $return; } if ($values['anonymous'] == '') { $values['anonymous'] = 0; } $additionalsets = ", shuffle = '" . Database::escape_string($values['shuffle']) . "'"; $additionalsets .= ", one_question_per_page = '" . Database::escape_string($values['one_question_per_page']) . "'"; if ($values['anonymous'] == 0) { $additionalsets .= ", show_form_profile = '" . Database::escape_string($values['show_form_profile']) . "'"; if (isset($values['show_form_profile']) && $values['show_form_profile'] == 1) { $fields = explode(',', $values['input_name_list']); $field_values = ''; foreach ($fields as &$field) { if ($field != '') { if ($values[$field] == '') { $values[$field] = 0; } $field_values .= $field . ':' . $values[$field] . '@'; } } $additionalsets .= ", form_fields = '" . Database::escape_string($field_values) . "'"; } else { $additionalsets .= ", form_fields = '' "; } } else { $additionalsets .= ", show_form_profile = '0'"; $additionalsets .= ", form_fields = '' "; } $sql = "UPDATE {$table_survey} SET\n title \t\t\t= '" . Database::escape_string($values['survey_title']) . "',\n code = '" . Database::escape_string(strtolower(CourseManager::generate_course_code(api_substr($values['survey_code'], 0)))) . "',\n subtitle \t\t= '" . Database::escape_string($values['survey_subtitle']) . "',\n author \t\t\t= '" . api_get_user_id() . "',\n lang \t\t\t= '" . Database::escape_string($values['survey_language']) . "',\n avail_from \t\t= '" . Database::escape_string($values['start_date']) . "',\n avail_till\t\t= '" . Database::escape_string($values['end_date']) . "',\n is_shared\t\t= '" . Database::escape_string($shared_survey_id) . "',\n template \t\t= 'template',\n intro\t\t\t= '" . Database::escape_string($values['survey_introduction']) . "',\n surveythanks\t= '" . Database::escape_string($values['survey_thanks']) . "',\n anonymous = '" . Database::escape_string($values['anonymous']) . "'" . $additionalsets . "\n\t\t\t\t\tWHERE c_id = {$course_id} AND survey_id = '" . Database::escape_string($values['survey_id']) . "'"; Database::query($sql); // Update into item_property (update) api_item_property_update(api_get_course_info(), TOOL_SURVEY, $values['survey_id'], 'SurveyUpdated', api_get_user_id()); $return['message'] = 'SurveyUpdatedSuccesfully'; $return['type'] = 'confirmation'; $return['id'] = $values['survey_id']; } return $return; }
/** * @param string $correctAnswer * * @return int */ public static function getFillTheBlankAnswerType($correctAnswer) { if (api_strpos($correctAnswer, "|") && !api_strpos($correctAnswer, "||")) { return self::FILL_THE_BLANK_MENU; } elseif (api_strpos($correctAnswer, "||")) { return self::FILL_THE_BLANK_SEVERAL_ANSWER; } else { return self::FILL_THE_BLANK_STANDARD; } }
/** * This function was originally found in the exercise_show.php * @param int exe id * @param int question id * @param int the choice the user selected * @param array the hotspot coordinates $hotspot[$question_id] = coordinates * @param string function is called from 'exercise_show' or 'exercise_result' * @param bool save results in the DB or just show the reponse * @param bool gets information from DB or from the current selection * @param bool show results or not * @todo reduce parameters of this function * @return string html code */ public function manageAnswers($exeId, $questionId, $choice, $from = 'exercise_show', $exerciseResultCoordinates = array(), $saved_results = true, $from_database = false, $show_result = true, $hotspot_delineation_result = array(), $updateResults = false) { global $debug; global $learnpath_id, $learnpath_item_id; //needed in order to use in the exercise_attempt() for the time require_once api_get_path(LIBRARY_PATH) . 'geometry.lib.php'; $feedback_type = $this->feedback_type; $propagate_neg = $this->selectPropagateNeg(); if ($debug) { error_log("<------ manage_answer ------> "); error_log('exe_id: ' . $exeId); error_log('$from: ' . $from); error_log('$saved_results: ' . intval($saved_results)); error_log('$from_database: ' . intval($from_database)); error_log('$show_result: ' . $show_result); error_log('$propagate_neg: ' . $propagate_neg); error_log('$exerciseResultCoordinates: ' . print_r($exerciseResultCoordinates, 1)); error_log('$hotspot_delineation_result: ' . print_r($hotspot_delineation_result, 1)); error_log('$learnpath_id: ' . $learnpath_id); error_log('$learnpath_item_id: ' . $learnpath_item_id); error_log('$choice: ' . print_r($choice, 1)); } $extra_data = array(); $final_overlap = 0; $final_missing = 0; $final_excess = 0; $overlap_color = 0; $missing_color = 0; $excess_color = 0; $threadhold1 = 0; $threadhold2 = 0; $threadhold3 = 0; $arrques = null; $arrans = null; $questionId = intval($questionId); $exeId = intval($exeId); $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER); // Creates a temporary Question object $course_id = api_get_course_int_id(); $objQuestionTmp = Question::read($questionId, $course_id); if ($objQuestionTmp === false) { return false; } $questionName = $objQuestionTmp->selectTitle(); $questionWeighting = $objQuestionTmp->selectWeighting(); $answerType = $objQuestionTmp->selectType(); $quesId = $objQuestionTmp->selectId(); $extra = $objQuestionTmp->extra; $next = 1; //not for now //Extra information of the question if (!empty($extra)) { $extra = explode(':', $extra); if ($debug) { error_log(print_r($extra, 1)); } //Fixes problems with negatives values using intval $true_score = intval($extra[0]); $false_score = intval($extra[1]); $doubt_score = intval($extra[2]); } $totalWeighting = 0; $totalScore = 0; // Destruction of the Question object unset($objQuestionTmp); // Construction of the Answer object $objAnswerTmp = new Answer($questionId, null, $this); $nbrAnswers = $objAnswerTmp->selectNbrAnswers(); if ($debug) { error_log('Count of answers: ' . $nbrAnswers); error_log('$answerType: ' . $answerType); } if ($answerType == FREE_ANSWER || $answerType == ORAL_EXPRESSION) { $nbrAnswers = 1; } $nano = null; if ($answerType == ORAL_EXPRESSION) { $exe_info = get_exercise_results_by_attempt($exeId); $exe_info = $exe_info[$exeId]; $params = array(); $params['course_id'] = api_get_course_int_id(); $params['session_id'] = api_get_session_id(); $params['user_id'] = isset($exe_info['exe_user_id']) ? $exe_info['exe_user_id'] : api_get_user_id(); $params['exercise_id'] = isset($exe_info['exe_exo_id']) ? $exe_info['exe_exo_id'] : $this->id; $params['question_id'] = $questionId; $params['exe_id'] = isset($exe_info['exe_id']) ? $exe_info['exe_id'] : $exeId; $nano = new Nanogong($params); //probably this attempt came in an exercise all question by page if ($feedback_type == 0) { $nano->replace_with_real_exe($exeId); } } $user_answer = ''; // Get answer list for matching $sql_answer = 'SELECT iid, answer FROM ' . $table_ans . ' WHERE question_id = "' . $questionId . '" '; $res_answer = Database::query($sql_answer); $answer_matching = array(); $answer_list = array(); while ($real_answer = Database::fetch_array($res_answer)) { $answer_matching[$real_answer['iid']] = $real_answer['answer']; $answer_list[] = $real_answer['iid']; } if ($answerType == FREE_ANSWER || $answerType == ORAL_EXPRESSION) { $nbrAnswers = 1; $answer_list[] = 1; } $real_answers = array(); $quiz_question_options = Question::readQuestionOption($questionId, $course_id); $organs_at_risk_hit = 0; $questionScore = 0; if ($debug) { error_log('<<-- Start answer loop -->'); } $answer_correct_array = array(); //for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { $counter = 1; foreach ($answer_list as $answerId) { /** @var \Answer $objAnswerTmp */ $answer = $objAnswerTmp->selectAnswer($answerId); $answerComment = $objAnswerTmp->selectComment($answerId); $answerCorrect = $objAnswerTmp->isCorrect($answerId); $answerWeighting = (double) $objAnswerTmp->selectWeighting($answerId); //$numAnswer = $objAnswerTmp->selectAutoId($answerId); $numAnswer = $answerId; $answer_correct_array[$answerId] = (bool) $answerCorrect; if ($debug) { error_log("answer auto id: {$numAnswer} "); error_log("answer correct: {$answerCorrect} "); } //Delineation $delineation_cord = $objAnswerTmp->selectHotspotCoordinates(1); $answer_delineation_destination = $objAnswerTmp->selectDestination(1); switch ($answerType) { // for unique answer case UNIQUE_ANSWER: case UNIQUE_ANSWER_IMAGE: case UNIQUE_ANSWER_NO_OPTION: if ($from_database) { $queryans = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . " WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($queryans); $choice = Database::result($resultans, 0, "answer"); $studentChoice = $choice == $numAnswer ? 1 : 0; if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } else { $studentChoice = $choice == $numAnswer ? 1 : 0; if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } break; // for multiple answers // for multiple answers case MULTIPLE_ANSWER_TRUE_FALSE: if ($from_database) { $choice = array(); $queryans = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . " WHERE exe_id = " . $exeId . " AND question_id = " . $questionId; $resultans = Database::query($queryans); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $result = explode(':', $ind); $my_answer_id = $result[0]; $option = $result[1]; $choice[$my_answer_id] = $option; } $studentChoice = $choice[$numAnswer]; } else { $studentChoice = $choice[$numAnswer]; } if (!empty($studentChoice)) { if ($studentChoice == $answerCorrect) { $questionScore += $true_score; } else { if ($quiz_question_options[$studentChoice]['name'] != "Don't know") { $questionScore += $false_score; } else { $questionScore += $doubt_score; } } } else { //if no result then the user just hit don't know $studentChoice = 3; $questionScore += $doubt_score; } $totalScore = $questionScore; break; case MULTIPLE_ANSWER: //2 if ($from_database) { $choice = array(); $queryans = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . " WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($queryans); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$numAnswer]) ? $choice[$numAnswer] : null; $real_answers[$answerId] = (bool) $studentChoice; if ($studentChoice) { $questionScore += $answerWeighting; } } else { $studentChoice = isset($choice[$numAnswer]) ? $choice[$numAnswer] : null; $real_answers[$answerId] = (bool) $studentChoice; if (isset($studentChoice)) { $questionScore += $answerWeighting; } } $totalScore += $answerWeighting; if ($debug) { error_log("studentChoice: {$studentChoice}"); } break; case GLOBAL_MULTIPLE_ANSWER: if ($from_database) { $choice = array(); $queryans = "SELECT answer FROM {$TBL_TRACK_ATTEMPT} WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($queryans); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = $choice[$numAnswer]; $real_answers[$answerId] = (bool) $studentChoice; if ($studentChoice) { $questionScore += $answerWeighting; } } else { $studentChoice = $choice[$numAnswer]; if (isset($studentChoice)) { $questionScore += $answerWeighting; } $real_answers[$answerId] = (bool) $studentChoice; } $totalScore += $answerWeighting; if ($debug) { error_log("studentChoice: {$studentChoice}"); } break; case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: if ($from_database) { $queryans = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . " where exe_id = " . $exeId . " AND question_id= " . $questionId; $resultans = Database::query($queryans); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $result = explode(':', $ind); $my_answer_id = $result[0]; $option = $result[1]; $choice[$my_answer_id] = $option; } //$numAnswer = $objAnswerTmp->selectAutoId($answerId); $numAnswer = $answerId; $studentChoice = $choice[$numAnswer]; if ($answerCorrect == $studentChoice) { //$answerCorrect = 1; $real_answers[$answerId] = true; } else { //$answerCorrect = 0; $real_answers[$answerId] = false; } } else { $studentChoice = $choice[$numAnswer]; if ($answerCorrect == $studentChoice) { //$answerCorrect = 1; $real_answers[$answerId] = true; } else { //$answerCorrect = 0; $real_answers[$answerId] = false; } } break; case MULTIPLE_ANSWER_COMBINATION: if ($from_database) { $queryans = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . " where exe_id = '" . $exeId . "' and question_id= '" . $questionId . "'"; $resultans = Database::query($queryans); while ($row = Database::fetch_array($resultans)) { $choice[$row['answer']] = 1; } $studentChoice = $choice[$answerId]; if ($answerCorrect == 1) { if ($studentChoice) { $real_answers[$answerId] = true; } else { $real_answers[$answerId] = false; } } else { if ($studentChoice) { $real_answers[$answerId] = false; } else { $real_answers[$answerId] = true; } } } else { $studentChoice = $choice[$numAnswer]; if ($answerCorrect == 1) { if ($studentChoice) { $real_answers[$answerId] = true; } else { $real_answers[$answerId] = false; } } else { if ($studentChoice) { $real_answers[$answerId] = false; } else { $real_answers[$answerId] = true; } } } break; // for fill in the blanks // for fill in the blanks case FILL_IN_BLANKS: // the question is encoded like this // [A] B [C] D [E] F::10,10,10@1 // number 1 before the "@" means that is a switchable fill in blank question // [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10 // means that is a normal fill blank question // first we explode the "::" $pre_array = explode('::', $answer); // is switchable fill blank or not $last = count($pre_array) - 1; $is_set_switchable = explode('@', $pre_array[$last]); $switchable_answer_set = false; if (isset($is_set_switchable[1]) && $is_set_switchable[1] == 1) { $switchable_answer_set = true; } $answer = ''; for ($k = 0; $k < $last; $k++) { $answer .= $pre_array[$k]; } // splits weightings that are joined with a comma $answerWeighting = explode(',', $is_set_switchable[0]); // we save the answer because it will be modified //$temp = $answer; $temp = $answer; $answer = ''; $j = 0; //initialise answer tags $user_tags = $correct_tags = $real_text = array(); // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks (detect '[') if (($pos = api_strpos($temp, '[')) === false) { // adds the end of the text $answer = $temp; /* // Deprecated code // TeX parsing - replacement of texcode tags $answer = str_replace("{texcode}", $texstring, $answer); */ $real_text[] = $answer; break; //no more "blanks", quit the loop } // adds the piece of text that is before the blank //and ends with '[' into a general storage array $real_text[] = api_substr($temp, 0, $pos + 1); $answer .= api_substr($temp, 0, $pos + 1); //take the string remaining (after the last "[" we found) $temp = api_substr($temp, $pos + 1); // quit the loop if there are no more blanks, and update $pos to the position of next ']' if (($pos = api_strpos($temp, ']')) === false) { // adds the end of the text $answer .= $temp; break; } if ($from_database) { $queryfill = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . " WHERE exe_id = " . $exeId . " AND question_id= " . Database::escape_string($questionId); $resfill = Database::query($queryfill); if (Database::num_rows($resfill)) { $str = Database::result($resfill, 0, 'answer'); api_preg_match_all('#\\[([^[]*)\\]#', $str, $arr); $str = str_replace('\\r\\n', '', $str); $choice = $arr[1]; $tmp = api_strrpos($choice[$j], ' / '); $choice[$j] = api_substr($choice[$j], 0, $tmp); $choice[$j] = trim($choice[$j]); //Needed to let characters ' and " to work as part of an answer $choice[$j] = stripslashes($choice[$j]); } } else { $choice[$j] = trim($choice[$j]); } //No idea why we api_strtolower user reponses //$user_tags[] = api_strtolower($choice[$j]); $user_tags[] = $choice[$j]; //put the contents of the [] answer tag into correct_tags[] //$correct_tags[] = api_strtolower(api_substr($temp, 0, $pos)); $correct_tags[] = api_substr($temp, 0, $pos); $j++; $temp = api_substr($temp, $pos + 1); } $answer = ''; $real_correct_tags = $correct_tags; $chosen_list = array(); for ($i = 0; $i < count($real_correct_tags); $i++) { if ($i == 0) { $answer .= $real_text[0]; } if (!$switchable_answer_set) { //needed to parse ' and " characters $user_tags[$i] = stripslashes($user_tags[$i]); if ($correct_tags[$i] == $user_tags[$i]) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $correct_tags[$i]; } elseif (!empty($user_tags[$i])) { // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ' '; } } else { // switchable fill in the blanks if (in_array($user_tags[$i], $correct_tags)) { $chosen_list[] = $user_tags[$i]; $correct_tags = array_diff($correct_tags, $chosen_list); // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $user_tags[$i]; } elseif (!empty($user_tags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ' '; } } // adds the correct word, followed by ] to close the blank $answer .= ' / <font color="green"><b>' . $real_correct_tags[$i] . '</b></font>]'; if (isset($real_text[$i + 1])) { $answer .= $real_text[$i + 1]; } } break; // for free answer // for free answer case FREE_ANSWER: if ($from_database) { $query = "SELECT answer, marks FROM " . $TBL_TRACK_ATTEMPT . " WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resq = Database::query($query); $questionScore = 0; $choice = null; if ($resq) { $row = Database::fetch_array($resq); $choice = $row['answer']; $questionScore = $row['marks']; $choice = str_replace('\\r\\n', '', $choice); $choice = stripslashes($choice); } if ($questionScore == -1) { $totalScore += 0; } else { $totalScore += $questionScore; } if ($questionScore == '') { $questionScore = 0; } $arrques = $questionName; $arrans = $choice; } else { $studentChoice = $choice; if ($studentChoice) { //Fixing negative puntation see #2193 $questionScore = 0; $totalScore += 0; } } break; case ORAL_EXPRESSION: if ($from_database) { $query = "SELECT answer, marks FROM " . $TBL_TRACK_ATTEMPT . " WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resq = Database::query($query); $choice = Database::result($resq, 0, 'answer'); $choice = str_replace('\\r\\n', '', $choice); $choice = stripslashes($choice); $questionScore = Database::result($resq, 0, "marks"); if ($questionScore == -1) { $totalScore += 0; } else { $totalScore += $questionScore; } $arrques = $questionName; $arrans = $choice; } else { $studentChoice = $choice; if ($studentChoice) { //Fixing negative puntation see #2193 $questionScore = 0; $totalScore += 0; } } break; // for matching // for matching case DRAGGABLE: case MATCHING: if ($from_database) { $sql_answer = 'SELECT iid, answer FROM ' . $table_ans . ' WHERE c_id = ' . $course_id . ' AND question_id="' . $questionId . '" AND correct=0'; $res_answer = Database::query($sql_answer); // getting the real answer $real_list = array(); while ($real_answer = Database::fetch_array($res_answer)) { $real_list[$real_answer['iid']] = $real_answer['answer']; } $sql_select_answer = "SELECT iid, answer, correct FROM {$table_ans}\n WHERE c_id = {$course_id} AND question_id = '{$questionId}' AND correct <> 0\n ORDER BY iid"; $res_answers = Database::query($sql_select_answer); $questionScore = 0; while ($a_answers = Database::fetch_array($res_answers)) { $i_answer_id = $a_answers['iid']; //3 $s_answer_label = $a_answers['answer']; // your daddy - your mother $i_answer_correct_answer = $a_answers['correct']; //1 - 2 $answerIdCorrect = $a_answers['correct']; $sql_user_answer = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE exe_id = '{$exeId}' AND\n question_id = '{$questionId}' AND\n position = '{$i_answer_id}'"; $res_user_answer = Database::query($sql_user_answer); if (Database::num_rows($res_user_answer)) { // Rich - good looking $result = Database::fetch_array($res_user_answer, 'ASSOC'); $s_user_answer = $result['answer']; } else { $s_user_answer = 0; } $i_answerWeighting = $objAnswerTmp->selectWeighting($i_answer_id); if ($answerType == MATCHING) { $i_answer_correct_answer = $objAnswerTmp->getAnswerIdFromList($i_answer_correct_answer); } $user_answer = ''; if (!empty($s_user_answer)) { if ($s_user_answer == $i_answer_correct_answer) { $questionScore += $i_answerWeighting; $totalScore += $i_answerWeighting; if ($answerType == DRAGGABLE) { $user_answer = Display::label(get_lang('Correct'), 'success'); } else { $user_answer = '<span>' . $real_list[$answerIdCorrect] . '</span>'; } } else { if ($answerType == DRAGGABLE) { $user_answer = Display::label(get_lang('NotCorrect'), 'important'); } else { $user_answer = '<span style="color: #FF0000; text-decoration: line-through;">' . $real_list[$s_user_answer] . '</span>'; } } } else { if ($answerType == DRAGGABLE) { $user_answer = Display::label(get_lang('Incorrect'), 'important'); } } if ($show_result) { echo '<tr>'; echo '<td>' . $s_answer_label . '</td>'; echo '<td>' . $user_answer . ''; if ($answerType == MATCHING) { echo '<b><span style="color: #008000;"> ' . $real_list[$answerIdCorrect] . '</span></b>'; } echo '</td>'; echo '</tr>'; } } break 2; //break the switch and the "for" condition } else { $numAnswer = $answerId; if ($answerCorrect) { $matchingKey = $choice[$numAnswer]; if ($answerType == DRAGGABLE) { $matchingKey = $numAnswer; } if ($answerType == MATCHING) { $answerCorrect = $objAnswerTmp->getAnswerIdFromList($answerCorrect); $matchingKey = $numAnswer; } if ($answerCorrect == $choice[$numAnswer]) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $user_answer = '<span>' . $answer_matching[$matchingKey] . '</span>'; } else { if ($choice[$numAnswer]) { $user_answer = '<span style="color: #FF0000; text-decoration: line-through;">' . $answer_matching[$matchingKey] . '</span>'; } } $matching[$numAnswer] = $choice[$numAnswer]; } break; } // for hotspot with no order // for hotspot with no order case HOT_SPOT: if ($from_database) { if ($show_result) { $TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); $query = "SELECT hotspot_correct\n FROM " . $TBL_TRACK_HOTSPOT . "\n WHERE hotspot_exe_id = '" . $exeId . "' and\n hotspot_question_id= '" . $questionId . "' AND\n hotspot_answer_id='" . Database::escape_string($answerId) . "'"; $resq = Database::query($query); $studentChoice = Database::result($resq, 0, "hotspot_correct"); if ($studentChoice == 1) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } } else { if (isset($choice[$answerId])) { $studentChoice = $choice[$answerId]; } else { $studentChoice = false; } if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } break; // @todo never added to chamilo //for hotspot with fixed order // @todo never added to chamilo //for hotspot with fixed order case HOT_SPOT_ORDER: $studentChoice = $choice['order'][$answerId]; if ($studentChoice == $answerId) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $studentChoice = true; } else { $studentChoice = false; } break; // for hotspot with delineation // for hotspot with delineation case HOT_SPOT_DELINEATION: if ($from_database) { // getting the user answer $TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); $query = "SELECT hotspot_correct, hotspot_coordinate\n FROM " . $TBL_TRACK_HOTSPOT . "\n WHERE hotspot_exe_id = '" . $exeId . "' AND\n hotspot_question_id= '" . $questionId . "' AND\n hotspot_answer_id='1'"; //by default we take 1 because it's a delineation $resq = Database::query($query); $row = Database::fetch_array($resq, 'ASSOC'); $choice = $row['hotspot_correct']; $user_answer = $row['hotspot_coordinate']; // THIS is very important otherwise the poly_compile will throw an error!! // round-up the coordinates $coords = explode('/', $user_answer); $user_array = ''; foreach ($coords as $coord) { list($x, $y) = explode(';', $coord); $user_array .= round($x) . ';' . round($y) . '/'; } $user_array = substr($user_array, 0, -1); } else { if ($studentChoice) { $newquestionList[] = $questionId; } if ($answerId === 1) { $studentChoice = $choice[$answerId]; $questionScore += $answerWeighting; if ($hotspot_delineation_result[1] == 1) { $totalScore += $answerWeighting; //adding the total } } } $_SESSION['hotspot_coord'][1] = $delineation_cord; $_SESSION['hotspot_dest'][1] = $answer_delineation_destination; break; } // end switch Answertype global $origin; if ($show_result) { if ($debug) { error_log('show result ' . $show_result); } if ($from == 'exercise_result') { if ($debug) { error_log('Showing questions $from ' . $from); } //display answers (if not matching type, or if the answer is correct) if (!in_array($answerType, array(DRAGGABLE, MATCHING)) || $answerCorrect) { if (in_array($answerType, array(UNIQUE_ANSWER, UNIQUE_ANSWER_IMAGE, UNIQUE_ANSWER_NO_OPTION, MULTIPLE_ANSWER, MULTIPLE_ANSWER_COMBINATION, GLOBAL_MULTIPLE_ANSWER))) { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, 0, 0); } elseif ($answerType == MULTIPLE_ANSWER_TRUE_FALSE) { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, $questionId, 0); } elseif ($answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, 0, 0); } elseif ($answerType == FILL_IN_BLANKS) { ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer, 0, 0); } elseif ($answerType == FREE_ANSWER) { ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore); } elseif ($answerType == ORAL_EXPRESSION) { // to store the details of open questions in an array to be used in mail ExerciseShowFunctions::display_oral_expression_answer($choice, 0, 0, $nano); } elseif ($answerType == HOT_SPOT) { ExerciseShowFunctions::display_hotspot_answer($feedback_type, $counter, $answer, $studentChoice, $answerComment); } elseif ($answerType == HOT_SPOT_ORDER) { ExerciseShowFunctions::display_hotspot_order_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment); } elseif ($answerType == HOT_SPOT_DELINEATION) { $user_answer = $_SESSION['exerciseResultCoordinates'][$questionId]; // Round-up the coordinates $coords = explode('/', $user_answer); $user_array = ''; foreach ($coords as $coord) { list($x, $y) = explode(';', $coord); $user_array .= round($x) . ';' . round($y) . '/'; } $user_array = substr($user_array, 0, -1); if ($next) { $user_answer = $user_array; // we compare only the delineation not the other points $answer_question = $_SESSION['hotspot_coord'][1]; $answerDestination = $_SESSION['hotspot_dest'][1]; //calculating the area $poly_user = convert_coordinates($user_answer, '/'); $poly_answer = convert_coordinates($answer_question, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_user_compiled = poly_compile($poly_user, $max_coord); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $poly_results = poly_result($poly_answer_compiled, $poly_user_compiled, $max_coord); $overlap = $poly_results['both']; $poly_answer_area = $poly_results['s1']; $poly_user_area = $poly_results['s2']; $missing = $poly_results['s1Only']; $excess = $poly_results['s2Only']; //$overlap = round(polygons_overlap($poly_answer,$poly_user)); //this is an area in pixels if ($debug > 0) { error_log(__LINE__ . ' - Polygons results are ' . print_r($poly_results, 1), 0); } if ($overlap < 1) { //shortcut to avoid complicated calculations $final_overlap = 0; $final_missing = 100; $final_excess = 100; } else { // the final overlap is the percentage of the initial polygon that is overlapped by the user's polygon $final_overlap = round((double) $overlap / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final overlap is ' . $final_overlap, 0); } // the final missing area is the percentage of the initial polygon that is not overlapped by the user's polygon $final_missing = 100 - $final_overlap; if ($debug > 1) { error_log(__LINE__ . ' - Final missing is ' . $final_missing, 0); } // the final excess area is the percentage of the initial polygon's size that is covered by the user's polygon outside of the initial polygon $final_excess = round(((double) $poly_user_area - (double) $overlap) / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final excess is ' . $final_excess, 0); } } //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); $threadhold_total = $destination_items[0]; $threadhold_items = explode(';', $threadhold_total); $threadhold1 = $threadhold_items[0]; // overlap $threadhold2 = $threadhold_items[1]; // excess $threadhold3 = $threadhold_items[2]; //missing // if is delineation if ($answerId === 1) { //setting colors if ($final_overlap >= $threadhold1) { $overlap_color = true; //echo 'a'; } //echo $excess.'-'.$threadhold2; if ($final_excess <= $threadhold2) { $excess_color = true; //echo 'b'; } //echo '--------'.$missing.'-'.$threadhold3; if ($final_missing <= $threadhold3) { $missing_color = true; //echo 'c'; } // if pass if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) { $next = 1; //go to the oars $result_comment = get_lang('Acceptable'); $final_answer = 1; // do not update with update_exercise_attempt } else { $next = 0; $result_comment = get_lang('Unacceptable'); $comment = $answerDestination = $objAnswerTmp->selectComment(1); $answerDestination = $objAnswerTmp->selectDestination(1); //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); } } elseif ($answerId > 1) { if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') { if ($debug > 0) { error_log(__LINE__ . ' - answerId is of type noerror', 0); } //type no error shouldn't be treated $next = 1; continue; } if ($debug > 0) { error_log(__LINE__ . ' - answerId is >1 so we\'re probably in OAR', 0); } //check the intersection between the oar and the user //echo 'user'; print_r($x_user_list); print_r($y_user_list); //echo 'official';print_r($x_list);print_r($y_list); //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list); $inter = $result['success']; //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId); $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); $poly_answer = convert_coordinates($delineation_cord, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $overlap = poly_touch($poly_user_compiled, $poly_answer_compiled, $max_coord); if ($overlap == false) { //all good, no overlap $next = 1; continue; } else { if ($debug > 0) { error_log(__LINE__ . ' - Overlap is ' . $overlap . ': OAR hit', 0); } $organs_at_risk_hit++; //show the feedback $next = 0; $comment = $answerDestination = $objAnswerTmp->selectComment($answerId); $answerDestination = $objAnswerTmp->selectDestination($answerId); $destination_items = explode('@@', $answerDestination); $try_hotspot = $destination_items[1]; $lp_hotspot = $destination_items[2]; $select_question_hotspot = $destination_items[3]; $url_hotspot = $destination_items[4]; } } } else { // the first delineation feedback if ($debug > 0) { error_log(__LINE__ . ' first', 0); } } } elseif ($answerType == MATCHING) { //if ($origin != 'learnpath') { echo '<tr>'; echo '<td>' . $answer_matching[$answerId] . '</td><td>' . $user_answer . ' / <b><span style="color: #008000;">' . $answer_matching[$answerCorrect] . '</span></b></td>'; echo '</tr>'; //} } } } else { if ($debug) { error_log('Showing questions $from ' . $from); } switch ($answerType) { case UNIQUE_ANSWER: case UNIQUE_ANSWER_IMAGE: case UNIQUE_ANSWER_NO_OPTION: case MULTIPLE_ANSWER: case GLOBAL_MULTIPLE_ANSWER: case MULTIPLE_ANSWER_COMBINATION: if ($answerId == 1) { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId); } else { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, ""); } break; case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: if ($answerId == 1) { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId); } else { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, ""); } break; case MULTIPLE_ANSWER_TRUE_FALSE: if ($answerId == 1) { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId); } else { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, ""); } break; case FILL_IN_BLANKS: ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer, $exeId, $questionId); break; case FREE_ANSWER: echo ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore); break; case ORAL_EXPRESSION: echo '<tr> <td valign="top">' . ExerciseShowFunctions::display_oral_expression_answer($feedback_type, $choice, $exeId, $questionId, $nano) . '</td> </tr> </table>'; break; case HOT_SPOT: ExerciseShowFunctions::display_hotspot_answer($feedback_type, $counter, $answer, $studentChoice, $answerComment); break; case HOT_SPOT_DELINEATION: $user_answer = $user_array; if ($next) { $user_answer = $user_array; // we compare only the delineation not the other points $answer_question = $_SESSION['hotspot_coord'][1]; $answerDestination = $_SESSION['hotspot_dest'][1]; //calculating the area $poly_user = convert_coordinates($user_answer, '/'); $poly_answer = convert_coordinates($answer_question, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_user_compiled = poly_compile($poly_user, $max_coord); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $poly_results = poly_result($poly_answer_compiled, $poly_user_compiled, $max_coord); $overlap = $poly_results['both']; $poly_answer_area = $poly_results['s1']; $poly_user_area = $poly_results['s2']; $missing = $poly_results['s1Only']; $excess = $poly_results['s2Only']; //$overlap = round(polygons_overlap($poly_answer,$poly_user)); //this is an area in pixels if ($debug > 0) { error_log(__LINE__ . ' - Polygons results are ' . print_r($poly_results, 1), 0); } if ($overlap < 1) { //shortcut to avoid complicated calculations $final_overlap = 0; $final_missing = 100; $final_excess = 100; } else { // the final overlap is the percentage of the initial polygon that is overlapped by the user's polygon $final_overlap = round((double) $overlap / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final overlap is ' . $final_overlap, 0); } // the final missing area is the percentage of the initial polygon that is not overlapped by the user's polygon $final_missing = 100 - $final_overlap; if ($debug > 1) { error_log(__LINE__ . ' - Final missing is ' . $final_missing, 0); } // the final excess area is the percentage of the initial polygon's size that is covered by the user's polygon outside of the initial polygon $final_excess = round(((double) $poly_user_area - (double) $overlap) / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final excess is ' . $final_excess, 0); } } //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); $threadhold_total = $destination_items[0]; $threadhold_items = explode(';', $threadhold_total); $threadhold1 = $threadhold_items[0]; // overlap $threadhold2 = $threadhold_items[1]; // excess $threadhold3 = $threadhold_items[2]; //missing // if is delineation if ($answerId === 1) { //setting colors if ($final_overlap >= $threadhold1) { $overlap_color = true; //echo 'a'; } //echo $excess.'-'.$threadhold2; if ($final_excess <= $threadhold2) { $excess_color = true; //echo 'b'; } //echo '--------'.$missing.'-'.$threadhold3; if ($final_missing <= $threadhold3) { $missing_color = true; //echo 'c'; } // if pass if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) { $next = 1; //go to the oars $result_comment = get_lang('Acceptable'); $final_answer = 1; // do not update with update_exercise_attempt } else { $next = 0; $result_comment = get_lang('Unacceptable'); $comment = $answerDestination = $objAnswerTmp->selectComment(1); $answerDestination = $objAnswerTmp->selectDestination(1); //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); } } elseif ($answerId > 1) { if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') { if ($debug > 0) { error_log(__LINE__ . ' - answerId is of type noerror', 0); } //type no error shouldn't be treated $next = 1; continue; } if ($debug > 0) { error_log(__LINE__ . ' - answerId is >1 so we\'re probably in OAR', 0); } //check the intersection between the oar and the user //echo 'user'; print_r($x_user_list); print_r($y_user_list); //echo 'official';print_r($x_list);print_r($y_list); //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list); $inter = $result['success']; //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId); $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); $poly_answer = convert_coordinates($delineation_cord, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $overlap = poly_touch($poly_user_compiled, $poly_answer_compiled, $max_coord); if ($overlap == false) { //all good, no overlap $next = 1; continue; } else { if ($debug > 0) { error_log(__LINE__ . ' - Overlap is ' . $overlap . ': OAR hit', 0); } $organs_at_risk_hit++; //show the feedback $next = 0; $comment = $answerDestination = $objAnswerTmp->selectComment($answerId); $answerDestination = $objAnswerTmp->selectDestination($answerId); $destination_items = explode('@@', $answerDestination); $try_hotspot = $destination_items[1]; $lp_hotspot = $destination_items[2]; $select_question_hotspot = $destination_items[3]; $url_hotspot = $destination_items[4]; } } } else { // the first delineation feedback if ($debug > 0) { error_log(__LINE__ . ' first', 0); } } break; case HOT_SPOT_ORDER: ExerciseShowFunctions::display_hotspot_order_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment); break; case DRAGGABLE: case MATCHING: //if ($origin != 'learnpath') { echo '<tr>'; echo '<td>' . $answer_matching[$answerId] . '</td><td>' . $user_answer . ' / <b><span style="color: #008000;">' . $answer_matching[$answerCorrect] . '</span></b></td>'; echo '</tr>'; //} break; } } } $counter++; } // end for that loops over all answers of the current question if ($debug) { error_log('<-- end answer loop -->'); } $final_answer = true; foreach ($real_answers as $my_answer) { if (!$my_answer) { $final_answer = false; } } //we add the total score after dealing with the answers if ($answerType == MULTIPLE_ANSWER_COMBINATION || $answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { if ($final_answer) { //getting only the first score where we save the weight of all the question $answerWeighting = $objAnswerTmp->selectWeighting($objAnswerTmp->getRealAnswerIdFromList(1)); $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } //Fixes multiple answer question in order to be exact if ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { $diff = @array_diff($answer_correct_array, $real_answers); /* * All good answers or nothing works like exact $counter = 1; $correct_answer = true; foreach ($real_answers as $my_answer) { if ($debug) error_log(" my_answer: $my_answer answer_correct_array[counter]: ".$answer_correct_array[$counter]); if ($my_answer != $answer_correct_array[$counter]) { $correct_answer = false; break; } $counter++; } */ if ($debug) { error_log("answer_correct_array: " . print_r($answer_correct_array, 1) . ""); error_log("real_answers: " . print_r($real_answers, 1) . ""); } // This makes the result non exact if (!empty($diff)) { //$questionScore = 0; } } $extra_data = array('final_overlap' => $final_overlap, 'final_missing' => $final_missing, 'final_excess' => $final_excess, 'overlap_color' => $overlap_color, 'missing_color' => $missing_color, 'excess_color' => $excess_color, 'threadhold1' => $threadhold1, 'threadhold2' => $threadhold2, 'threadhold3' => $threadhold3); if ($from == 'exercise_result') { // if answer is hotspot. To the difference of exercise_show.php, we use the results from the session (from_db=0) // TODO Change this, because it is wrong to show the user some results that haven't been stored in the database yet if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER || $answerType == HOT_SPOT_DELINEATION) { if ($debug) { error_log('$from AND this is a hotspot kind of question '); } $my_exe_id = 0; $from_database = 0; if ($answerType == HOT_SPOT_DELINEATION) { if (0) { if ($overlap_color) { $overlap_color = 'green'; } else { $overlap_color = 'red'; } if ($missing_color) { $missing_color = 'green'; } else { $missing_color = 'red'; } if ($excess_color) { $excess_color = 'green'; } else { $excess_color = 'red'; } if (!is_numeric($final_overlap)) { $final_overlap = 0; } if (!is_numeric($final_missing)) { $final_missing = 0; } if (!is_numeric($final_excess)) { $final_excess = 0; } if ($final_overlap > 100) { $final_overlap = 100; } $table_resume = '<table class="data_table"> <tr class="row_odd" > <td></td> <td ><b>' . get_lang('Requirements') . '</b></td> <td><b>' . get_lang('YourAnswer') . '</b></td> </tr> <tr class="row_even"> <td><b>' . get_lang('Overlap') . '</b></td> <td>' . get_lang('Min') . ' ' . $threadhold1 . '</td> <td><div style="color:' . $overlap_color . '">' . ($final_overlap < 0 ? 0 : intval($final_overlap)) . '</div></td> </tr> <tr> <td><b>' . get_lang('Excess') . '</b></td> <td>' . get_lang('Max') . ' ' . $threadhold2 . '</td> <td><div style="color:' . $excess_color . '">' . ($final_excess < 0 ? 0 : intval($final_excess)) . '</div></td> </tr> <tr class="row_even"> <td><b>' . get_lang('Missing') . '</b></td> <td>' . get_lang('Max') . ' ' . $threadhold3 . '</td> <td><div style="color:' . $missing_color . '">' . ($final_missing < 0 ? 0 : intval($final_missing)) . '</div></td> </tr> </table>'; if ($next == 0) { $try = $try_hotspot; $lp = $lp_hotspot; $destinationid = $select_question_hotspot; $url = $url_hotspot; } else { //show if no error //echo 'no error'; $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers); $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers); } echo '<h1><div style="color:#333;">' . get_lang('Feedback') . '</div></h1> <p style="text-align:center">'; $message = '<p>' . get_lang('YourDelineation') . '</p>'; $message .= $table_resume; $message .= '<br />' . get_lang('ResultIs') . ' ' . $result_comment . '<br />'; if ($organs_at_risk_hit > 0) { $message .= '<p><b>' . get_lang('OARHit') . '</b></p>'; } $message .= '<p>' . $comment . '</p>'; echo $message; } else { echo $hotspot_delineation_result[0]; //prints message $from_database = 1; // the hotspot_solution.swf needs this variable } //save the score attempts if (1) { $final_answer = $hotspot_delineation_result[1]; //getting the answer 1 or 0 comes from exercise_submit_modal.php if ($final_answer == 0) { $questionScore = 0; } saveQuestionAttempt($questionScore, 1, $quesId, $exeId, 0, null, $updateResults); // we always insert the answer_id 1 = delineation //in delineation mode, get the answer from $hotspot_delineation_result[1] saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList(1), $hotspot_delineation_result[1], $exerciseResultCoordinates[$quesId], $updateResults); } else { if ($final_answer == 0) { $questionScore = 0; $answer = 0; saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, null, $updateResults); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList($idx), 0, $val, $updateResults); } } } else { saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, null, $updateResults); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList($idx), $choice[$idx], $val, $updateResults); } } } } $my_exe_id = $exeId; } } if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER) { // We made an extra table for the answers if ($show_result) { //if ($origin != 'learnpath') { echo '</table></td></tr>'; echo '<tr> <td colspan="2">'; echo '<i>' . get_lang('HotSpot') . '</i><br /><br />'; echo '<object type="application/x-shockwave-flash" data="' . api_get_path(WEB_CODE_PATH) . 'plugin/hotspot/hotspot_solution.swf?modifyAnswers=' . Security::remove_XSS($questionId) . '&exe_id=' . $exeId . '&from_db=1" width="552" height="352"> <param name="movie" value="../plugin/hotspot/hotspot_solution.swf?modifyAnswers=' . Security::remove_XSS($questionId) . '&exe_id=' . $exeId . '&from_db=1" /> </object>'; echo '</td> </tr>'; //} } } if ($origin != 'learnpath') { if ($show_result) { echo '</table>'; } } } $totalWeighting += $questionWeighting; // Store results directly in the database // For all in one page exercises, the results will be // stored by exercise_results.php (using the session) if ($saved_results) { if ($debug) { error_log("Save question results: {$saved_results}"); error_log(print_r($choice, 1)); } if (empty($choice)) { $choice = 0; } if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE || $answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { if ($choice != 0) { $reply = array_keys($choice); for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; saveQuestionAttempt($questionScore, $ans . ':' . $choice[$ans], $quesId, $exeId, $i, $this->id, $updateResults); if ($debug) { error_log('result =>' . $questionScore . ' ' . $ans . ':' . $choice[$ans]); } } } else { saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id, $updateResults); } } elseif ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { if ($choice != 0) { $reply = array_keys($choice); if ($debug) { error_log("reply " . print_r($reply, 1) . ""); } for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; saveQuestionAttempt($questionScore, $ans, $quesId, $exeId, $i, $this->id, $updateResults); } } else { saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id, $updateResults); } } elseif ($answerType == MULTIPLE_ANSWER_COMBINATION) { if ($choice != 0) { $reply = array_keys($choice); for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; saveQuestionAttempt($questionScore, $ans, $quesId, $exeId, $i, $this->id, $updateResults); } } else { saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id, $updateResults); } } elseif ($answerType == MATCHING || $answerType == DRAGGABLE) { if (isset($matching)) { foreach ($matching as $j => $val) { saveQuestionAttempt($questionScore, $val, $quesId, $exeId, $j, $this->id, $updateResults); } } } elseif ($answerType == FREE_ANSWER) { $answer = $choice; saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $updateResults); } elseif ($answerType == ORAL_EXPRESSION) { $answer = $choice; saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $updateResults, $nano); } elseif ($answerType == UNIQUE_ANSWER || $answerType == UNIQUE_ANSWER_IMAGE || $answerType == UNIQUE_ANSWER_NO_OPTION) { $answer = $choice; saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $updateResults); // } elseif ($answerType == HOT_SPOT || $answerType == HOT_SPOT_DELINEATION) { } elseif ($answerType == HOT_SPOT) { saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $updateResults); if (isset($exerciseResultCoordinates[$questionId]) && !empty($exerciseResultCoordinates[$questionId])) { foreach ($exerciseResultCoordinates[$questionId] as $idx => $val) { saveExerciseAttemptHotspot($exeId, $quesId, $objAnswerTmp->getRealAnswerIdFromList($idx), $choice[$idx], $val, $updateResults, $this->id); } } } else { saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $updateResults); } } if ($propagate_neg == 0 && $questionScore < 0) { $questionScore = 0; } if ($saved_results) { $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCICES); $sql_update = 'UPDATE ' . $stat_table . ' SET exe_result = exe_result + ' . floatval($questionScore) . ' WHERE exe_id = ' . $exeId; if ($debug) { error_log($sql_update); } Database::query($sql_update); } $return_array = array('score' => $questionScore, 'weight' => $questionWeighting, 'extra' => $extra_data, 'open_question' => $arrques, 'open_answer' => $arrans, 'answer_type' => $answerType, 'user_choices' => $choice); return $return_array; }
function xmd_html_value($xmPath, $parent = 0, $fun = 'htmlspecialchars') { if (!is_string($xmPath)) { return ''; } $fix = array(); if (($p = api_strpos($xmPath, ' -% ')) !== FALSE) { $fix['pre'] = api_substr($xmPath, 0, $p); $xmPath = api_substr($xmPath, $p + 4); } if (($p = api_strpos($xmPath, ' %- ')) !== FALSE) { $fix['post'] = api_substr($xmPath, $p + 4); $xmPath = api_substr($xmPath, 0, $p); } if (($p = api_strpos($xmPath, ' ')) !== FALSE) { $fix['in'] = api_substr($xmPath, $p + 1); $xmPath = api_substr($xmPath, 0, $p); } return $this->xmd_value($xmPath, $parent, $fix, $fun); }
/** * @param string $file * @param bool $updatesession options: * true: if the session exists it will be updated * false: if session exists a new session will be created adding a counter session1, session2, etc * @param int $user_id * @param $logger * @param array convert a file row to an extra field. Example in CSV file there's a SessionID then it will * converted to extra_external_session_id if you set this: array('SessionId' => 'extra_external_session_id') * @param array extra fields * @param string extra field id * @param int $daysCoachAccessBeforeBeginning * @param int $daysCoachAccessAfterBeginning * @param int $sessionVisibility * @return array */ static function importCSV($file, $updatesession, $defaultUserId = null, $logger = null, $extraFields = array(), $extraFieldId = null, $daysCoachAccessBeforeBeginning = null, $daysCoachAccessAfterBeginning = null, $sessionVisibility = 1, $fieldsToAvoidUpdate = array()) { $content = file($file); $error_message = null; $session_counter = 0; if (empty($defaultUserId)) { $defaultUserId = api_get_user_id(); } $eol = PHP_EOL; if (PHP_SAPI != 'cli') { $eol = '<br />'; } $debug = false; if (isset($logger)) { $debug = true; } $extraParameters = null; if (!empty($daysCoachAccessBeforeBeginning) && !empty($daysCoachAccessAfterBeginning)) { $extraParameters .= ' , nb_days_access_before_beginning = ' . intval($daysCoachAccessBeforeBeginning); $extraParameters .= ' , nb_days_access_after_end = ' . intval($daysCoachAccessAfterBeginning); } $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER); $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); $sessions = array(); if (!api_strstr($content[0], ';')) { $error_message = get_lang('NotCSV'); } else { $tag_names = array(); foreach ($content as $key => $enreg) { $enreg = explode(';', trim($enreg)); if ($key) { foreach ($tag_names as $tag_key => $tag_name) { $sessions[$key - 1][$tag_name] = $enreg[$tag_key]; } } else { foreach ($enreg as $tag_name) { $tag_names[] = api_preg_replace('/[^a-zA-Z0-9_\\-]/', '', $tag_name); } if (!in_array('SessionName', $tag_names) || !in_array('DateStart', $tag_names) || !in_array('DateEnd', $tag_names)) { $error_message = get_lang('NoNeededData'); break; } } } // Looping the sessions. foreach ($sessions as $enreg) { $user_counter = 0; $course_counter = 0; if (isset($extraFields) && !empty($extraFields)) { foreach ($extraFields as $original => $to) { $enreg[$to] = $enreg[$original]; } } $session_name = Database::escape_string($enreg['SessionName']); $date_start = $enreg['DateStart']; $date_end = $enreg['DateEnd']; $visibility = isset($enreg['Visibility']) ? $enreg['Visibility'] : $sessionVisibility; $session_category_id = isset($enreg['SessionCategory']) ? $enreg['SessionCategory'] : null; // Searching a general coach. if (!empty($enreg['Coach'])) { $coach_id = UserManager::get_user_id_from_username($enreg['Coach']); if ($coach_id === false) { // If the coach-user does not exist - I'm the coach. $coach_id = $defaultUserId; } } else { $coach_id = $defaultUserId; } if (!$updatesession) { // Always create a session. $unique_name = false; // This MUST be initializead. $i = 0; // Change session name, verify that session doesn't exist. $suffix = null; while (!$unique_name) { if ($i > 1) { $suffix = ' - ' . $i; } $sql = 'SELECT 1 FROM ' . $tbl_session . ' WHERE name="' . $session_name . $suffix . '"'; $rs = Database::query($sql); if (Database::result($rs, 0, 0)) { $i++; } else { $unique_name = true; $session_name .= $suffix; } } // Creating the session. /*$sql_session = "INSERT IGNORE INTO $tbl_session SET name = '".$session_name."', id_coach = '$coach_id', date_start = '$date_start', date_end = '$date_end', visibility = '$visibility', session_category_id = '$session_category_id', session_admin_id=".intval($defaultUserId).$extraParameters; Database::query($sql_session);*/ $params = array('id_coach' => $coach_id, 'visibility' => $visibility, 'name' => $session_name, 'access_start_date' => $date_start, 'access_end_date' => $date_end, 'session_category_id' => $session_category_id, 'session_admin_id' => $defaultUserId); $session_id = SessionManager::add($params); if ($debug) { if ($session_id) { foreach ($enreg as $key => $value) { if (substr($key, 0, 6) == 'extra_') { //an extra field self::update_session_extra_field_value($session_id, substr($key, 6), $value); } } $logger->addInfo("Sessions - Session created: #{$session_id} - {$session_name}"); } else { $logger->addError("Sessions - Session NOT created: {$session_name}"); } } $session_counter++; } else { $sessionId = null; if (isset($extraFields) && !empty($extraFields)) { $sessionId = self::get_session_id_from_original_id($enreg['extra_' . $extraFieldId], $extraFieldId); if (empty($sessionId)) { $my_session_result = false; } else { $my_session_result = true; } } else { $my_session_result = self::get_session_by_name($enreg['SessionName']); } if ($my_session_result === false) { // Creating a session. /*$sql_session = "INSERT IGNORE INTO $tbl_session SET name = '$session_name', id_coach = '$coach_id', date_start = '$date_start', date_end = '$date_end', visibility = '$visibility', session_category_id = '$session_category_id' ".$extraParameters;*/ $params = array('id_coach' => $coach_id, 'visibility' => $visibility, 'name' => $session_name, 'access_start_date' => $date_start, 'access_end_date' => $date_end, 'session_category_id' => $session_category_id, 'session_admin_id' => $defaultUserId); $session_id = SessionManager::add($params); // We get the last insert id. /*$my_session_result = SessionManager::get_session_by_name($enreg['SessionName']); $session_id = $my_session_result['id'];*/ if ($debug) { if ($session_id) { foreach ($enreg as $key => $value) { if (substr($key, 0, 6) == 'extra_') { //an extra field self::update_session_extra_field_value($session_id, substr($key, 6), $value); } } $logger->addInfo("Sessions - #{$session_id} created: {$session_name}"); } else { $logger->addError("Sessions - Session NOT created: {$session_name}"); } } } else { $params = array('id_coach' => $coach_id, 'date_start' => $date_start, 'date_end' => $date_end, 'visibility' => $visibility, 'session_category_id' => $session_category_id); if (!empty($fieldsToAvoidUpdate)) { foreach ($fieldsToAvoidUpdate as $field) { unset($params[$field]); } } if (isset($sessionId) && !empty($sessionId)) { // The session already exists, update it then. Database::update($tbl_session, $params, array('id = ?' => $sessionId)); $session_id = $sessionId; } else { Database::update($tbl_session, $params, array("name = '?' " => $enreg['SessionName'])); $row = Database::query("SELECT id FROM {$tbl_session} WHERE name = '{$session_name}'"); list($session_id) = Database::fetch_array($row); } foreach ($enreg as $key => $value) { if (substr($key, 0, 6) == 'extra_') { //an extra field self::update_session_extra_field_value($session_id, substr($key, 6), $value); } } Database::query("DELETE FROM {$tbl_session_user} WHERE id_session='{$session_id}'"); Database::query("DELETE FROM {$tbl_session_course} WHERE id_session='{$session_id}'"); Database::query("DELETE FROM {$tbl_session_course_user} WHERE id_session='{$session_id}'"); } $session_counter++; } $users = explode('|', $enreg['Users']); // Adding the relationship "Session - User". if (is_array($users)) { foreach ($users as $user) { $user_id = UserManager::get_user_id_from_username($user); if ($user_id !== false) { // Insert new users. $sql = "INSERT IGNORE INTO {$tbl_session_user} SET\n id_user = '******',\n id_session = '{$session_id}'"; Database::query($sql); if ($debug) { $logger->addInfo("Sessions - Adding User #{$user_id} ({$user}) to session #{$session_id}"); } $user_counter++; } } } $courses = explode('|', $enreg['Courses']); foreach ($courses as $course) { $course_code = api_strtoupper(api_substr($course, 0, api_strpos($course, '['))); if (CourseManager::course_exists($course_code)) { $courseInfo = api_get_course_info($course_code); $courseId = $courseInfo['real_id']; // Adding the course to a session. $sql_course = "INSERT IGNORE INTO {$tbl_session_course}\n SET c_id = '" . $courseId . "', id_session = '{$session_id}'"; Database::query($sql_course); if ($debug) { $logger->addInfo("Sessions - Adding course '{$course_code}' to session #{$session_id}"); } $course_counter++; $pattern = "/\\[(.*?)\\]/"; preg_match_all($pattern, $course, $matches); if (isset($matches[1])) { $course_coaches = $matches[1][0]; $course_users = $matches[1][1]; } $course_users = explode(',', $course_users); $course_coaches = explode(',', $course_coaches); // Adding coaches to session course user if (!empty($course_coaches)) { foreach ($course_coaches as $course_coach) { $coach_id = UserManager::get_user_id_from_username($course_coach); if ($coach_id !== false) { $sql = "INSERT IGNORE INTO {$tbl_session_course_user} SET\n id_user='******',\n c_id ='{$courseId}',\n id_session = '{$session_id}',\n status = 2 "; Database::query($sql); if ($debug) { $logger->addInfo("Sessions - Adding course coach: user #{$coach_id} ({$course_coach}) to course: '{$course_code}' and session #{$session_id}"); } } else { $error_message .= get_lang('UserDoesNotExist') . ' : ' . $course_coach . $eol; } } } $users_in_course_counter = 0; // Adding the relationship "Session - Course - User". foreach ($course_users as $user) { $user_id = UserManager::get_user_id_from_username($user); if ($user_id !== false) { $sql = "INSERT IGNORE INTO {$tbl_session_course_user} SET\n id_user='******',\n c_id = '{$courseId}',\n id_session = '{$session_id}'"; Database::query($sql); if ($debug) { $logger->addInfo("Sessions - Adding student: user #{$user_id} ({$user}) to course: '{$course_code}' and session #{$session_id}"); } $users_in_course_counter++; } else { $error_message .= get_lang('UserDoesNotExist') . ': ' . $user . $eol; } } $sql = "UPDATE {$tbl_session_course} SET nbr_users='{$users_in_course_counter}' WHERE c_id ='{$courseId}'"; Database::query($sql); $course_info = CourseManager::get_course_information($course_code); $inserted_in_course[$course_code] = $course_info['title']; } } $access_url_id = api_get_current_access_url_id(); UrlManager::add_session_to_url($session_id, $access_url_id); $sql_update_users = "UPDATE {$tbl_session} SET nbr_users ='{$user_counter}', nbr_courses='{$course_counter}' WHERE id='{$session_id}'"; Database::query($sql_update_users); } } return array('error_message' => $error_message, 'session_counter' => $session_counter); }
/** * Split strings on new line */ function str_split_on_new_line($str) { $content = array(); if (api_strpos($str, "\r\n") !== false) { $content = explode("\r\n", $str); } elseif (api_strpos($str, "\n") !== false) { $content = explode("\n", $str); } elseif (api_strpos($str, "\r") !== false) { $content = explode("\r", $str); } else { $content[] = $str; } return $content; }
function xhtdoc($htt_file_contents) { $htt_file_contents = str_replace("\r", "\n", str_replace("\r\n", "\n", $htt_file_contents)); while (api_substr($htt_file_contents, -1) == "\n") { $htt_file_contents = api_substr($htt_file_contents, 0, -1); } $last_line = api_strrchr($htt_file_contents, "\n"); $this->htt_error = ''; if (api_strlen($last_line) < 12 || api_substr($last_line, 0, 6) != "\n<!-- " || api_strlen($last_line) % 2 != 0 || api_substr($last_line, -4) != " -->") { $this->htt_error = 'last line must be of the form <!-- {--} -->'; return; } define('XHT_PL', (int) (api_strlen($last_line) - 10) / 2); // Parentheses Lth define('XHT_LP', api_substr($last_line, 6, XHT_PL)); // Left Par define('XHT_RP', api_substr($last_line, 6 + XHT_PL, XHT_PL)); // Right Par if (XHT_LP == XHT_RP) { $this->htt_error = 'parentheses in last line <!-- {--} --> must not be identical'; return; } $this->htt_array = array(); // named elements are arrays and strings foreach (explode("\n<!-- " . XHT_LP, "\n" . $htt_file_contents) as $name_and_text) { if ($name_length = api_strpos($name_and_text, XHT_RP . " -->\n")) { $template_name = trim(api_substr($name_and_text, 0, $name_length)); if (api_strpos($template_name, ' ') !== FALSE) { give_up('Template ' . $template_name . ' has a space in its name'); } $httext = api_substr($name_and_text, $name_length + XHT_PL + 5); while (api_substr($httext, 0, 1) == "\n") { $httext = api_substr($httext, 1); } while (api_substr($httext, -1) == "\n") { $httext = api_substr($httext, 0, -1); } $this->xht_add_template($template_name, $httext); } } define('XHT_SUBS1', '^(C|H|L|P|U|V|W|X) +(.*)$'); // substitution types 1: // Call, Htmlchars, Lang, Param, Urlencode, Value, Wchars, Xvalue define('XHT_SUBS2', '^(D|E|R|T) +([^ ]+) +(.*)$'); // substitution types 2: // Define, Escape, Repeat, Test $this->xht_dbgo = ''; $this->xht_param = array(0 => '0', 1 => '1', '' => '', 'empty' => '', 'rdepth' => 0); $this->_prev_param = $this->xht_param; // empty: {-R * P empty-} puts the number of subelements in {-P number-} // rdepth: current number of nested R's // rdepth1, rdepth2, ...: key or number, see R }
$temp=str_replace($texstring,"{texcode}",$temp); } */ // blanks will be put into an array $blanks = array(); $i = 1; // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks if (($pos = api_strpos($temp, '[')) === false) { break; } // removes characters till '[' $temp = api_substr($temp, $pos + 1); // quits the loop if there are no more blanks if (($pos = api_strpos($temp, ']')) === false) { break; } // stores the found blank into the array $blanks[$i++] = api_substr($temp, 0, $pos); // removes the character ']' $temp = api_substr($temp, $pos + 1); } } } else { unset($setWeighting); } } elseif ($answerType == FREE_ANSWER) { if ($debug > 0) { echo str_repeat(' ', 2) . '$answerType is FREE_ANSWER' . "<br />\n"; }
function mds_update_xml_and_mdt($mdo, &$xmlDoc, $mda, $eid, &$traceinfo, $exists = TRUE) // note: $xmlDoc and $traceinfo passed by reference { foreach (explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $mda))) as $update) { if (!$update) continue; if (($nameLth = strpos($update, '='))) // e.g. 'gen/tit/str=new' { if (($text = api_substr($update, $nameLth + 1)) === FALSE) $text = ''; if (!($path = trim(api_substr($update, 0, $nameLth)))) continue; if (($sc = api_strpos($path, ';'))) // e.g. 'gen/tit,gen/des;str@lang' $xmlDoc->xmd_update_many(api_substr($path, 0, $sc), api_substr($path, $sc + 1), $text); else $xmlDoc->xmd_update($path, $text); } elseif ($nameLth === FALSE) // e.g. 'gen/tit/str[-1]~' { if ($update == '~~') { $update = 'DELETE ' . $eid; if ($exists === FALSE) $update = ''; else $this->mds_delete($eid); $mda = ''; $exists = TRUE; foreach ($xmlDoc->children[0] as $key => $child) unset($xmlDoc->children[0][$key]); } elseif ($update == '!!') { define_kwds($mdo); $update = ''; $mda = ''; $exists = TRUE; } else { $x = $xmlDoc->xmd_update(trim($update), ''); } } if ($update) $traceinfo .= $update . '- '; } $mdt = $xmlDoc->xmd_xml(); if ($exists === FALSE) { $this->mds_put($eid, $mdt, 'mdxmltext', FALSE); $traceinfo .= 'INSERT ' . $eid . '- '; } elseif($mda) { $this->mds_put($eid, $mdt, 'mdxmltext'); $traceinfo .= 'UPDATE ' . $eid . '- '; } return $mdt; }
/** * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya. * @param string $firstname The first name of the user. * @param string $lastname The last name of the user. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then. * @param string $encoding (optional) The character encoding for the input names. If it is omitted, the platform character set will be used by default. * @return string Suggests a username that contains only ASCII-letters and digits, without check for uniqueness within the system. * @author Julio Montoya Armas * @author Ivan Tcholakov, 2009 - rework about internationalization. * @assert ('','') === false * @assert ('a','b') === 'ab' */ public static function create_username($firstname, $lastname, $language = null, $encoding = null) { if (is_null($encoding)) { $encoding = api_get_system_encoding(); } if (is_null($language)) { $language = api_get_interface_language(); } $firstname = api_substr(preg_replace(USERNAME_PURIFIER, '', api_transliterate($firstname, '', $encoding)), 0, 1); // The first letter only. //Looking for a space in the lastname $pos = api_strpos($lastname, ' '); if ($pos !== false) { $lastname = api_substr($lastname, 0, $pos); } $lastname = preg_replace(USERNAME_PURIFIER, '', api_transliterate($lastname, '', $encoding)); //$username = api_is_western_name_order(null, $language) ? $firstname.$lastname : $lastname.$firstname; $username = $firstname . $lastname; if (empty($username)) { $username = '******'; } return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3)); }
/** * This function was originally found in the exercise_show.php * @param int $exeId * @param int $questionId * @param int $choice the user selected * @param string $from function is called from 'exercise_show' or 'exercise_result' * @param array $exerciseResultCoordinates the hotspot coordinates $hotspot[$question_id] = coordinates * @param bool $saved_results save results in the DB or just show the reponse * @param bool $from_database gets information from DB or from the current selection * @param bool $show_result show results or not * @param int $propagate_neg * @param array $hotspot_delineation_result * * @todo reduce parameters of this function * @return string html code */ public function manage_answer($exeId, $questionId, $choice, $from = 'exercise_show', $exerciseResultCoordinates = array(), $saved_results = true, $from_database = false, $show_result = true, $propagate_neg = 0, $hotspot_delineation_result = array()) { global $debug; //needed in order to use in the exercise_attempt() for the time global $learnpath_id, $learnpath_item_id; require_once api_get_path(LIBRARY_PATH) . 'geometry.lib.php'; $feedback_type = $this->selectFeedbackType(); $results_disabled = $this->selectResultsDisabled(); if ($debug) { error_log("<------ manage_answer ------> "); error_log('exe_id: ' . $exeId); error_log('$from: ' . $from); error_log('$saved_results: ' . intval($saved_results)); error_log('$from_database: ' . intval($from_database)); error_log('$show_result: ' . $show_result); error_log('$propagate_neg: ' . $propagate_neg); error_log('$exerciseResultCoordinates: ' . print_r($exerciseResultCoordinates, 1)); error_log('$hotspot_delineation_result: ' . print_r($hotspot_delineation_result, 1)); error_log('$learnpath_id: ' . $learnpath_id); error_log('$learnpath_item_id: ' . $learnpath_item_id); error_log('$choice: ' . print_r($choice, 1)); } $extra_data = array(); $final_overlap = 0; $final_missing = 0; $final_excess = 0; $overlap_color = 0; $missing_color = 0; $excess_color = 0; $threadhold1 = 0; $threadhold2 = 0; $threadhold3 = 0; $arrques = null; $arrans = null; $questionId = intval($questionId); $exeId = intval($exeId); $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER); // Creates a temporary Question object $course_id = $this->course_id; $objQuestionTmp = Question::read($questionId, $course_id); if ($objQuestionTmp === false) { return false; } $questionName = $objQuestionTmp->selectTitle(); $questionWeighting = $objQuestionTmp->selectWeighting(); $answerType = $objQuestionTmp->selectType(); $quesId = $objQuestionTmp->selectId(); $extra = $objQuestionTmp->extra; $next = 1; //not for now // Extra information of the question if (!empty($extra)) { $extra = explode(':', $extra); if ($debug) { error_log(print_r($extra, 1)); } // Fixes problems with negatives values using intval $true_score = floatval(trim($extra[0])); $false_score = floatval(trim($extra[1])); $doubt_score = floatval(trim($extra[2])); } $totalWeighting = 0; $totalScore = 0; // Destruction of the Question object unset($objQuestionTmp); // Construction of the Answer object $objAnswerTmp = new Answer($questionId); $nbrAnswers = $objAnswerTmp->selectNbrAnswers(); if ($debug) { error_log('Count of answers: ' . $nbrAnswers); error_log('$answerType: ' . $answerType); } if ($answerType == FREE_ANSWER || $answerType == ORAL_EXPRESSION || $answerType == CALCULATED_ANSWER) { $nbrAnswers = 1; } $nano = null; if ($answerType == ORAL_EXPRESSION) { $exe_info = Event::get_exercise_results_by_attempt($exeId); $exe_info = isset($exe_info[$exeId]) ? $exe_info[$exeId] : null; $params = array(); $params['course_id'] = $course_id; $params['session_id'] = api_get_session_id(); $params['user_id'] = isset($exe_info['exe_user_id']) ? $exe_info['exe_user_id'] : api_get_user_id(); $params['exercise_id'] = isset($exe_info['exe_exo_id']) ? $exe_info['exe_exo_id'] : $this->id; $params['question_id'] = $questionId; $params['exe_id'] = isset($exe_info['exe_id']) ? $exe_info['exe_id'] : $exeId; $nano = new Nanogong($params); //probably this attempt came in an exercise all question by page if ($feedback_type == 0) { $nano->replace_with_real_exe($exeId); } } $user_answer = ''; // Get answer list for matching $sql = "SELECT id_auto, id, answer\n FROM {$table_ans}\n WHERE c_id = {$course_id} AND question_id = {$questionId}"; $res_answer = Database::query($sql); $answerMatching = array(); while ($real_answer = Database::fetch_array($res_answer)) { $answerMatching[$real_answer['id_auto']] = $real_answer['answer']; } $real_answers = array(); $quiz_question_options = Question::readQuestionOption($questionId, $course_id); $organs_at_risk_hit = 0; $questionScore = 0; if ($debug) { error_log('Start answer loop '); } $answer_correct_array = array(); for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { $answer = $objAnswerTmp->selectAnswer($answerId); $answerComment = $objAnswerTmp->selectComment($answerId); $answerCorrect = $objAnswerTmp->isCorrect($answerId); $answerWeighting = (double) $objAnswerTmp->selectWeighting($answerId); $answerAutoId = $objAnswerTmp->selectAutoId($answerId); $answer_correct_array[$answerId] = (bool) $answerCorrect; if ($debug) { error_log("answer auto id: {$answerAutoId} "); error_log("answer correct: {$answerCorrect} "); } // Delineation $delineation_cord = $objAnswerTmp->selectHotspotCoordinates(1); $answer_delineation_destination = $objAnswerTmp->selectDestination(1); switch ($answerType) { // for unique answer case UNIQUE_ANSWER: case UNIQUE_ANSWER_IMAGE: case UNIQUE_ANSWER_NO_OPTION: if ($from_database) { $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = '" . $exeId . "' AND\n question_id= '" . $questionId . "'"; $result = Database::query($sql); $choice = Database::result($result, 0, "answer"); $studentChoice = $choice == $answerAutoId ? 1 : 0; if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } else { $studentChoice = $choice == $answerAutoId ? 1 : 0; if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } break; // for multiple answers // for multiple answers case MULTIPLE_ANSWER_TRUE_FALSE: if ($from_database) { $choice = array(); $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = {$exeId} AND\n question_id = " . $questionId; $result = Database::query($sql); while ($row = Database::fetch_array($result)) { $ind = $row['answer']; $values = explode(':', $ind); $my_answer_id = isset($values[0]) ? $values[0] : ''; $option = isset($values[1]) ? $values[1] : ''; $choice[$my_answer_id] = $option; } } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if (!empty($studentChoice)) { if ($studentChoice == $answerCorrect) { $questionScore += $true_score; } else { if ($quiz_question_options[$studentChoice]['name'] == "Don't know" || $quiz_question_options[$studentChoice]['name'] == "DoubtScore") { $questionScore += $doubt_score; } else { $questionScore += $false_score; } } } else { // If no result then the user just hit don't know $studentChoice = 3; $questionScore += $doubt_score; } $totalScore = $questionScore; break; case MULTIPLE_ANSWER: //2 if ($from_database) { $choice = array(); $sql = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; $real_answers[$answerId] = (bool) $studentChoice; if ($studentChoice) { $questionScore += $answerWeighting; } } else { $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; $real_answers[$answerId] = (bool) $studentChoice; if (isset($studentChoice)) { $questionScore += $answerWeighting; } } $totalScore += $answerWeighting; if ($debug) { error_log("studentChoice: {$studentChoice}"); } break; case GLOBAL_MULTIPLE_ANSWER: if ($from_database) { $choice = array(); $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; $real_answers[$answerId] = (bool) $studentChoice; if ($studentChoice) { $questionScore += $answerWeighting; } } else { $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if (isset($studentChoice)) { $questionScore += $answerWeighting; } $real_answers[$answerId] = (bool) $studentChoice; } $totalScore += $answerWeighting; if ($debug) { error_log("studentChoice: {$studentChoice}"); } break; case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: if ($from_database) { $sql = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = {$exeId} AND question_id= " . $questionId; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $result = explode(':', $ind); if (isset($result[0])) { $my_answer_id = isset($result[0]) ? $result[0] : ''; $option = isset($result[1]) ? $result[1] : ''; $choice[$my_answer_id] = $option; } } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : ''; if ($answerCorrect == $studentChoice) { //$answerCorrect = 1; $real_answers[$answerId] = true; } else { //$answerCorrect = 0; $real_answers[$answerId] = false; } } else { $studentChoice = $choice[$answerAutoId]; if ($answerCorrect == $studentChoice) { //$answerCorrect = 1; $real_answers[$answerId] = true; } else { //$answerCorrect = 0; $real_answers[$answerId] = false; } } break; case MULTIPLE_ANSWER_COMBINATION: if ($from_database) { $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE exe_id = {$exeId} AND question_id= {$questionId}"; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if ($answerCorrect == 1) { if ($studentChoice) { $real_answers[$answerId] = true; } else { $real_answers[$answerId] = false; } } else { if ($studentChoice) { $real_answers[$answerId] = false; } else { $real_answers[$answerId] = true; } } } else { $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if ($answerCorrect == 1) { if ($studentChoice) { $real_answers[$answerId] = true; } else { $real_answers[$answerId] = false; } } else { if ($studentChoice) { $real_answers[$answerId] = false; } else { $real_answers[$answerId] = true; } } } break; case FILL_IN_BLANKS: $str = ''; if ($from_database) { $sql = "SELECT answer\n FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = {$exeId} AND\n question_id= " . intval($questionId); $result = Database::query($sql); $str = Database::result($result, 0, 'answer'); } if ($saved_results == false && strpos($str, 'font color') !== false) { // the question is encoded like this // [A] B [C] D [E] F::10,10,10@1 // number 1 before the "@" means that is a switchable fill in blank question // [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10 // means that is a normal fill blank question // first we explode the "::" $pre_array = explode('::', $answer); // is switchable fill blank or not $last = count($pre_array) - 1; $is_set_switchable = explode('@', $pre_array[$last]); $switchable_answer_set = false; if (isset($is_set_switchable[1]) && $is_set_switchable[1] == 1) { $switchable_answer_set = true; } $answer = ''; for ($k = 0; $k < $last; $k++) { $answer .= $pre_array[$k]; } // splits weightings that are joined with a comma $answerWeighting = explode(',', $is_set_switchable[0]); // we save the answer because it will be modified $temp = $answer; $answer = ''; $j = 0; //initialise answer tags $user_tags = $correct_tags = $real_text = array(); // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks (detect '[') if (($pos = api_strpos($temp, '[')) === false) { // adds the end of the text $answer = $temp; $real_text[] = $answer; break; //no more "blanks", quit the loop } // adds the piece of text that is before the blank //and ends with '[' into a general storage array $real_text[] = api_substr($temp, 0, $pos + 1); $answer .= api_substr($temp, 0, $pos + 1); //take the string remaining (after the last "[" we found) $temp = api_substr($temp, $pos + 1); // quit the loop if there are no more blanks, and update $pos to the position of next ']' if (($pos = api_strpos($temp, ']')) === false) { // adds the end of the text $answer .= $temp; break; } if ($from_database) { $queryfill = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE\n exe_id = '" . $exeId . "' AND\n question_id= " . intval($questionId) . ""; $resfill = Database::query($queryfill); $str = Database::result($resfill, 0, 'answer'); api_preg_match_all('#\\[([^[]*)\\]#', $str, $arr); $str = str_replace('\\r\\n', '', $str); $choice = $arr[1]; if (isset($choice[$j])) { $tmp = api_strrpos($choice[$j], ' / '); $choice[$j] = api_substr($choice[$j], 0, $tmp); $choice[$j] = trim($choice[$j]); // Needed to let characters ' and " to work as part of an answer $choice[$j] = stripslashes($choice[$j]); } else { $choice[$j] = null; } } else { // This value is the user input, not escaped while correct answer is escaped by fckeditor $choice[$j] = api_htmlentities(trim($choice[$j])); } $user_tags[] = $choice[$j]; //put the contents of the [] answer tag into correct_tags[] $correct_tags[] = api_substr($temp, 0, $pos); $j++; $temp = api_substr($temp, $pos + 1); } $answer = ''; $real_correct_tags = $correct_tags; $chosen_list = array(); for ($i = 0; $i < count($real_correct_tags); $i++) { if ($i == 0) { $answer .= $real_text[0]; } if (!$switchable_answer_set) { // Needed to parse ' and " characters $user_tags[$i] = stripslashes($user_tags[$i]); if ($correct_tags[$i] == $user_tags[$i]) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $correct_tags[$i]; } elseif (!empty($user_tags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ''; // remove that causes issue } } else { // switchable fill in the blanks if (in_array($user_tags[$i], $correct_tags)) { $chosen_list[] = $user_tags[$i]; $correct_tags = array_diff($correct_tags, $chosen_list); // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $user_tags[$i]; } elseif (!empty($user_tags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ''; // remove that causes issue } } // adds the correct word, followed by ] to close the blank $answer .= ' / <font color="green"><b>' . $real_correct_tags[$i] . '</b></font>]'; if (isset($real_text[$i + 1])) { $answer .= $real_text[$i + 1]; } } } else { // insert the student result in the track_e_attempt table, field answer // $answer is the answer like in the c_quiz_answer table for the question // student data are choice[] $listCorrectAnswers = FillBlanks::getAnswerInfo($answer); $switchableAnswerSet = $listCorrectAnswers["switchable"]; $answerWeighting = $listCorrectAnswers["tabweighting"]; // user choices is an array $choice // get existing user data in n the BDD if ($from_database) { $sql = "SELECT answer\n FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = {$exeId} AND\n question_id= " . intval($questionId); $result = Database::query($sql); $str = Database::result($result, 0, 'answer'); $listStudentResults = FillBlanks::getAnswerInfo($str, true); $choice = $listStudentResults['studentanswer']; } // loop other all blanks words if (!$switchableAnswerSet) { // not switchable answer, must be in the same place than teacher order for ($i = 0; $i < count($listCorrectAnswers['tabwords']); $i++) { $studentAnswer = isset($choice[$i]) ? trim($choice[$i]) : ''; // This value is the user input, not escaped while correct answer is escaped by fckeditor // Works with cyrillic alphabet and when using ">" chars see #7718 #7610 #7618 if (!$from_database) { $studentAnswer = htmlentities(api_utf8_encode($studentAnswer)); } $correctAnswer = $listCorrectAnswers['tabwords'][$i]; $isAnswerCorrect = 0; if (FillBlanks::isGoodStudentAnswer($studentAnswer, $correctAnswer)) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; $isAnswerCorrect = 1; } $listCorrectAnswers['studentanswer'][$i] = $studentAnswer; $listCorrectAnswers['studentscore'][$i] = $isAnswerCorrect; } } else { // switchable answer $listStudentAnswerTemp = $choice; $listTeacherAnswerTemp = $listCorrectAnswers['tabwords']; // for every teacher answer, check if there is a student answer for ($i = 0; $i < count($listStudentAnswerTemp); $i++) { $studentAnswer = trim($listStudentAnswerTemp[$i]); $found = false; for ($j = 0; $j < count($listTeacherAnswerTemp); $j++) { $correctAnswer = $listTeacherAnswerTemp[$j]; if (!$found) { if (FillBlanks::isGoodStudentAnswer($studentAnswer, $correctAnswer)) { $questionScore += $answerWeighting[$i]; $totalScore += $answerWeighting[$i]; $listTeacherAnswerTemp[$j] = ""; $found = true; } } } $listCorrectAnswers['studentanswer'][$i] = $studentAnswer; if (!$found) { $listCorrectAnswers['studentscore'][$i] = 0; } else { $listCorrectAnswers['studentscore'][$i] = 1; } } } $answer = FillBlanks::getAnswerInStudentAttempt($listCorrectAnswers); } break; // for calculated answer // for calculated answer case CALCULATED_ANSWER: $calculatedAnswer = Session::read('calculatedAnswerId'); $answer = $objAnswerTmp->selectAnswer($calculatedAnswer[$questionId]); $preArray = explode('@@', $answer); $last = count($preArray) - 1; $answer = ''; for ($k = 0; $k < $last; $k++) { $answer .= $preArray[$k]; } $answerWeighting = array($answerWeighting); // we save the answer because it will be modified $temp = $answer; $answer = ''; $j = 0; //initialise answer tags $userTags = $correctTags = $realText = array(); // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks (detect '[') if (($pos = api_strpos($temp, '[')) === false) { // adds the end of the text $answer = $temp; $realText[] = $answer; break; //no more "blanks", quit the loop } // adds the piece of text that is before the blank //and ends with '[' into a general storage array $realText[] = api_substr($temp, 0, $pos + 1); $answer .= api_substr($temp, 0, $pos + 1); //take the string remaining (after the last "[" we found) $temp = api_substr($temp, $pos + 1); // quit the loop if there are no more blanks, and update $pos to the position of next ']' if (($pos = api_strpos($temp, ']')) === false) { // adds the end of the text $answer .= $temp; break; } if ($from_database) { $queryfill = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE\n exe_id = '" . $exeId . "' AND\n question_id= " . intval($questionId) . ""; $resfill = Database::query($queryfill); $str = Database::result($resfill, 0, 'answer'); api_preg_match_all('#\\[([^[]*)\\]#', $str, $arr); $str = str_replace('\\r\\n', '', $str); $choice = $arr[1]; if (isset($choice[$j])) { $tmp = api_strrpos($choice[$j], ' / '); $choice[$j] = api_substr($choice[$j], 0, $tmp); $choice[$j] = trim($choice[$j]); // Needed to let characters ' and " to work as part of an answer $choice[$j] = stripslashes($choice[$j]); } else { $choice[$j] = null; } } else { // This value is the user input, not escaped while correct answer is escaped by fckeditor $choice[$j] = api_htmlentities(trim($choice[$j])); } $userTags[] = $choice[$j]; //put the contents of the [] answer tag into correct_tags[] $correctTags[] = api_substr($temp, 0, $pos); $j++; $temp = api_substr($temp, $pos + 1); } $answer = ''; $realCorrectTags = $correctTags; for ($i = 0; $i < count($realCorrectTags); $i++) { if ($i == 0) { $answer .= $realText[0]; } // Needed to parse ' and " characters $userTags[$i] = stripslashes($userTags[$i]); if ($correctTags[$i] == $userTags[$i]) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $correctTags[$i]; } elseif (!empty($userTags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $userTags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ''; // remove that causes issue } // adds the correct word, followed by ] to close the blank $answer .= ' / <font color="green"><b>' . $realCorrectTags[$i] . '</b></font>]'; if (isset($realText[$i + 1])) { $answer .= $realText[$i + 1]; } } break; // for free answer // for free answer case FREE_ANSWER: if ($from_database) { $query = "SELECT answer, marks FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resq = Database::query($query); $data = Database::fetch_array($resq); $choice = $data['answer']; $choice = str_replace('\\r\\n', '', $choice); $choice = stripslashes($choice); $questionScore = $data['marks']; if ($questionScore == -1) { $totalScore += 0; } else { $totalScore += $questionScore; } if ($questionScore == '') { $questionScore = 0; } $arrques = $questionName; $arrans = $choice; } else { $studentChoice = $choice; if ($studentChoice) { //Fixing negative puntation see #2193 $questionScore = 0; $totalScore += 0; } } break; case ORAL_EXPRESSION: if ($from_database) { $query = "SELECT answer, marks FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resq = Database::query($query); $choice = Database::result($resq, 0, 'answer'); $choice = str_replace('\\r\\n', '', $choice); $choice = stripslashes($choice); $questionScore = Database::result($resq, 0, "marks"); if ($questionScore == -1) { $totalScore += 0; } else { $totalScore += $questionScore; } $arrques = $questionName; $arrans = $choice; } else { $studentChoice = $choice; if ($studentChoice) { //Fixing negative puntation see #2193 $questionScore = 0; $totalScore += 0; } } break; case DRAGGABLE: //no break //no break case MATCHING_DRAGGABLE: //no break //no break case MATCHING: if ($from_database) { $sql = 'SELECT id, answer, id_auto FROM ' . $table_ans . ' WHERE c_id = ' . $course_id . ' AND question_id = "' . $questionId . '" AND correct = 0'; $res_answer = Database::query($sql); // Getting the real answer $real_list = array(); while ($real_answer = Database::fetch_array($res_answer)) { $real_list[$real_answer['id_auto']] = $real_answer['answer']; } $sql = 'SELECT id, answer, correct, id_auto, ponderation FROM ' . $table_ans . ' WHERE c_id = ' . $course_id . ' AND question_id="' . $questionId . '" AND correct <> 0 ORDER BY id_auto'; $res_answers = Database::query($sql); $questionScore = 0; while ($a_answers = Database::fetch_array($res_answers)) { $i_answer_id = $a_answers['id']; //3 $s_answer_label = $a_answers['answer']; // your daddy - your mother $i_answer_correct_answer = $a_answers['correct']; //1 - 2 $i_answer_id_auto = $a_answers['id_auto']; // 3 - 4 $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = '{$exeId}' AND\n question_id = '{$questionId}' AND\n position = '{$i_answer_id_auto}'"; $res_user_answer = Database::query($sql); if (Database::num_rows($res_user_answer) > 0) { // rich - good looking $s_user_answer = Database::result($res_user_answer, 0, 0); } else { $s_user_answer = 0; } $i_answerWeighting = $a_answers['ponderation']; $user_answer = ''; if (!empty($s_user_answer)) { if ($answerType == DRAGGABLE) { if ($s_user_answer == $i_answer_correct_answer) { $questionScore += $i_answerWeighting; $totalScore += $i_answerWeighting; $user_answer = Display::label(get_lang('Correct'), 'success'); } else { $user_answer = Display::label(get_lang('Incorrect'), 'danger'); } } else { if ($s_user_answer == $i_answer_correct_answer) { $questionScore += $i_answerWeighting; $totalScore += $i_answerWeighting; if (isset($real_list[$i_answer_id])) { $user_answer = Display::span($real_list[$i_answer_id]); } } else { $user_answer = Display::span($real_list[$s_user_answer], ['style' => 'color: #FF0000; text-decoration: line-through;']); } } } elseif ($answerType == DRAGGABLE) { $user_answer = Display::label(get_lang('Incorrect'), 'danger'); } if ($show_result) { echo '<tr>'; echo '<td>' . $s_answer_label . '</td>'; echo '<td>' . $user_answer; if (in_array($answerType, [MATCHING, MATCHING_DRAGGABLE])) { if (isset($real_list[$i_answer_correct_answer])) { echo Display::span($real_list[$i_answer_correct_answer], ['style' => 'color: #008000; font-weight: bold;']); } } echo '</td>'; echo '</tr>'; } } break 2; // break the switch and the "for" condition } else { if ($answerCorrect) { if (isset($choice[$answerAutoId]) && $answerCorrect == $choice[$answerAutoId]) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $user_answer = Display::span($answerMatching[$choice[$answerAutoId]]); } else { if (isset($answerMatching[$choice[$answerAutoId]])) { $user_answer = Display::span($answerMatching[$choice[$answerAutoId]], ['style' => 'color: #FF0000; text-decoration: line-through;']); } } $matching[$answerAutoId] = $choice[$answerAutoId]; } break; } case HOT_SPOT: if ($from_database) { $TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); $sql = "SELECT hotspot_correct\n FROM {$TBL_TRACK_HOTSPOT}\n WHERE\n hotspot_exe_id = '" . $exeId . "' AND\n hotspot_question_id= '" . $questionId . "' AND\n hotspot_answer_id = " . intval($answerAutoId) . ""; $result = Database::query($sql); $studentChoice = Database::result($result, 0, "hotspot_correct"); if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } else { if (!isset($choice[$answerAutoId])) { $choice[$answerAutoId] = 0; } else { $studentChoice = $choice[$answerAutoId]; $choiceIsValid = false; if (!empty($studentChoice)) { $hotspotType = $objAnswerTmp->selectHotspotType($answerId); $hotspotCoordinates = $objAnswerTmp->selectHotspotCoordinates($answerId); $choicePoint = Geometry::decodePoint($studentChoice); switch ($hotspotType) { case 'square': $hotspotProperties = Geometry::decodeSquare($hotspotCoordinates); $choiceIsValid = Geometry::pointIsInSquare($hotspotProperties, $choicePoint); break; case 'circle': $hotspotProperties = Geometry::decodeEllipse($hotspotCoordinates); $choiceIsValid = Geometry::pointIsInEllipse($hotspotProperties, $choicePoint); break; case 'poly': $hotspotProperties = Geometry::decodePolygon($hotspotCoordinates); $choiceIsValid = Geometry::pointIsInPolygon($hotspotProperties, $choicePoint); break; } } $choice[$answerAutoId] = 0; if ($choiceIsValid) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $choice[$answerAutoId] = 1; } } } break; // @todo never added to chamilo //for hotspot with fixed order // @todo never added to chamilo //for hotspot with fixed order case HOT_SPOT_ORDER: $studentChoice = $choice['order'][$answerId]; if ($studentChoice == $answerId) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $studentChoice = true; } else { $studentChoice = false; } break; // for hotspot with delineation // for hotspot with delineation case HOT_SPOT_DELINEATION: if ($from_database) { // getting the user answer $TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); $query = "SELECT hotspot_correct, hotspot_coordinate\n FROM {$TBL_TRACK_HOTSPOT}\n WHERE\n hotspot_exe_id = '" . $exeId . "' AND\n hotspot_question_id= '" . $questionId . "' AND\n hotspot_answer_id='1'"; //by default we take 1 because it's a delineation $resq = Database::query($query); $row = Database::fetch_array($resq, 'ASSOC'); $choice = $row['hotspot_correct']; $user_answer = $row['hotspot_coordinate']; // THIS is very important otherwise the poly_compile will throw an error!! // round-up the coordinates $coords = explode('/', $user_answer); $user_array = ''; foreach ($coords as $coord) { list($x, $y) = explode(';', $coord); $user_array .= round($x) . ';' . round($y) . '/'; } $user_array = substr($user_array, 0, -1); } else { if (!empty($studentChoice)) { $newquestionList[] = $questionId; } if ($answerId === 1) { $studentChoice = $choice[$answerId]; $questionScore += $answerWeighting; if ($hotspot_delineation_result[1] == 1) { $totalScore += $answerWeighting; //adding the total } } } $_SESSION['hotspot_coord'][1] = $delineation_cord; $_SESSION['hotspot_dest'][1] = $answer_delineation_destination; break; } // end switch Answertype if ($show_result) { if ($debug) { error_log('show result ' . $show_result); } if ($from == 'exercise_result') { if ($debug) { error_log('Showing questions $from ' . $from); } //display answers (if not matching type, or if the answer is correct) if (!in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE]) || $answerCorrect) { if (in_array($answerType, array(UNIQUE_ANSWER, UNIQUE_ANSWER_IMAGE, UNIQUE_ANSWER_NO_OPTION, MULTIPLE_ANSWER, MULTIPLE_ANSWER_COMBINATION, GLOBAL_MULTIPLE_ANSWER))) { //if ($origin != 'learnpath') { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, 0, 0, $results_disabled); //} } elseif ($answerType == MULTIPLE_ANSWER_TRUE_FALSE) { //if ($origin!='learnpath') { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, $questionId, 0, $results_disabled); //} } elseif ($answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { // if ($origin!='learnpath') { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, 0, 0, $results_disabled); //} } elseif ($answerType == FILL_IN_BLANKS) { //if ($origin!='learnpath') { ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer, 0, 0, $results_disabled); // } } elseif ($answerType == CALCULATED_ANSWER) { //if ($origin!='learnpath') { ExerciseShowFunctions::display_calculated_answer($feedback_type, $answer, 0, 0); // } } elseif ($answerType == FREE_ANSWER) { //if($origin != 'learnpath') { ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore); //} } elseif ($answerType == ORAL_EXPRESSION) { // to store the details of open questions in an array to be used in mail //if ($origin != 'learnpath') { ExerciseShowFunctions::display_oral_expression_answer($feedback_type, $choice, 0, 0, $nano); //} } elseif ($answerType == HOT_SPOT) { //if ($origin != 'learnpath') { ExerciseShowFunctions::display_hotspot_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment, $results_disabled); // } } elseif ($answerType == HOT_SPOT_ORDER) { //if ($origin != 'learnpath') { ExerciseShowFunctions::display_hotspot_order_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment); //} } elseif ($answerType == HOT_SPOT_DELINEATION) { $user_answer = $_SESSION['exerciseResultCoordinates'][$questionId]; //round-up the coordinates $coords = explode('/', $user_answer); $user_array = ''; foreach ($coords as $coord) { list($x, $y) = explode(';', $coord); $user_array .= round($x) . ';' . round($y) . '/'; } $user_array = substr($user_array, 0, -1); if ($next) { $user_answer = $user_array; // we compare only the delineation not the other points $answer_question = $_SESSION['hotspot_coord'][1]; $answerDestination = $_SESSION['hotspot_dest'][1]; //calculating the area $poly_user = convert_coordinates($user_answer, '/'); $poly_answer = convert_coordinates($answer_question, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_user_compiled = poly_compile($poly_user, $max_coord); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $poly_results = poly_result($poly_answer_compiled, $poly_user_compiled, $max_coord); $overlap = $poly_results['both']; $poly_answer_area = $poly_results['s1']; $poly_user_area = $poly_results['s2']; $missing = $poly_results['s1Only']; $excess = $poly_results['s2Only']; //$overlap = round(polygons_overlap($poly_answer,$poly_user)); // //this is an area in pixels if ($debug > 0) { error_log(__LINE__ . ' - Polygons results are ' . print_r($poly_results, 1), 0); } if ($overlap < 1) { //shortcut to avoid complicated calculations $final_overlap = 0; $final_missing = 100; $final_excess = 100; } else { // the final overlap is the percentage of the initial polygon // that is overlapped by the user's polygon $final_overlap = round((double) $overlap / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final overlap is ' . $final_overlap, 0); } // the final missing area is the percentage of the initial polygon // that is not overlapped by the user's polygon $final_missing = 100 - $final_overlap; if ($debug > 1) { error_log(__LINE__ . ' - Final missing is ' . $final_missing, 0); } // the final excess area is the percentage of the initial polygon's size // that is covered by the user's polygon outside of the initial polygon $final_excess = round(((double) $poly_user_area - (double) $overlap) / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final excess is ' . $final_excess, 0); } } //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); $threadhold_total = $destination_items[0]; $threadhold_items = explode(';', $threadhold_total); $threadhold1 = $threadhold_items[0]; // overlap $threadhold2 = $threadhold_items[1]; // excess $threadhold3 = $threadhold_items[2]; //missing // if is delineation if ($answerId === 1) { //setting colors if ($final_overlap >= $threadhold1) { $overlap_color = true; //echo 'a'; } //echo $excess.'-'.$threadhold2; if ($final_excess <= $threadhold2) { $excess_color = true; //echo 'b'; } //echo '--------'.$missing.'-'.$threadhold3; if ($final_missing <= $threadhold3) { $missing_color = true; //echo 'c'; } // if pass if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) { $next = 1; //go to the oars $result_comment = get_lang('Acceptable'); $final_answer = 1; // do not update with update_exercise_attempt } else { $next = 0; $result_comment = get_lang('Unacceptable'); $comment = $answerDestination = $objAnswerTmp->selectComment(1); $answerDestination = $objAnswerTmp->selectDestination(1); //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); } } elseif ($answerId > 1) { if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') { if ($debug > 0) { error_log(__LINE__ . ' - answerId is of type noerror', 0); } //type no error shouldn't be treated $next = 1; continue; } if ($debug > 0) { error_log(__LINE__ . ' - answerId is >1 so we\'re probably in OAR', 0); } //check the intersection between the oar and the user //echo 'user'; print_r($x_user_list); print_r($y_user_list); //echo 'official';print_r($x_list);print_r($y_list); //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list); $inter = $result['success']; //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId); $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); $poly_answer = convert_coordinates($delineation_cord, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $overlap = poly_touch($poly_user_compiled, $poly_answer_compiled, $max_coord); if ($overlap == false) { //all good, no overlap $next = 1; continue; } else { if ($debug > 0) { error_log(__LINE__ . ' - Overlap is ' . $overlap . ': OAR hit', 0); } $organs_at_risk_hit++; //show the feedback $next = 0; $comment = $answerDestination = $objAnswerTmp->selectComment($answerId); $answerDestination = $objAnswerTmp->selectDestination($answerId); $destination_items = explode('@@', $answerDestination); $try_hotspot = $destination_items[1]; $lp_hotspot = $destination_items[2]; $select_question_hotspot = $destination_items[3]; $url_hotspot = $destination_items[4]; } } } else { // the first delineation feedback if ($debug > 0) { error_log(__LINE__ . ' first', 0); } } } elseif (in_array($answerType, [MATCHING, MATCHING_DRAGGABLE])) { echo '<tr>'; echo Display::tag('td', $answerMatching[$answerId]); echo Display::tag('td', "{$user_answer} / " . Display::tag('strong', $answerMatching[$answerCorrect], ['style' => 'color: #008000; font-weight: bold;'])); echo '</tr>'; } } } else { if ($debug) { error_log('Showing questions $from ' . $from); } switch ($answerType) { case UNIQUE_ANSWER: case UNIQUE_ANSWER_IMAGE: case UNIQUE_ANSWER_NO_OPTION: case MULTIPLE_ANSWER: case GLOBAL_MULTIPLE_ANSWER: case MULTIPLE_ANSWER_COMBINATION: if ($answerId == 1) { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId, $results_disabled); } else { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, "", $results_disabled); } break; case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: if ($answerId == 1) { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId, $results_disabled); } else { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, "", $results_disabled); } break; case MULTIPLE_ANSWER_TRUE_FALSE: if ($answerId == 1) { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId, $results_disabled); } else { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, "", $results_disabled); } break; case FILL_IN_BLANKS: ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer, $exeId, $questionId, $results_disabled, $str); break; case CALCULATED_ANSWER: ExerciseShowFunctions::display_calculated_answer($feedback_type, $answer, $exeId, $questionId); break; case FREE_ANSWER: echo ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore); break; case ORAL_EXPRESSION: echo '<tr> <td valign="top">' . ExerciseShowFunctions::display_oral_expression_answer($feedback_type, $choice, $exeId, $questionId, $nano) . '</td> </tr> </table>'; break; case HOT_SPOT: ExerciseShowFunctions::display_hotspot_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment, $results_disabled); break; case HOT_SPOT_DELINEATION: $user_answer = $user_array; if ($next) { //$tbl_track_e_hotspot = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); // Save into db /* $sql = "INSERT INTO $tbl_track_e_hotspot ( * hotspot_user_id, * hotspot_course_code, * hotspot_exe_id, * hotspot_question_id, * hotspot_answer_id, * hotspot_correct, * hotspot_coordinate * ) VALUES ( * '".Database::escape_string($_user['user_id'])."', * '".Database::escape_string($_course['id'])."', * '".Database::escape_string($exeId)."', '".Database::escape_string($questionId)."', * '".Database::escape_string($answerId)."', * '".Database::escape_string($studentChoice)."', * '".Database::escape_string($user_array)."')"; $result = Database::query($sql,__FILE__,__LINE__); */ $user_answer = $user_array; // we compare only the delineation not the other points $answer_question = $_SESSION['hotspot_coord'][1]; $answerDestination = $_SESSION['hotspot_dest'][1]; //calculating the area $poly_user = convert_coordinates($user_answer, '/'); $poly_answer = convert_coordinates($answer_question, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_user_compiled = poly_compile($poly_user, $max_coord); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $poly_results = poly_result($poly_answer_compiled, $poly_user_compiled, $max_coord); $overlap = $poly_results['both']; $poly_answer_area = $poly_results['s1']; $poly_user_area = $poly_results['s2']; $missing = $poly_results['s1Only']; $excess = $poly_results['s2Only']; //$overlap = round(polygons_overlap($poly_answer,$poly_user)); //this is an area in pixels if ($debug > 0) { error_log(__LINE__ . ' - Polygons results are ' . print_r($poly_results, 1), 0); } if ($overlap < 1) { //shortcut to avoid complicated calculations $final_overlap = 0; $final_missing = 100; $final_excess = 100; } else { // the final overlap is the percentage of the initial polygon that is overlapped by the user's polygon $final_overlap = round((double) $overlap / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final overlap is ' . $final_overlap, 0); } // the final missing area is the percentage of the initial polygon that is not overlapped by the user's polygon $final_missing = 100 - $final_overlap; if ($debug > 1) { error_log(__LINE__ . ' - Final missing is ' . $final_missing, 0); } // the final excess area is the percentage of the initial polygon's size that is covered by the user's polygon outside of the initial polygon $final_excess = round(((double) $poly_user_area - (double) $overlap) / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final excess is ' . $final_excess, 0); } } //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); $threadhold_total = $destination_items[0]; $threadhold_items = explode(';', $threadhold_total); $threadhold1 = $threadhold_items[0]; // overlap $threadhold2 = $threadhold_items[1]; // excess $threadhold3 = $threadhold_items[2]; //missing // if is delineation if ($answerId === 1) { //setting colors if ($final_overlap >= $threadhold1) { $overlap_color = true; //echo 'a'; } //echo $excess.'-'.$threadhold2; if ($final_excess <= $threadhold2) { $excess_color = true; //echo 'b'; } //echo '--------'.$missing.'-'.$threadhold3; if ($final_missing <= $threadhold3) { $missing_color = true; //echo 'c'; } // if pass if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) { $next = 1; //go to the oars $result_comment = get_lang('Acceptable'); $final_answer = 1; // do not update with update_exercise_attempt } else { $next = 0; $result_comment = get_lang('Unacceptable'); $comment = $answerDestination = $objAnswerTmp->selectComment(1); $answerDestination = $objAnswerTmp->selectDestination(1); //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); } } elseif ($answerId > 1) { if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') { if ($debug > 0) { error_log(__LINE__ . ' - answerId is of type noerror', 0); } //type no error shouldn't be treated $next = 1; continue; } if ($debug > 0) { error_log(__LINE__ . ' - answerId is >1 so we\'re probably in OAR', 0); } //check the intersection between the oar and the user //echo 'user'; print_r($x_user_list); print_r($y_user_list); //echo 'official';print_r($x_list);print_r($y_list); //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list); $inter = $result['success']; //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId); $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); $poly_answer = convert_coordinates($delineation_cord, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $overlap = poly_touch($poly_user_compiled, $poly_answer_compiled, $max_coord); if ($overlap == false) { //all good, no overlap $next = 1; continue; } else { if ($debug > 0) { error_log(__LINE__ . ' - Overlap is ' . $overlap . ': OAR hit', 0); } $organs_at_risk_hit++; //show the feedback $next = 0; $comment = $answerDestination = $objAnswerTmp->selectComment($answerId); $answerDestination = $objAnswerTmp->selectDestination($answerId); $destination_items = explode('@@', $answerDestination); $try_hotspot = $destination_items[1]; $lp_hotspot = $destination_items[2]; $select_question_hotspot = $destination_items[3]; $url_hotspot = $destination_items[4]; } } } else { // the first delineation feedback if ($debug > 0) { error_log(__LINE__ . ' first', 0); } } break; case HOT_SPOT_ORDER: ExerciseShowFunctions::display_hotspot_order_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment); break; case DRAGGABLE: //no break //no break case MATCHING_DRAGGABLE: //no break //no break case MATCHING: echo '<tr>'; echo Display::tag('td', $answerMatching[$answerId]); echo Display::tag('td', "{$user_answer} / " . Display::tag('strong', $answerMatching[$answerCorrect], ['style' => 'color: #008000; font-weight: bold;'])); echo '</tr>'; break; } } } if ($debug) { error_log(' ------ '); } } // end for that loops over all answers of the current question if ($debug) { error_log('-- end answer loop --'); } $final_answer = true; foreach ($real_answers as $my_answer) { if (!$my_answer) { $final_answer = false; } } //we add the total score after dealing with the answers if ($answerType == MULTIPLE_ANSWER_COMBINATION || $answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { if ($final_answer) { //getting only the first score where we save the weight of all the question $answerWeighting = $objAnswerTmp->selectWeighting(1); $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } //Fixes multiple answer question in order to be exact //if ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { /* if ($answerType == GLOBAL_MULTIPLE_ANSWER) { $diff = @array_diff($answer_correct_array, $real_answers); // All good answers or nothing works like exact $counter = 1; $correct_answer = true; foreach ($real_answers as $my_answer) { if ($debug) error_log(" my_answer: $my_answer answer_correct_array[counter]: ".$answer_correct_array[$counter]); if ($my_answer != $answer_correct_array[$counter]) { $correct_answer = false; break; } $counter++; } if ($debug) error_log(" answer_correct_array: ".print_r($answer_correct_array, 1).""); if ($debug) error_log(" real_answers: ".print_r($real_answers, 1).""); if ($debug) error_log(" correct_answer: ".$correct_answer); if ($correct_answer == false) { $questionScore = 0; } // This makes the result non exact if (!empty($diff)) { $questionScore = 0; } }*/ $extra_data = array('final_overlap' => $final_overlap, 'final_missing' => $final_missing, 'final_excess' => $final_excess, 'overlap_color' => $overlap_color, 'missing_color' => $missing_color, 'excess_color' => $excess_color, 'threadhold1' => $threadhold1, 'threadhold2' => $threadhold2, 'threadhold3' => $threadhold3); if ($from == 'exercise_result') { // if answer is hotspot. To the difference of exercise_show.php, // we use the results from the session (from_db=0) // TODO Change this, because it is wrong to show the user // some results that haven't been stored in the database yet if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER || $answerType == HOT_SPOT_DELINEATION) { if ($debug) { error_log('$from AND this is a hotspot kind of question '); } $my_exe_id = 0; $from_database = 0; if ($answerType == HOT_SPOT_DELINEATION) { if (0) { if ($overlap_color) { $overlap_color = 'green'; } else { $overlap_color = 'red'; } if ($missing_color) { $missing_color = 'green'; } else { $missing_color = 'red'; } if ($excess_color) { $excess_color = 'green'; } else { $excess_color = 'red'; } if (!is_numeric($final_overlap)) { $final_overlap = 0; } if (!is_numeric($final_missing)) { $final_missing = 0; } if (!is_numeric($final_excess)) { $final_excess = 0; } if ($final_overlap > 100) { $final_overlap = 100; } $table_resume = '<table class="data_table"> <tr class="row_odd" > <td></td> <td ><b>' . get_lang('Requirements') . '</b></td> <td><b>' . get_lang('YourAnswer') . '</b></td> </tr> <tr class="row_even"> <td><b>' . get_lang('Overlap') . '</b></td> <td>' . get_lang('Min') . ' ' . $threadhold1 . '</td> <td><div style="color:' . $overlap_color . '">' . ($final_overlap < 0 ? 0 : intval($final_overlap)) . '</div></td> </tr> <tr> <td><b>' . get_lang('Excess') . '</b></td> <td>' . get_lang('Max') . ' ' . $threadhold2 . '</td> <td><div style="color:' . $excess_color . '">' . ($final_excess < 0 ? 0 : intval($final_excess)) . '</div></td> </tr> <tr class="row_even"> <td><b>' . get_lang('Missing') . '</b></td> <td>' . get_lang('Max') . ' ' . $threadhold3 . '</td> <td><div style="color:' . $missing_color . '">' . ($final_missing < 0 ? 0 : intval($final_missing)) . '</div></td> </tr> </table>'; if ($next == 0) { $try = $try_hotspot; $lp = $lp_hotspot; $destinationid = $select_question_hotspot; $url = $url_hotspot; } else { //show if no error //echo 'no error'; $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers); $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers); } echo '<h1><div style="color:#333;">' . get_lang('Feedback') . '</div></h1> <p style="text-align:center">'; $message = '<p>' . get_lang('YourDelineation') . '</p>'; $message .= $table_resume; $message .= '<br />' . get_lang('ResultIs') . ' ' . $result_comment . '<br />'; if ($organs_at_risk_hit > 0) { $message .= '<p><b>' . get_lang('OARHit') . '</b></p>'; } $message .= '<p>' . $comment . '</p>'; echo $message; } else { echo $hotspot_delineation_result[0]; //prints message $from_database = 1; // the hotspot_solution.swf needs this variable } //save the score attempts if (1) { //getting the answer 1 or 0 comes from exercise_submit_modal.php $final_answer = $hotspot_delineation_result[1]; if ($final_answer == 0) { $questionScore = 0; } // we always insert the answer_id 1 = delineation Event::saveQuestionAttempt($questionScore, 1, $quesId, $exeId, 0); //in delineation mode, get the answer from $hotspot_delineation_result[1] Event::saveExerciseAttemptHotspot($exeId, $quesId, 1, $hotspot_delineation_result[1], $exerciseResultCoordinates[$quesId]); } else { if ($final_answer == 0) { $questionScore = 0; $answer = 0; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, 0, $val); } } } else { Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, $choice[$idx], $val); } } } } $my_exe_id = $exeId; } } if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER) { // We made an extra table for the answers if ($show_result) { // if ($origin != 'learnpath') { echo '</table></td></tr>'; echo "\n <tr>\n <td colspan=\"2\">\n <p><em>" . get_lang('HotSpot') . "</em></p>\n <div id=\"hotspot-solution-{$questionId}\"></div>\n\n <script>\n \$(document).on('ready', function () {\n new HotspotQuestion({\n questionId: {$questionId},\n exerciseId: {$exeId},\n selector: '#hotspot-solution-{$questionId}',\n for: 'solution'\n });\n });\n </script>\n </td>\n </tr>\n "; // } } } //if ($origin != 'learnpath') { if ($show_result) { echo '</table>'; } // } } unset($objAnswerTmp); $totalWeighting += $questionWeighting; // Store results directly in the database // For all in one page exercises, the results will be // stored by exercise_results.php (using the session) if ($saved_results) { if ($debug) { error_log("Save question results {$saved_results}"); } if ($debug) { error_log(print_r($choice, 1)); } if (empty($choice)) { $choice = 0; } if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE || $answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { if ($choice != 0) { $reply = array_keys($choice); for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; Event::saveQuestionAttempt($questionScore, $ans . ':' . $choice[$ans], $quesId, $exeId, $i, $this->id); if ($debug) { error_log('result =>' . $questionScore . ' ' . $ans . ':' . $choice[$ans]); } } } else { Event::saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id); } } elseif ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { if ($choice != 0) { $reply = array_keys($choice); if ($debug) { error_log("reply " . print_r($reply, 1) . ""); } for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; Event::saveQuestionAttempt($questionScore, $ans, $quesId, $exeId, $i, $this->id); } } else { Event::saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id); } } elseif ($answerType == MULTIPLE_ANSWER_COMBINATION) { if ($choice != 0) { $reply = array_keys($choice); for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; Event::saveQuestionAttempt($questionScore, $ans, $quesId, $exeId, $i, $this->id); } } else { Event::saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id); } } elseif (in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE])) { if (isset($matching)) { foreach ($matching as $j => $val) { Event::saveQuestionAttempt($questionScore, $val, $quesId, $exeId, $j, $this->id); } } } elseif ($answerType == FREE_ANSWER) { $answer = $choice; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id); } elseif ($answerType == ORAL_EXPRESSION) { $answer = $choice; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $nano); } elseif (in_array($answerType, [UNIQUE_ANSWER, UNIQUE_ANSWER_IMAGE, UNIQUE_ANSWER_NO_OPTION])) { $answer = $choice; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id); // } elseif ($answerType == HOT_SPOT || $answerType == HOT_SPOT_DELINEATION) { } elseif ($answerType == HOT_SPOT) { $answer = []; if (isset($exerciseResultCoordinates[$questionId]) && !empty($exerciseResultCoordinates[$questionId])) { Database::delete(Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT), ['hotspot_exe_id = ? AND hotspot_question_id = ? AND c_id = ?' => [$exeId, $questionId, api_get_course_int_id()]]); foreach ($exerciseResultCoordinates[$questionId] as $idx => $val) { $answer[] = $val; Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, $choice[$idx], $val, false, $this->id); } } Event::saveQuestionAttempt($questionScore, implode('|', $answer), $quesId, $exeId, 0, $this->id); } else { Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id); } } if ($propagate_neg == 0 && $questionScore < 0) { $questionScore = 0; } if ($saved_results) { $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); $sql = 'UPDATE ' . $stat_table . ' SET exe_result = exe_result + ' . floatval($questionScore) . ' WHERE exe_id = ' . $exeId; if ($debug) { error_log($sql); } Database::query($sql); } $return_array = array('score' => $questionScore, 'weight' => $questionWeighting, 'extra' => $extra_data, 'open_question' => $arrques, 'open_answer' => $arrans, 'answer_type' => $answerType); return $return_array; }
/** * Function export last wiki page version to document area * @param int $doc_id wiki page id * * @author Juan Carlos Raña <*****@*****.**> */ public function export2doc($doc_id) { $_course = $this->courseInfo; $groupId = api_get_group_id(); $data = self::get_wiki_data($doc_id); if (empty($data)) { return false; } $wikiTitle = $data['title']; $wikiContents = $data['content']; $template = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{LANGUAGE}" lang="{LANGUAGE}"> <head> <title>{TITLE}</title> <meta http-equiv="Content-Type" content="text/html; charset={ENCODING}" /> <style type="text/css" media="screen, projection"> /*<![CDATA[*/ {CSS} /*]]>*/ </style> {ASCIIMATHML_SCRIPT}</head> <body dir="{TEXT_DIRECTION}"> {CONTENT} </body> </html>'; $css_file = api_get_path(TO_SYS, WEB_CSS_PATH) . api_get_setting('stylesheets') . '/default.css'; if (file_exists($css_file)) { $css = @file_get_contents($css_file); } else { $css = ''; } // Fixing some bugs in css files. $root_rel = api_get_path(REL_PATH); $css_path = 'main/css/'; $theme = api_get_setting('stylesheets') . '/'; $css = str_replace('behavior:url("/main/css/csshover3.htc");', '', $css); $css = str_replace('main/', $root_rel . 'main/', $css); $css = str_replace('images/', $root_rel . $css_path . $theme . 'images/', $css); $css = str_replace('../../img/', $root_rel . 'main/img/', $css); $asciimathmal_script = api_contains_asciimathml($wikiContents) || api_contains_asciisvg($wikiContents) ? '<script src="' . api_get_path(TO_REL, SCRIPT_ASCIIMATHML) . '" type="text/javascript"></script>' . "\n" : ''; $template = str_replace(array('{LANGUAGE}', '{ENCODING}', '{TEXT_DIRECTION}', '{TITLE}', '{CSS}', '{ASCIIMATHML_SCRIPT}'), array(api_get_language_isocode(), api_get_system_encoding(), api_get_text_direction(), $wikiTitle, $css, $asciimathmal_script), $template); if (0 != $groupId) { $groupPart = '_group' . $groupId; // and add groupId to put the same document title in different groups $group_properties = GroupManager::get_group_properties($groupId); $groupPath = $group_properties['directory']; } else { $groupPart = ''; $groupPath = ''; } $exportDir = api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/document' . $groupPath; $exportFile = api_replace_dangerous_char($wikiTitle) . $groupPart; $wikiContents = trim(preg_replace("/\\[[\\[]?([^\\]|]*)[|]?([^|\\]]*)\\][\\]]?/", "\$1", $wikiContents)); //TODO: put link instead of title $wikiContents = str_replace('{CONTENT}', $wikiContents, $template); // replace relative path by absolute path for courses, so you can see items into this page wiki (images, mp3, etc..) exported in documents if (api_strpos($wikiContents, '../../courses/') !== false) { $web_course_path = api_get_path(WEB_COURSE_PATH); $wikiContents = str_replace('../../courses/', $web_course_path, $wikiContents); } $i = 1; //only export last version, but in new export new version in document area while (file_exists($exportDir . '/' . $exportFile . '_' . $i . '.html')) { $i++; } $wikiFileName = $exportFile . '_' . $i . '.html'; $exportPath = $exportDir . '/' . $wikiFileName; file_put_contents($exportPath, $wikiContents); $doc_id = add_document($_course, $groupPath . '/' . $wikiFileName, 'file', filesize($exportPath), $wikiTitle); api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', api_get_user_id(), $groupId); return $doc_id; }
/** * Creates a username using person's names, i.e. creates jmontoya from Julio Montoya. * @param string $firstname The first name of the user. * @param string $lastname The last name of the user. * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then. * @param string $encoding (optional) The character encoding for the input names. If it is omitted, the platform character set will be used by default. * @return string Suggests a username that contains only ASCII-letters and digits, without check for uniqueness within the system. * @author Julio Montoya Armas * @author Ivan Tcholakov, 2009 - rework about internationalization. * @assert ('','') === false * @assert ('a','b') === 'ab' */ public static function create_username($firstname, $lastname, $language = null, $encoding = null) { if (empty($firstname) && empty($lastname)) { return false; } $firstname = api_substr(preg_replace(USERNAME_PURIFIER, '', $firstname), 0, 1); // The first letter only. //Looking for a space in the lastname $pos = api_strpos($lastname, ' '); if ($pos !== false) { $lastname = api_substr($lastname, 0, $pos); } $lastname = preg_replace(USERNAME_PURIFIER, '', $lastname); $username = $firstname . $lastname; if (empty($username)) { $username = '******'; } $username = URLify::transliterate($username); return strtolower(substr($username, 0, USERNAME_MAX_LENGTH - 3)); }
/** * Export the text with missing words. * * As a side effect, it stores two lists in the class : * the missing words and their respective weightings. */ function export() { global $charset; $js = ''; $html = '<tr><td colspan="2"><table width="100%">' . "\n"; // get all enclosed answers $blankList = array(); // build replacement $replacementList = array(); foreach ($this->answer as $i => $answer) { $blankList[] = '[' . $answer . ']'; } $answerCount = count($blankList); // splits text and weightings that are joined with the character '::' list($answer, $weight) = explode('::', $answer); $weights = explode(',', $weight); // because [] is parsed here we follow this procedure: // 1. find everything between the [ and ] tags $i = 1; $jstmp = ''; $jstmpc = ''; $jstmpw = 'questions_answers_ponderation[' . $this->questionJSId . '] = new Array();' . "\n"; $jstmpw .= 'questions_answers_ponderation[' . $this->questionJSId . '][0] = 0;' . "\n"; $startlocations = api_strpos($answer, '['); $endlocations = api_strpos($answer, ']'); while ($startlocations !== false && $endlocations !== false) { $texstring = api_substr($answer, $startlocations, $endlocations - $startlocations + 1); $answer = api_substr_replace($answer, '<input type="text" name="question_' . $this->questionJSId . '_fib_' . $i . '" id="question_' . $this->questionJSId . '_fib_' . $i . '" size="10" value="" />', $startlocations, $endlocations - $startlocations + 1); $jstmp .= $i . ','; $jstmpc .= "'" . api_htmlentities(api_substr($texstring, 1, -1), ENT_QUOTES, $charset) . "',"; $my_weight = explode('@', $weights[$i - 1]); if (count($my_weight) == 2) { $weight_db = $my_weight[0]; } else { $weight_db = $my_weight[0]; } $jstmpw .= 'questions_answers_ponderation[' . $this->questionJSId . '][' . $i . '] = ' . $weight_db . ";\n"; $i++; $startlocations = api_strpos($answer, '['); $endlocations = api_strpos($answer, ']'); } $html .= '<tr>' . "\n" . '<td>' . "\n" . $answer . "\n" . '</td>' . "\n" . '</tr>' . "\n"; $html .= '</table></td></tr>' . "\n"; $js .= 'questions_answers[' . $this->questionJSId . '] = new Array(' . api_substr($jstmp, 0, -1) . ');' . "\n"; $js .= 'questions_answers_correct[' . $this->questionJSId . '] = new Array(' . api_substr($jstmpc, 0, -1) . ');' . "\n"; $js .= 'questions_types[' . $this->questionJSId . '] = \'fib\';' . "\n"; $js .= $jstmpw; return array($js, $html); }
/** * Find evaluations by name * @param string $name_mask search string * @return array evaluation objects matching the search criterium * @todo can be written more efficiently using a new (but very complex) sql query */ public function find_evaluations($name_mask, $selectcat) { $rootcat = Category::load($selectcat); $evals = $rootcat[0]->get_evaluations(api_is_allowed_to_create_course() ? null : api_get_user_id(), true); $foundevals = array(); foreach ($evals as $eval) { if (!(api_strpos(api_strtolower($eval->get_name()), api_strtolower($name_mask)) === false)) { $foundevals[] = $eval; } } return $foundevals; }
/** * This function writes the imsmanifest.xml and exports the chapter names * @param array Array containing filenames * @param integer Learnpath_id * @return void */ function createimsmanifest($circle1_files, $learnpath_id) { global $LPname, $expdir, $LPnamesafe; $_course = api_get_course_info(); //$tbl_learnpath_main, $tbl_learnpath_chapter, $tbl_learnpath_item, $tbl_learnpath_main = Database::get_course_table(TABLE_LEARNPATH_MAIN); $tbl_learnpath_item = Database::get_course_table(TABLE_LEARNPATH_ITEM); $tbl_learnpath_chapter = Database::get_course_table(TABLE_LEARNPATH_CHAPTER); include_once '../metadata/md_funcs.php'; // RH: export metadata // Header // Charset should be dependent on content. $header = '<?xml version="1.0" encoding="' . api_get_system_encoding() . '"?>' . "\n<manifest identifier='" . $LPnamesafe . "' version='1.1'\n xmlns='http://www.imsproject.org/xsd/imscp_rootv1p1p2'\n xmlns:adlcp='http://www.adlnet.org/xsd/adlcp_rootv1p2'\n xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n xsi:schemaLocation='http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd\n http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd\n http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd'>\n"; $org = xmltagwrite('metadata', 'open'); $org .= ' ' . xmltagwrite('schema', 'full', 'ADL SCORM'); $org .= ' ' . xmltagwrite('schemaversion', 'full', '1.2'); $org .= xmltagwrite('metadata', 'close'); $defaultorgname = 'default_org'; $attributes[0][0] = 'default'; $attributes[1][0] = $defaultorgname; $org .= xmltagwrite('organizations', 'open', $attributes); $attributes[0][0] = 'identifier'; $attributes[1][0] = $defaultorgname; $org .= ' ' . xmltagwrite('organization', 'open', $attributes); $org .= ' ' . xmltagwrite('title', 'full', $LPname); // Items list. $i = 0; $course_id = api_get_course_int_id(); $previous_item_id = '00'; while ($circle1_files[0][$i]) { // Check whether we are in the border of two chapters. //if (!$desc=strpos($circle1_files[2][$i],'scription')) { // This is needed if the descriptions are exported to file. $sql = "SELECT * FROM {$tbl_learnpath_item} WHERE c_id = {$course_id} AND (id=" . $circle1_files[2][$i] . ")"; $result = Database::query($sql); $row = Database::fetch_array($result); $parent_item_id = $row['parent_item_id']; if ($parent_item_id != $previous_item_id) { // We create the item tag for the chapter (without indifierref). $sql2 = "SELECT * FROM {$tbl_learnpath_chapter} WHERE c_id = {$course_id} AND (id=" . $parent_item_id . ")"; $result2 = Database::query($sql2); $row2 = Database::fetch_array($result2); $chapter_name = $row2['chapter_name']; $attributes = ''; $attributes[0][] = 'identifier'; $attributes[1][] = 'chapter_' . $row2['id']; $attributes[0][] = 'isvisible'; $attributes[1][] = '1'; if ($previous_item_id != '00') { $org .= ' ' . xmltagwrite('item', 'close'); } $org .= ' ' . xmltagwrite('item', 'open', $attributes); $org .= ' ' . xmltagwrite('title', 'full', $chapter_name); if ($row2['chapter_description'] != '') { // Chapter description. $attributes = ''; $attributes[0][] = 'identifier'; $attributes[1][] = 'chapter_' . $row2['id'] . '_desc'; $attributes[0][] = 'isvisible'; $attributes[1][] = '1'; $org .= ' ' . xmltagwrite('item', 'open', $attributes); $org .= ' ' . xmltagwrite('title', 'full', ' ' . $row2['chapter_description']); $org .= ' ' . xmltagwrite('item', 'close'); } } $previous_item_id = $parent_item_id; //} $attributes = ''; // Item output. $attributes[0][] = 'identifier'; $attributes[1][] = 'item_' . $circle1_files[2][$i]; $attributes[0][] = 'identifierref'; $attributes[1][] = 'item_ref_' . $circle1_files[2][$i]; $attributes[0][] = 'isvisible'; $attributes[1][] = '1'; $org .= ' ' . xmltagwrite('item', 'open', $attributes); $org .= ' ' . xmltagwrite('title', 'full', $circle1_files[1][$i]); if ($row['prereq_id'] != '') { // Item prerequisites. $attributes = ''; $attributes[0][] = 'type'; $attributes[1][] = 'aicc_script'; $org .= ' ' . xmltagwrite('adlcp:prerequisites', 'open', $attributes, 'no_linebreak'); if ($row['prereq_type'] == 'i') { $org .= 'item_' . $row['prereq_id']; } if ($row['prereq_type'] == 'c') { $org .= 'chapter_' . $row['prereq_id']; } $org .= xmltagwrite('adlcp:prerequisites', 'close', $attributes); } if ($row['description'] != '') { // Item description. $attributes = ''; $attributes[0][] = 'identifier'; $attributes[1][] = 'item_' . $circle1_files[2][$i] . '_desc'; $attributes[0][] = 'isvisible'; $attributes[1][] = '1'; $org .= ' ' . xmltagwrite('item', 'open', $attributes); $org .= ' ' . xmltagwrite('title', 'full', ' ' . $row['description']); $org .= ' ' . xmltagwrite('item', 'close'); } $mds = new mdstore(true); // RH: export metadata; if no table, create it if ($mdt = $mds->mds_get($row['item_type'] . '.' . $row['item_id'])) { if (($mdo = api_strpos($mdt, '<metadata>')) && ($mdc = api_strpos($mdt, '</metadata>'))) { $org .= ' ' . api_substr($mdt, $mdo, $mdc - $mdo + 11) . "\n"; } } $org .= ' ' . xmltagwrite('item', 'close'); $i++; } if ($circle1_files) { $org .= ' ' . xmltagwrite('item', 'close'); } // Not needed in case of a blank path. $org .= ' ' . xmltagwrite('organization', 'close'); $org .= xmltagwrite('organizations', 'close'); $org .= xmltagwrite('resources', 'open'); // Resources list. $i = 0; while ($circle1_files[0][$i]) { $attributes = ''; $attributes[0][] = 'identifier'; $attributes[1][] = 'item_ref_' . $circle1_files[2][$i]; $attributes[0][] = 'type'; $attributes[1][] = 'webcontent'; $attributes[0][] = 'adlcp:scormtype'; $attributes[1][] = 'sco'; $attributes[0][] = 'href'; $attributes[1][] = $circle1_files[0][$i]; $org .= ' ' . xmltagwrite('resource', 'open', $attributes); $org .= ' ' . xmltagwrite('metadata', 'open'); $org .= ' ' . xmltagwrite('schema', 'full', 'ADL SCORM'); $org .= ' ' . xmltagwrite('schemaversion', 'full', '1.2'); $org .= ' ' . xmltagwrite('metadata', 'close'); $attributes = ''; $attributes[0][] = 'href'; $attributes[1][] = $circle1_files[0][$i]; $org .= ' ' . xmltagwrite('file', 'open', $attributes); $org .= ' ' . xmltagwrite('resource', 'close'); $i++; } $org .= xmltagwrite('resources', 'close'); $org .= xmltagwrite('manifest', 'close'); $manifest = $header . $org; exporttofile('imsmanifest.xml', 'Manifest file', '0', $manifest); }
/** * Manages chapter splitting * @param string Chapter header * @param string Content * @return void */ function dealPerChapter($header, $content) { $_course = api_get_course_info(); $content = str_replace('||page_break||', '', $content); // Get all the h1. preg_match_all("|<h1[^>]*>([^(h1)+]*)</h1>|is", $content, $matches_temp); // Empty the fake chapters. $new_index = 0; for ($i = 0; $i < count($matches_temp[0]); $i++) { if (trim($matches_temp[1][$i]) !== '') { $matches[0][$new_index] = $matches_temp[0][$i]; $matches[1][$new_index] = $matches_temp[1][$i]; $new_index++; } } // Add intro item. $intro_content = api_substr($content, 0, api_strpos($content, $matches[0][0])); $items_to_create[get_lang('Introduction')] = $intro_content; for ($i = 0; $i < count($matches[0]); $i++) { if (empty($matches[1][$i])) { continue; } $content = api_strstr($content, $matches[0][$i]); if ($i + 1 !== count($matches[0])) { $chapter_content = api_substr($content, 0, api_strpos($content, $matches[0][$i + 1])); } else { $chapter_content = $content; } $items_to_create[$matches[1][$i]] = $chapter_content; } $i = 0; foreach ($items_to_create as $item_title => $item_content) { $i++; $page_content = $this->format_page_content($header, $item_content); $html_file = $this->created_dir . '-' . $i . '.html'; $handle = fopen($this->base_work_dir . $this->created_dir . '/' . $html_file, 'w+'); fwrite($handle, $page_content); fclose($handle); $document_id = add_document($_course, $this->created_dir . '/' . $html_file, 'file', filesize($this->base_work_dir . $this->created_dir . '/' . $html_file), $html_file); if ($document_id) { // Put the document in item_property update. api_item_property_update($_course, TOOL_DOCUMENT, $document_id, 'DocumentAdded', $_SESSION['_uid'], 0, 0, null, null, api_get_session_id()); $infos = pathinfo($this->filepath); $slide_name = strip_tags(nl2br($item_title)); $slide_name = str_replace(array("\r\n", "\r", "\n"), '', $slide_name); $slide_name = api_html_entity_decode($slide_name, ENT_COMPAT, api_get_system_encoding()); $previous = learnpath::add_item(0, $previous, 'document', $document_id, $slide_name, ''); if ($this->first_item == 0) { $this->first_item = $previous; } } } }
/** * This function stores a survey in the database. * * @param array $values * * @return array $return the type of return message that has to be displayed and the message in it * * @author Patrick Cool <*****@*****.**>, Ghent University * @version February 2007 */ public static function store_survey($values) { $_user = api_get_user_info(); $course_id = api_get_course_int_id(); $table_survey = Database::get_course_table(TABLE_SURVEY); $shared_survey_id = 0; if (!isset($values['survey_id'])) { // Check if the code doesn't soon exists in this language $sql = 'SELECT 1 FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND code="' . Database::escape_string($values['survey_code']) . '" AND lang="' . Database::escape_string($values['survey_language']) . '"'; $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { $return['message'] = 'ThisSurveyCodeSoonExistsInThisLanguage'; $return['type'] = 'error'; $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; return $return; } if (!isset($values['anonymous'])) { $values['anonymous'] = 0; } $values['anonymous'] = intval($values['anonymous']); $additional['columns'] = ''; $extraParams = []; if ($values['anonymous'] == 0) { // Input_name_list $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0; $extraParams['show_form_profile'] = $values['show_form_profile']; if ($values['show_form_profile'] == 1) { // Input_name_list $fields = explode(',', $values['input_name_list']); $field_values = ''; foreach ($fields as &$field) { if ($field != '') { if ($values[$field] == '') { $values[$field] = 0; } $field_values .= $field . ':' . $values[$field] . '@'; } } $extraParams['form_fields'] = $field_values; } else { $extraParams['form_fields'] = ''; } } else { // Input_name_list $extraParams['show_form_profile'] = 0; $extraParams['form_fields'] = ''; } if ($values['survey_type'] == 1) { $extraParams['survey_type'] = 1; $extraParams['shuffle'] = $values['shuffle']; $extraParams['one_question_per_page'] = $values['one_question_per_page']; $extraParams['parent_id'] = $values['parent_id']; // Logic for versioning surveys if (!empty($values['parent_id'])) { $versionValue = ''; $sql = 'SELECT survey_version FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND parent_id = ' . intval($values['parent_id']) . ' ORDER BY survey_version DESC LIMIT 1'; $rs = Database::query($sql); if (Database::num_rows($rs) === 0) { $sql = 'SELECT survey_version FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND survey_id = ' . intval($values['parent_id']); $rs = Database::query($sql); $getversion = Database::fetch_array($rs, 'ASSOC'); if (empty($getversion['survey_version'])) { $versionValue = ++$getversion['survey_version']; } else { $versionValue = $getversion['survey_version']; } } else { $row = Database::fetch_array($rs, 'ASSOC'); $pos = api_strpos($row['survey_version']); if ($pos === false) { $row['survey_version'] = $row['survey_version'] + 1; $versionValue = $row['survey_version']; } else { $getlast = explode('\\.', $row['survey_version']); $lastversion = array_pop($getlast); $lastversion = $lastversion + 1; $add = implode('.', $getlast); if ($add != '') { $insertnewversion = $add . '.' . $lastversion; } else { $insertnewversion = $lastversion; } $versionValue = $insertnewversion; } } $extraParams['survey_version'] = $versionValue; } } $course_id = api_get_course_int_id(); $params = ['c_id' => $course_id, 'code' => strtolower(CourseManager::generate_course_code($values['survey_code'])), 'title' => $values['survey_title'], 'subtitle' => $values['survey_subtitle'], 'author' => $_user['user_id'], 'lang' => $values['survey_language'], 'avail_from' => $values['start_date'], 'avail_till' => $values['end_date'], 'is_shared' => $shared_survey_id, 'template' => 'template', 'intro' => $values['survey_introduction'], 'surveythanks' => $values['survey_thanks'], 'creation_date' => api_get_utc_datetime(), 'anonymous' => $values['anonymous'], 'session_id' => api_get_session_id(), 'visible_results' => $values['visible_results']]; $params = array_merge($params, $extraParams); $survey_id = Database::insert($table_survey, $params); if ($survey_id > 0) { $sql = "UPDATE {$table_survey} SET survey_id = {$survey_id}\n WHERE iid = {$survey_id}"; Database::query($sql); // Insert into item_property api_item_property_update(api_get_course_info(), TOOL_SURVEY, $survey_id, 'SurveyAdded', api_get_user_id()); } if ($values['survey_type'] == 1 && !empty($values['parent_id'])) { SurveyManager::copy_survey($values['parent_id'], $survey_id); } $return['message'] = 'SurveyCreatedSuccesfully'; $return['type'] = 'confirmation'; $return['id'] = $survey_id; } else { // Check whether the code doesn't soon exists in this language $sql = 'SELECT 1 FROM ' . $table_survey . ' WHERE c_id = ' . $course_id . ' AND code = "' . Database::escape_string($values['survey_code']) . '" AND lang = "' . Database::escape_string($values['survey_language']) . '" AND survey_id !=' . intval($values['survey_id']); $rs = Database::query($sql); if (Database::num_rows($rs) > 0) { $return['message'] = 'ThisSurveyCodeSoonExistsInThisLanguage'; $return['type'] = 'error'; $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0; return $return; } if (!isset($values['anonymous']) || isset($values['anonymous']) && $values['anonymous'] == '') { $values['anonymous'] = 0; } $values['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : null; $values['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : null; $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : null; $extraParams = []; $extraParams['shuffle'] = $values['shuffle']; $extraParams['one_question_per_page'] = $values['one_question_per_page']; $extraParams['shuffle'] = $values['shuffle']; if ($values['anonymous'] == 0) { $extraParams['show_form_profile'] = $values['show_form_profile']; if ($values['show_form_profile'] == 1) { $fields = explode(',', $values['input_name_list']); $field_values = ''; foreach ($fields as &$field) { if ($field != '') { if (!isset($values[$field]) || isset($values[$field]) && $values[$field] == '') { $values[$field] = 0; } $field_values .= $field . ':' . $values[$field] . '@'; } } $extraParams['form_fields'] = $field_values; } else { $extraParams['form_fields'] = ''; } } else { $extraParams['show_form_profile'] = 0; $extraParams['form_fields'] = ''; } $params = ['title' => $values['survey_title'], 'subtitle' => $values['survey_subtitle'], 'author' => $_user['user_id'], 'lang' => $values['survey_language'], 'avail_from' => $values['start_date'], 'avail_till' => $values['end_date'], 'is_shared' => $shared_survey_id, 'template' => 'template', 'intro' => $values['survey_introduction'], 'surveythanks' => $values['survey_thanks'], 'anonymous' => $values['anonymous'], 'session_id' => api_get_session_id(), 'visible_results' => $values['visible_results']]; $params = array_merge($params, $extraParams); Database::update($table_survey, $params, ['c_id = ? AND survey_id = ?' => [$course_id, $values['survey_id']]]); // Update into item_property (update) api_item_property_update(api_get_course_info(), TOOL_SURVEY, $values['survey_id'], 'SurveyUpdated', api_get_user_id()); $return['message'] = 'SurveyUpdatedSuccesfully'; $return['type'] = 'confirmation'; $return['id'] = $values['survey_id']; } return $return; }