/** * Edits a question for the question manager * * @param Application $app * @param int $id * @return Response */ public function editQuestionAction(Application $app, $id) { $extraJS = array(); //@todo improve this JS includes should be added using twig $extraJS[] = '<link href="' . api_get_path(WEB_LIBRARY_PATH) . 'javascript/tag/style.css" rel="stylesheet" type="text/css" />'; $extraJS[] = '<script src="' . api_get_path(WEB_LIBRARY_PATH) . 'javascript/tag/jquery.fcbkcomplete.js" type="text/javascript" language="javascript"></script>'; $app['extraJS'] = $extraJS; // Setting exercise obj. $exercise = new \Exercise(); $exercise->edit_exercise_in_lp = true; // Setting question obj. /** @var \Question $question */ $question = \Question::read($id, null, $exercise); $question->submitClass = "btn save"; $question->submitText = get_lang('ModifyQuestion'); $question->setDefaultValues = true; // Generating edit URL. $url = $app['url_generator']->generate('admin_questions_edit', array('id' => $id)); // Creating a new form $form = new \FormValidator('edit_question', 'post', $url); $extraFields = new \ExtraField('question'); $extraFields->addElements($form, $id); // Validating if there are extra fields to modify. if (count($form->_elements) > 1) { $form->addElement('button', 'submit', get_lang('Update')); $app['template']->assign('question', $question); $app['template']->assign('form', $form->toHtml()); } else { $app['template']->assign('message', \Display::return_message(get_lang('ThereAreNotExtrafieldsAvailable'), 'warning')); } // If form was submitted. if ($form->validate()) { $field_value = new \ExtraFieldValue('question'); $params = $form->exportValues(); $params['question_id'] = $id; $field_value->save_field_values($params); $app['template']->assign('message', \Display::return_message(get_lang('ItemUpdated'), 'success')); $url = $app['url_generator']->generate('admin_questions_edit', array('id' => $id)); return $app->redirect($url); } $response = $app['template']->render_template('admin/questionmanager/edit_question.tpl'); return new Response($response, 200, array()); }
/** * Edits a question for the question manager * * @Route("/edit") * @Method({"GET"}) * @param int $id * @return Response */ public function editQuestionAction($id) { // Setting exercise obj. $exercise = new \Exercise(); $exercise->edit_exercise_in_lp = true; // Setting question obj. /** @var \Question $question */ $question = \Question::read($id, null, $exercise); $question->submitClass = "btn save"; $question->submitText = get_lang('ModifyQuestion'); $question->setDefaultValues = true; // Generating edit URL. $url = $this->generateControllerUrl('editQuestionAction', array('id' => $id)); // Creating a new form $form = new \FormValidator('edit_question', 'post', $url); $extraFields = new \ExtraField('question'); $extraFields->addElements($form, $id); // Validating if there are extra fields to modify. if (count($form->_elements) > 1) { $form->addElement('button', 'submit', get_lang('Update')); $this->getTemplate()->assign('question', $question); $this->getTemplate()->assign('form', $form->toHtml()); } else { $this->addFlash('warning', get_lang('ThereAreNotExtrafieldsAvailable')); } // If form was submitted. if ($form->validate()) { $field_value = new \ExtraFieldValue('question'); $params = $form->exportValues(); $params['question_id'] = $id; $field_value->save_field_values($params); $this->addFlash('success', get_lang('ItemUpdated')); $url = $this->generateControllerUrl('editQuestionAction', array('id' => $id)); return $this->redirect($url); } $response = $this->renderTemplate('edit_question.tpl'); return new Response($response, 200, array()); }
foreach ($row_table as $cell) { $table->setCellContents($row, $column, $cell); $table->updateCellAttributes($row, $column, 'align="center"'); $column++; } $table->updateRowAttributes($row, $row % 2 ? 'class="row_even"' : 'class="row_odd"', true); $row++; } $content = $table->toHtml(); // Format B $headers = array(get_lang('Question'), get_lang('Answer'), get_lang('Correct'), get_lang('NumberStudentWhoSelectedIt')); $data = array(); if (!empty($question_list)) { $id = 0; foreach ($question_list as $question_id) { $question_obj = Question::read($question_id); $exercise_stats = get_student_stats_by_question($question_id, $exercise_id, $courseCode, $sessionId); $answer = new Answer($question_id); $answer_count = $answer->selectNbrAnswers(); for ($answer_id = 1; $answer_id <= $answer_count; $answer_id++) { $answer_info = $answer->selectAnswer($answer_id); $is_correct = $answer->isCorrect($answer_id); $correct_answer = $is_correct == 1 ? get_lang('Yes') : get_lang('No'); $real_answer_id = $answer->selectAutoId($answer_id); // Overwriting values depending of the question switch ($question_obj->type) { case FILL_IN_BLANKS: $answer_info_db = $answer_info; $answer_info = substr($answer_info, 0, strpos($answer_info, '::')); $correct_answer = $is_correct; $answers = $objExercise->fill_in_blank_answer_to_array($answer_info);
/** * @Route("/score-attempt/{exeId}/jury/{juryId}") * @Method({"GET"}) */ public function scoreAttemptAction($exeId, $juryId) { $userId = $this->getUser()->getUserId(); $trackExercise = \ExerciseLib::get_exercise_track_exercise_info($exeId); if (empty($trackExercise)) { $this->createNotFoundException(); } /** @var \Chamilo\CoreBundle\Entity\Jury $jury */ $jury = $this->getRepository()->find($juryId); if (empty($jury)) { $this->createNotFoundException('Jury does not exists'); } if ($jury->getExerciseId() != $trackExercise['exe_exo_id']) { $this->createNotFoundException('Exercise attempt is not related with this jury.'); } $members = $jury->getMembers(); $criteria = Criteria::create()->where(Criteria::expr()->eq("userId", $userId))->setFirstResult(0)->setMaxResults(1); /** @var JuryMembers $member */ $member = $members->matching($criteria)->first(); if (empty($member)) { $this->createNotFoundException('You are not part of the jury.'); } $students = $member->getStudents(); $criteria = Criteria::create()->where(Criteria::expr()->eq("userId", $trackExercise['exe_user_id']))->setFirstResult(0)->setMaxResults(1); /** @var JuryMembers $member */ $student = $students->matching($criteria)->first(); if (empty($student)) { $this->createNotFoundException('You are not assigned to this user.'); } // Setting member only for president. if ($this->isGranted('ROLE_JURY_PRESIDENT')) { // Relating user with president if ($member) { $this->getManager()->getRepository('Chamilo\\CoreBundle\\Entity\\JuryMembers')->assignUserToJuryMember($trackExercise['exe_user_id'], $member->getId()); } } $questionScoreTypeModel = array(); $criteria = array('exeId' => $exeId, 'juryUserId' => $userId); $trackJury = $this->getManager()->getRepository('Chamilo\\CoreBundle\\Entity\\TrackAttemptJury')->findBy($criteria); if ($trackJury) { $this->get('session')->getFlashBag()->add('info', "You already review this exercise attempt."); /** @var TrackAttemptJury $track */ foreach ($trackJury as $track) { $questionScoreTypeModel[$track->getQuestionId()] = $track->getQuestionScoreNameId(); } } $questionList = explode(',', $trackExercise['data_tracking']); $exerciseResult = \ExerciseLib::getExerciseResult($trackExercise); $counter = 1; $objExercise = new \Exercise($trackExercise['c_id']); $objExercise->read($trackExercise['exe_exo_id']); $totalScore = $totalWeighting = 0; $show_media = true; $tempParentId = null; $mediaCounter = 0; $media_list = array(); $modelType = $objExercise->getScoreTypeModel(); $options = array(); if ($modelType) { /** @var \Chamilo\CoreBundle\Entity\QuestionScore $questionScoreName */ $questionScore = $this->get('orm.em')->getRepository('Chamilo\\CoreBundle\\Entity\\QuestionScore')->find($modelType); if ($questionScore) { $items = $questionScore->getItems(); /** @var \Chamilo\CoreBundle\Entity\QuestionScoreName $score */ foreach ($items as $score) { $options[$score->getId() . ':' . $score->getScore()] = $score; } } } else { return $this->createNotFoundException('The exercise does not contain a model type.'); } $exerciseContent = null; foreach ($questionList as $questionId) { ob_start(); $choice = isset($exerciseResult[$questionId]) ? $exerciseResult[$questionId] : null; // Creates a temporary Question object /** @var \Question $objQuestionTmp */ $objQuestionTmp = \Question::read($questionId); if ($objQuestionTmp->parent_id != 0) { if (!in_array($objQuestionTmp->parent_id, $media_list)) { $media_list[] = $objQuestionTmp->parent_id; $show_media = true; } if ($tempParentId == $objQuestionTmp->parent_id) { $mediaCounter++; } else { $mediaCounter = 0; } $counterToShow = chr(97 + $mediaCounter); $tempParentId = $objQuestionTmp->parent_id; } $questionWeighting = $objQuestionTmp->selectWeighting(); $answerType = $objQuestionTmp->selectType(); $question_result = $objExercise->manageAnswers($exeId, $questionId, $choice, 'exercise_show', array(), false, true, true); $questionScore = $question_result['score']; $totalScore += $question_result['score']; $my_total_score = $questionScore; $my_total_weight = $questionWeighting; $totalWeighting += $questionWeighting; $score = array(); $score['result'] = get_lang('Score') . " : " . \ExerciseLib::show_score($my_total_score, $my_total_weight, false, false); $score['pass'] = $my_total_score >= $my_total_weight ? true : false; $score['type'] = $answerType; $score['score'] = $my_total_score; $score['weight'] = $my_total_weight; $score['comments'] = isset($comnt) ? $comnt : null; $contents = ob_get_clean(); $question_content = '<div class="question_row">'; $question_content .= $objQuestionTmp->return_header($objExercise->feedback_type, $counter, $score, $show_media, $mediaCounter); $question_content .= '</table>'; // display question category, if any $question_content .= \Testcategory::getCategoryNamesForQuestion($questionId); $question_content .= $contents; $defaultValue = isset($questionScoreTypeModel[$questionId]) ? $questionScoreTypeModel[$questionId] : null; //$question_content .= \Display::select('options['.$questionId.']', $options, $defaultValue); foreach ($options as $value => $score) { $attributes = array(); if ($score->getId() == $defaultValue) { $attributes = array('checked' => 'checked'); } $question_content .= '<label>'; $question_content .= \Display::input('radio', 'options[' . $questionId . ']', $value, $attributes) . ' <span title="' . $score->getDescription() . '" data-toggle="tooltip" > ' . $score->getName() . ' </span>'; $question_content .= '</label>'; } $question_content .= '</div>'; $exerciseContent .= $question_content; $counter++; } $template = $this->get('template'); $template->assign('exercise', $exerciseContent); $template->assign('exe_id', $exeId); $template->assign('jury_id', $juryId); $response = $this->get('template')->render_template($this->getTemplatePath() . 'score_attempt.tpl'); return new Response($response, 200, array()); }
$objQuestionTmp = new Question(); // if the question exists if ($objQuestionTmp->read($delete)) { // deletes the question from all exercises $objQuestionTmp->delete(); } // destruction of the Question object unset($objQuestionTmp); //Session::set_flashdata($message, $class); redirect_to_home_page("modules/exercise/question_pool.php?course={$course_code}" . (isset($fromExercise) ? "&fromExercise={$fromExercise}" : "") . "&exerciseId={$exerciseId}"); } elseif (isset($_GET['recup']) && isset($fromExercise)) { $recup = intval($_GET['recup']); // construction of the Question object $objQuestionTmp = new Question(); // if the question exists if ($objQuestionTmp->read($recup)) { // adds the exercise ID into the list of exercises for the current question $objQuestionTmp->addToList($fromExercise); } // destruction of the Question object unset($objQuestionTmp); // adds the question ID into the list of questions for the current exercise $objExercise->addToList($recup); Session::Messages($langQuestionReused, 'alert-success'); redirect_to_home_page("modules/exercise/question_pool.php?course={$course_code}" . (isset($fromExercise) ? "&fromExercise={$fromExercise}" : "") . "&exerciseId={$exerciseId}"); } if (isset($fromExercise)) { $action_bar_options[] = array('title' => $langGoBackToEx, 'url' => "admin.php?course={$course_code}&exerciseId={$fromExercise}", 'icon' => 'fa-reply', 'level' => 'primary-label'); } else { $action_bar_options = array(array('title' => $langNewQu, 'url' => "admin.php?course={$course_code}&newQuestion=yes", 'icon' => 'fa-plus-circle', 'level' => 'primary-label', 'button-class' => 'btn-success'), array('title' => $langImportQTI, 'url' => "admin.php?course={$course_code}&importIMSQTI=yes", 'icon' => 'fa-download', 'level' => 'primary-label', 'button-class' => 'btn-success'), array('title' => $langExportQTI, 'url' => "question_pool.php?" . $_SERVER['QUERY_STRING'] . "&exportIMSQTI=yes", 'icon' => 'fa-upload', 'level' => 'primary-label', 'button-class' => 'btn-success')); }
/** * function which redefines Question::createAnswersForm * @param FormValidator $form */ public function createAnswersForm($form) { // Getting the exercise list $obj_ex = $_SESSION['objExercise']; $editor_config = array('ToolbarSet' => 'TestProposedAnswer', 'Width' => '100%', 'Height' => '125'); //this line defines how many questions by default appear when creating a choice question // The previous default value was 2. See task #1759. $nb_answers = isset($_POST['nb_answers']) ? (int) $_POST['nb_answers'] : 4; $nb_answers += isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0); /* Types of Feedback $feedback_option[0]=get_lang('Feedback'); $feedback_option[1]=get_lang('DirectFeedback'); $feedback_option[2]=get_lang('NoFeedback'); */ $feedback_title = ''; if ($obj_ex->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) { //Scenario $editor_config['Width'] = '250'; $editor_config['Height'] = '110'; $comment_title = '<th width="500px" >' . get_lang('Comment') . '</th>'; $feedback_title = '<th width="350px" >' . get_lang('Scenario') . '</th>'; } else { $comment_title = '<th>' . get_lang('Comment') . '</th>'; } $html = '<table class="data_table"> <tr style="text-align: center;"> <th width="10px"> ' . get_lang('Number') . ' </th> <th width="10px" > ' . get_lang('True') . ' </th> <th width="50%"> ' . get_lang('Answer') . ' </th> ' . $comment_title . ' ' . $feedback_title . ' <th width="50px"> ' . get_lang('Weighting') . ' </th> </tr>'; $form->addElement('label', get_lang('Answers') . '<br /> <img src="../img/fill_field.png">', $html); $defaults = array(); $correct = 0; if (!empty($this->id)) { $answer = new Answer($this->id); $answer->read(); if (count($answer->nbrAnswers) > 0 && !$form->isSubmitted()) { $nb_answers = $answer->nbrAnswers; } } $form->addElement('hidden', 'nb_answers'); //Feedback SELECT $question_list = $obj_ex->selectQuestionList(); $select_question = array(); $select_question[0] = get_lang('SelectTargetQuestion'); require_once '../newscorm/learnpathList.class.php'; if (is_array($question_list)) { foreach ($question_list as $key => $questionid) { //To avoid warning messages if (!is_numeric($questionid)) { continue; } $question = Question::read($questionid); $select_question[$questionid] = 'Q' . $key . ' :' . cut($question->selectTitle(), 20); } } $select_question[-1] = get_lang('ExitTest'); $list = new LearnpathList(api_get_user_id()); $flat_list = $list->get_flat_list(); $select_lp_id = array(); $select_lp_id[0] = get_lang('SelectTargetLP'); foreach ($flat_list as $id => $details) { $select_lp_id[$id] = cut($details['lp_name'], 20); } $temp_scenario = array(); if ($nb_answers < 1) { $nb_answers = 1; Display::display_normal_message(get_lang('YouHaveToCreateAtLeastOneAnswer')); } for ($i = 1; $i <= $nb_answers; ++$i) { $form->addElement('html', '<tr>'); if (isset($answer) && is_object($answer)) { if ($answer->correct[$i]) { $correct = $i; } $defaults['answer[' . $i . ']'] = $answer->answer[$i]; $defaults['comment[' . $i . ']'] = $answer->comment[$i]; $defaults['weighting[' . $i . ']'] = float_format($answer->weighting[$i], 1); $item_list = explode('@@', $answer->destination[$i]); $try = $item_list[0]; $lp = $item_list[1]; $list_dest = $item_list[2]; $url = $item_list[3]; if ($try == 0) { $try_result = 0; } else { $try_result = 1; } if ($url == 0) { $url_result = ''; } else { $url_result = $url; } $temp_scenario['url' . $i] = $url_result; $temp_scenario['try' . $i] = $try_result; $temp_scenario['lp' . $i] = $lp; $temp_scenario['destination' . $i] = $list_dest; } else { $defaults['answer[1]'] = get_lang('DefaultUniqueAnswer1'); $defaults['weighting[1]'] = 10; $defaults['answer[2]'] = get_lang('DefaultUniqueAnswer2'); $defaults['weighting[2]'] = 0; $temp_scenario['destination' . $i] = array('0'); $temp_scenario['lp' . $i] = array('0'); } $defaults['scenario'] = $temp_scenario; $renderer = $form->defaultRenderer(); $renderer->setElementTemplate('<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>', 'correct'); $renderer->setElementTemplate('<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>', 'counter[' . $i . ']'); $renderer->setElementTemplate('<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>', 'answer[' . $i . ']'); $renderer->setElementTemplate('<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>', 'comment[' . $i . ']'); $renderer->setElementTemplate('<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>', 'weighting[' . $i . ']'); $answer_number = $form->addElement('text', 'counter[' . $i . ']', null, ' value = "' . $i . '"'); $answer_number->freeze(); $form->addElement('radio', 'correct', null, null, $i, 'class="checkbox" style="margin-left: 0em;"'); $form->addElement('html_editor', 'answer[' . $i . ']', null, 'style="vertical-align:middle"', $editor_config); $form->addRule('answer[' . $i . ']', get_lang('ThisFieldIsRequired'), 'required'); if ($obj_ex->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_DIRECT) { $form->addElement('html_editor', 'comment[' . $i . ']', null, 'style="vertical-align:middle"', $editor_config); // Direct feedback //Adding extra feedback fields $group = array(); $group['try' . $i] = $form->createElement('checkbox', 'try' . $i, null, get_lang('TryAgain')); $group['lp' . $i] = $form->createElement('select', 'lp' . $i, get_lang('SeeTheory') . ': ', $select_lp_id); $group['destination' . $i] = $form->createElement('select', 'destination' . $i, get_lang('GoToQuestion') . ': ', $select_question); $group['url' . $i] = $form->createElement('text', 'url' . $i, get_lang('Other') . ': ', array('class' => 'span2', 'placeholder' => get_lang('Other'))); $form->addGroup($group, 'scenario'); $renderer->setElementTemplate('<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}', 'scenario'); } else { $form->addElement('html_editor', 'comment[' . $i . ']', null, 'style="vertical-align:middle"', $editor_config); } $form->addElement('text', 'weighting[' . $i . ']', null, array('class' => "span1", 'value' => '0')); $form->addElement('html', '</tr>'); } $form->addElement('html', '</table>'); $form->addElement('html', '<br />'); $navigator_info = api_get_navigator(); global $text, $class; //ie6 fix if ($obj_ex->edit_exercise_in_lp == true) { if ($navigator_info['name'] == 'Internet Explorer' && $navigator_info['version'] == '6') { $form->addElement('submit', 'lessAnswers', get_lang('LessAnswer'), 'class="btn minus"'); $form->addElement('submit', 'moreAnswers', get_lang('PlusAnswer'), 'class="btn plus"'); $form->addElement('submit', 'submitQuestion', $text, 'class="' . $class . '"'); } else { //setting the save button here and not in the question class.php $form->addElement('style_submit_button', 'lessAnswers', get_lang('LessAnswer'), 'class="btn minus"'); $form->addElement('style_submit_button', 'moreAnswers', get_lang('PlusAnswer'), 'class="btn plus"'); $form->addElement('style_submit_button', 'submitQuestion', $text, 'class="' . $class . '"'); } } $renderer->setElementTemplate('{element} ', 'submitQuestion'); $renderer->setElementTemplate('{element} ', 'lessAnswers'); $renderer->setElementTemplate('{element} ', 'moreAnswers'); $form->addElement('html', '</div></div>'); // We check the first radio button to be sure a radio button will be check if ($correct == 0) { $correct = 1; } $defaults['correct'] = $correct; if (!empty($this->id)) { $form->setDefaults($defaults); } else { if ($this->isContent == 1) { // Default sample content. $form->setDefaults($defaults); } else { $form->setDefaults(array('correct' => 1)); } } $form->setConstants(array('nb_answers' => $nb_answers)); }
$form->setDefaults(array('course_code' => (string) $course_code)); $course_info = api_get_course_info($course_code); if (!empty($course_info)) { $list = new LearnpathList('', $course_code); $lp_list = $list->get_flat_list(); $_course = $course_info; $main_question_list = array(); foreach ($lp_list as $lp_id => $lp) { $exercise_list = ExerciseLib::get_all_exercises_from_lp($lp_id, $course_info['real_id']); foreach ($exercise_list as $exercise) { $my_exercise = new Exercise(); $my_exercise->read($exercise['path']); $question_list = $my_exercise->selectQuestionList(); $exercise_stats = get_all_exercise_event_from_lp($exercise['path'], $course_info['real_id'], $session_id); foreach ($question_list as $question_id) { $question_data = Question::read($question_id); $main_question_list[$question_id] = $question_data; $quantity_exercises = 0; $question_result = 0; foreach ($exercise_stats as $stats) { if (!empty($stats['question_list'])) { foreach ($stats['question_list'] as $my_question_stat) { if ($question_id == $my_question_stat['question_id']) { $question_result = $question_result + $my_question_stat['marks']; $quantity_exercises++; } } } } if (!empty($quantity_exercises)) { $main_question_list[$question_id]->results = $question_result / $quantity_exercises;
/** * Calculate the max_score of the quiz, depending of question inside, and quiz advanced option */ public function get_max_score() { $out_max_score = 0; $tab_question_list = $this->selectQuestionList(true); // list of question's id !!! the array key start at 1 !!! // test is randomQuestions - see field random of test if ($this->random > 0 && $this->randomByCat == 0) { $nb_random_questions = $this->random; $tab_questions_score = array(); for ($i = 1; $i <= count($tab_question_list); $i++) { $tmpobj_question = Question::read($tab_question_list[$i]); $tab_questions_score[] = $tmpobj_question->weighting; } rsort($tab_questions_score); // add the first $nb_random_questions value of score array to get max_score for ($i = 0; $i < min($nb_random_questions, count($tab_questions_score)); $i++) { $out_max_score += $tab_questions_score[$i]; } } else { if ($this->random > 0 && $this->randomByCat > 0) { $nb_random_questions = $this->random; $tab_categories_scores = array(); for ($i = 1; $i <= count($tab_question_list); $i++) { $question_category_id = TestCategory::getCategoryForQuestion($tab_question_list[$i]); if (!is_array($tab_categories_scores[$question_category_id])) { $tab_categories_scores[$question_category_id] = array(); } $tmpobj_question = Question::read($tab_question_list[$i]); $tab_categories_scores[$question_category_id][] = $tmpobj_question->weighting; } // here we've got an array with first key, the category_id, second key, score of question for this cat while (list($key, $tab_scores) = each($tab_categories_scores)) { rsort($tab_scores); for ($i = 0; $i < min($nb_random_questions, count($tab_scores)); $i++) { $out_max_score += $tab_scores[$i]; } } } else { for ($i = 1; $i <= count($tab_question_list); $i++) { $tmpobj_question = Question::read($tab_question_list[$i]); $out_max_score += $tmpobj_question->weighting; } } } return $out_max_score; }
// probaloume th dikia mas forma me to diko mas action // kai me to katallhlo hidden pedio echo "<form method='GET' action='backFromExercise.php'><input type='hidden' name='course' value='$course_code'>" . "<input type='hidden' name='op' value='finish'>"; $i = $totalScore = $totalWeighting = 0; // for each question foreach ($_SESSION['questionList'][$exerciseId] as $questionId) { // gets the student choice for this question $choice = @$_SESSION['exerciseResult'][$exerciseId][$questionId]; // creates a temporary Question object $objQuestionTmp = new Question(); $objQuestionTmp->read($questionId); $questionName = $objQuestionTmp->selectTitle(); $questionDescription = $objQuestionTmp->selectDescription(); $questionDescription_temp = nl2br(make_clickable($questionDescription)); $questionDescription_temp = mathfilter($questionDescription_temp, 12, "$webDir/courses/mathimg/"); $questionWeighting = $objQuestionTmp->selectWeighting(); $answerType = $objQuestionTmp->selectType(); // destruction of the Question object unset($objQuestionTmp); if ($answerType == UNIQUE_ANSWER || $answerType == MULTIPLE_ANSWER || $answerType == TRUE_FALSE) { $colspan = 4; } elseif ($answerType == MATCHING) { $colspan = 2;
} else { $my_cid = null; } if (!empty($_POST['action'])) { $action = $_POST['action']; } else { $action = ''; } if (empty($my_qst) or empty($my_usr) or empty($my_cid) or empty($my_exe)) { header('Location: exercice.php'); exit; } if (!$is_courseTutor) { api_not_allowed(); } $obj_question = Question::read($my_qst); if (isset($_SESSION['gradebook'])) { $gradebook = $_SESSION['gradebook']; } if (!empty($gradebook) && $gradebook == 'view') { $interbreadcrumb[] = array('url' => '../gradebook/' . $_SESSION['gradebook_dest'], 'name' => get_lang('ToolGradebook')); } $nameTools = get_lang('Exercice'); $interbreadcrumb[] = array("url" => "exercice.php", "name" => get_lang('Exercices')); $my_msg = 'No change.'; if ($action == 'mark') { if (!empty($_POST['score']) and $_POST['score'] < $obj_question->selectWeighting() and $_POST['score'] >= 0) { //mark the user mark into the database using something similar to the following function: $exercise_table = Database::get_statistic_table('track_e_exercices'); #global $origin, $tbl_learnpath_user, $learnpath_id, $learnpath_item_id; $sql = "SELECT * FROM {$exercise_table}\n\t\t\t WHERE exe_user_id = " . intval($my_usr) . " AND exe_cours_id = '" . Database::escape_string($my_cid) . "' AND exe_exo_id = " . intval($my_exe) . "\n\t\t\t ORDER BY exe_date DESC";
if (in_array($_GET['message'], array('ExerciseStored', 'ItemUpdated', 'ItemAdded'))) { Display::display_confirmation_message(get_lang($_GET['message'])); } } if ($newQuestion || $editQuestion) { // Question management $type = isset($_REQUEST['answerType']) ? Security::remove_XSS($_REQUEST['answerType']) : null; echo '<input type="hidden" name="Type" value="' . $type . '" />'; if ($newQuestion == 'yes') { $objExercise->edit_exercise_in_lp = true; } require 'question_admin.inc.php'; } if (isset($_GET['hotspotadmin'])) { if (!is_object($objQuestion)) { $objQuestion = Question::read($_GET['hotspotadmin']); } if (!$objQuestion) { api_not_allowed(); } require 'hotspot_admin.inc.php'; } if (!$newQuestion && !$modifyQuestion && !$editQuestion && !isset($_GET['hotspotadmin'])) { // question list management require 'question_list_admin.inc.php'; } // if we are in question authoring, display warning to user is feedback not shown at the end of the test -ref #6619 // this test to display only message in the question authoring page and not in the question list page too // if (is_object($objQuestion) && $objExercise->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_EXAM && ($newQuestion || $modifyQuestion || $editQuestion)) { if ($objExercise->selectFeedbackType() == EXERCISE_FEEDBACK_TYPE_EXAM) { Display::display_normal_message(get_lang("TestFeedbackNotShown"));
/** * Update user answers */ private function update_answer_records($key, $value) { // construction of the Question object $objQuestionTmp = new Question(); // reads question informations $objQuestionTmp->read($key); $question_type = $objQuestionTmp->selectType(); $id = $this->id; $eurid = $_SESSION['exerciseUserRecordID'][$id]; if ($question_type == FREE_TEXT) { if (!empty($value)) { Database::get()->query("UPDATE exercise_answer_record SET answer = ?s, answer_id = 1, weight = NULL,\n is_answered = 1 WHERE eurid = ?d AND question_id = ?d", $value, $eurid, $key); } else { Database::get()->query("UPDATE exercise_answer_record SET answer = ?s, \n answer_id = 0, weight = 0, is_answered = 1 WHERE eurid = ?d AND question_id = ?d", $value, $eurid, $key); } } elseif ($question_type == FILL_IN_BLANKS) { $objAnswersTmp = new Answer($key); $answer_field = $objAnswersTmp->selectAnswer(1); //splits answer string from weighting string list($answer, $answerWeighting) = explode('::', $answer_field); // splits weightings that are joined with a comma $rightAnswerWeighting = explode(',', $answerWeighting); //getting all matched strings between [ and ] delimeters preg_match_all('#\\[(.*?)\\]#', $answer, $match); foreach ($value as $row_key => $row_choice) { //if user's choice is right assign rightAnswerWeight else 0 $weight = $row_choice == $match[1][$row_key - 1] ? $rightAnswerWeighting[$row_key - 1] : 0; Database::get()->query("UPDATE exercise_answer_record SET answer = ?s, weight = ?f, is_answered = 1 \n WHERE eurid = ?d AND question_id = ?d AND answer_id = ?d", $row_choice, $weight, $eurid, $key, $row_key); } } elseif ($question_type == MULTIPLE_ANSWER) { if ($value == 0) { $row_key = 0; $answer_weight = 0; Database::get()->query("UPDATE exercise_answer_record SET is_answered= 1 WHERE eurid = ?d AND question_id = ?d", $eurid, $key); } else { $objAnswersTmp = new Answer($key); $i = 1; // the first time in the loop we should update in order to keep question position in the DB // and then insert a new record if there are more than one answers foreach ($value as $row_key => $row_choice) { $answer_weight = $objAnswersTmp->selectWeighting($row_key); if ($i == 1) { Database::get()->query("UPDATE exercise_answer_record SET answer_id = ?d, weight = ?f , is_answered = 1 WHERE eurid = ?d AND question_id = ?d", $row_key, $answer_weight, $eurid, $key); } else { Database::get()->query("INSERT INTO exercise_answer_record (eurid, question_id, answer_id, weight, is_answered)\n VALUES (?d, ?d, ?d, ?f, 1)", $eurid, $key, $row_key, $answer_weight); } unset($answer_weight); $i++; } unset($objAnswersTmp); } } elseif ($question_type == MATCHING) { $objAnswersTmp = new Answer($key); foreach ($value as $row_key => $row_choice) { // In matching questions isCorrect() returns position of left column answers while $row_key returns right column position $correct_match = $objAnswersTmp->isCorrect($row_key); if ($correct_match == $row_choice) { $answer_weight = $objAnswersTmp->selectWeighting($row_key); } else { $answer_weight = 0; } Database::get()->query("UPDATE exercise_answer_record SET answer_id = ?d, weight = ?f , is_answered = 1\n WHERE eurid = ?d AND question_id = ?d AND answer = ?d", $row_choice, $answer_weight, $eurid, $key, $row_key); unset($answer_weight); } } else { if ($value != 0) { $objAnswersTmp = new Answer($key); $answer_weight = $objAnswersTmp->selectWeighting($value); } else { $answer_weight = 0; } Database::get()->query("UPDATE exercise_answer_record SET answer_id = ?d, weight = ?f , is_answered = 1\n WHERE eurid = ?d AND question_id = ?d", $value, $answer_weight, $eurid, $key); } unset($objQuestionTmp); }
/** * @param $exe_id * @param $objExercise * @return array */ public static function getAnsweredQuestionsFromAttempt($exe_id, $objExercise) { $attempt_list = self::getAllExerciseEventByExeId($exe_id); $exercise_result = array(); if (!empty($attempt_list)) { foreach ($attempt_list as $question_id => $options) { foreach ($options as $item) { $question_obj = Question::read($item['question_id']); switch ($question_obj->type) { case FILL_IN_BLANKS: $item['answer'] = $objExercise->fill_in_blank_answer_to_string($item['answer']); break; case HOT_SPOT: break; } if ($item['answer'] != '0' && !empty($item['answer'])) { $exercise_result[] = $question_id; break; } } } } return $exercise_result; }
/** * Build the Quiz-Questions */ public function build_quiz_questions($course_code = null) { $course_info = api_get_course_info($course_code); $course_id = $course_info['real_id']; $table_qui = Database::get_course_table(TABLE_QUIZ_TEST); $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION); $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER); // Building normal tests. $sql = "SELECT * FROM {$table_que} WHERE c_id = {$course_id} "; $db_result = Database::query($sql); while ($obj = Database::fetch_object($db_result)) { $categories = Testcategory::getCategoryForQuestionWithCategoryData($obj->iid, $course_id, true); $parent_info = array(); if (isset($obj->parent_id) && !empty($obj->parent_id)) { $parent_info = (array) Question::read($obj->parent_id, $course_id); } $question = new QuizQuestion($obj->iid, $obj->question, $obj->description, $obj->ponderation, $obj->type, $obj->position, $obj->picture, $obj->level, $obj->extra, $parent_info, $categories); $sql = 'SELECT * FROM ' . $table_ans . ' WHERE question_id = ' . $obj->iid; $db_result2 = Database::query($sql); while ($obj2 = Database::fetch_object($db_result2)) { $question->add_answer($obj2->iid, $obj2->answer, $obj2->correct, $obj2->comment, $obj2->ponderation, $obj2->position, $obj2->hotspot_coordinates, $obj2->hotspot_type); if ($obj->type == MULTIPLE_ANSWER_TRUE_FALSE) { $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION); $sql = 'SELECT * FROM ' . $table_options . ' WHERE c_id = ' . $course_id . ' AND question_id = ' . $obj->iid; $db_result3 = Database::query($sql); while ($obj3 = Database::fetch_object($db_result3)) { $question_option = new QuizQuestionOption($obj3); $question->add_option($question_option); } } } $this->course->add_resource($question); } // Building a fictional test for collecting orphan questions. $build_orphan_questions = !empty($_POST['recycle_option']); // When a course is emptied this option should be activated (true). //1st union gets the orphan questions from deleted exercises //2nd union gets the orphan questions from question that were deleted in a exercise. $sql = " (\n SELECT q.* FROM {$table_que} q INNER JOIN {$table_rel} r\n ON (q.c_id = r.c_id AND q.iid = r.question_id)\n INNER JOIN {$table_qui} ex\n ON (ex.iid = r.exercice_id AND ex.c_id = r.c_id )\n WHERE ex.c_id = {$course_id} AND ex.active = '-1'\n )\n UNION\n (\n SELECT q.* FROM {$table_que} q left\n OUTER JOIN {$table_rel} r\n ON (q.c_id = r.c_id AND q.iid = r.question_id)\n WHERE q.c_id = {$course_id} AND r.question_id is null\n )\n UNION\n (\n SELECT q.* FROM {$table_que} q\n INNER JOIN {$table_rel} r\n ON (q.c_id = r.c_id AND q.iid = r.question_id)\n WHERE r.c_id = {$course_id} AND (r.exercice_id = '-1' OR r.exercice_id = '0')\n )\n "; $db_result = Database::query($sql); if (Database::num_rows($db_result) > 0) { $build_orphan_questions = true; $orphanQuestionIds = array(); while ($obj = Database::fetch_object($db_result)) { $categories = Testcategory::getCategoryForQuestionWithCategoryData($obj->iid, $course_id, true); $parent_info = array(); if (isset($obj->parent_id) && !empty($obj->parent_id)) { $parent_info = (array) Question::read($obj->parent_id, $course_id); } //Avoid adding the same question twice if (!isset($this->course->resources[$obj->iid])) { $question = new QuizQuestion($obj->iid, $obj->question, $obj->description, $obj->ponderation, $obj->type, $obj->position, $obj->picture, $obj->level, $obj->extra, $parent_info, $categories); $sql = "SELECT * FROM {$table_ans} WHERE c_id = {$course_id} AND question_id = " . $obj->iid; $db_result2 = Database::query($sql); if (Database::num_rows($db_result2)) { while ($obj2 = Database::fetch_object($db_result2)) { $question->add_answer($obj2->iid, $obj2->answer, $obj2->correct, $obj2->comment, $obj2->ponderation, $obj2->position, $obj2->hotspot_coordinates, $obj2->hotspot_type); } $orphanQuestionIds[] = $obj->iid; } $this->course->add_resource($question); } } } if ($build_orphan_questions) { $obj = array('iid' => -1, 'title' => get_lang('OrphanQuestions', ''), 'type' => 2); $newQuiz = new Quiz((object) $obj); if (!empty($orphanQuestionIds)) { foreach ($orphanQuestionIds as $index => $orphanId) { $order = $index + 1; $newQuiz->add_question($orphanId, $order); } } $this->course->add_resource($newQuiz); } }
/* For licensing terms, see /license.txt */ /** * Code library for HotPotatoes integration. * @package chamilo.exercise */ /** * QUESTION LIST ADMINISTRATION * * This script allows to manage the question list * It is included from the script admin.php * */ // deletes a question from the exercise (not from the data base) if ($deleteQuestion) { // If the question exists if ($objQuestionTmp = Question::read($deleteQuestion)) { $objQuestionTmp->delete($exerciseId); // if the question has been removed from the exercise if ($objExercise->removeFromList($deleteQuestion)) { $nbrQuestions--; } } // destruction of the Question object unset($objQuestionTmp); } $token = Security::get_token(); //jqgrid will use this URL to do the selects $url = api_get_path(WEB_AJAX_PATH) . 'model.ajax.php?a=get_question_list&exerciseId=' . $exerciseId; //The order is important you need to check the the $column variable in the model.ajax.php file $columns = array(get_lang('Questions'), get_lang('Type'), get_lang('Category'), get_lang('Difficulty'), get_lang('Score'), get_lang('Actions')); //$columns = array(get_lang('Questions'), get_lang('Type'), get_lang('Category'), get_lang('Score'));
/** * Restore quiz-questions * @params int question id */ public function restore_quiz_question($id) { $resources = $this->course->resources; $question = isset($resources[RESOURCE_QUIZQUESTION][$id]) ? $resources[RESOURCE_QUIZQUESTION][$id] : null; $new_id = 0; if (is_object($question)) { if ($question->is_restored()) { return $question->destination_id; } $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION); $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER); $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION); // check resources inside html from ckeditor tool and copy correct urls into recipient course $question->description = DocumentManager::replace_urls_inside_content_html_from_copy_course($question->description, $this->course->code, $this->course->destination_path, $this->course->backup_path, $this->course->info['path']); $params = ['c_id' => $this->destination_course_id, 'question' => self::DBUTF8($question->question), 'description' => self::DBUTF8($question->description), 'ponderation' => self::DBUTF8($question->ponderation), 'position' => self::DBUTF8($question->position), 'type' => self::DBUTF8($question->quiz_type), 'picture' => self::DBUTF8($question->picture), 'level' => self::DBUTF8($question->level), 'extra' => self::DBUTF8($question->extra)]; $new_id = Database::insert($table_que, $params); if ($new_id) { $sql = "UPDATE {$table_que} SET id = iid WHERE iid = {$new_id}"; Database::query($sql); if (!empty($question->picture)) { $question_temp = Question::read($new_id, $this->destination_course_info['real_id']); $documentPath = api_get_path(SYS_COURSE_PATH) . $this->destination_course_info['path'] . '/document'; // picture path $picturePath = $documentPath . '/images'; $old_picture = api_get_path(SYS_COURSE_PATH) . $this->course->info['path'] . '/document/images/' . $question->picture; if (file_exists($old_picture)) { $picture_name = 'quiz-' . $new_id . '.jpg'; $result = $question_temp->uploadPicture($old_picture, $picture_name, $picturePath); if ($result) { $sql = "UPDATE {$table_que} SET\n picture = '{$picture_name}'\n WHERE\n c_id = " . $this->destination_course_id . " AND\n id = {$new_id} "; Database::query($sql); } } } } if (in_array($question->quiz_type, [MATCHING, MATCHING_DRAGGABLE])) { $temp = array(); foreach ($question->answers as $index => $answer) { $temp[$answer['position']] = $answer; } foreach ($temp as $index => $answer) { //id = '".$index."', $params = ['c_id' => $this->destination_course_id, 'question_id' => $new_id, 'answer' => self::DBUTF8($answer['answer']), 'correct' => $answer['correct'], 'comment' => self::DBUTF8($answer['comment']), 'ponderation' => $answer['ponderation'], 'position' => $answer['position'], 'hotspot_coordinates' => $answer['hotspot_coordinates'], 'hotspot_type' => $answer['hotspot_type']]; $answerId = Database::insert($table_ans, $params); if ($answerId) { $sql = "UPDATE {$table_ans} SET id = iid, id_auto = iid WHERE iid = {$answerId}"; Database::query($sql); } } } else { $correct_answers = array(); foreach ($question->answers as $index => $answer) { // check resources inside html from ckeditor tool and copy correct urls into recipient course $answer['answer'] = DocumentManager::replace_urls_inside_content_html_from_copy_course($answer['answer'], $this->course->code, $this->course->destination_path, $this->course->backup_path, $this->course->info['path']); $answer['comment'] = DocumentManager::replace_urls_inside_content_html_from_copy_course($answer['comment'], $this->course->code, $this->course->destination_path, $this->course->backup_path, $this->course->info['path']); // id = '". ($index + 1)."', $params = ['c_id' => $this->destination_course_id, 'question_id' => $new_id, 'answer' => self::DBUTF8($answer['answer']), 'correct' => $answer['correct'], 'comment' => self::DBUTF8($answer['comment']), 'ponderation' => $answer['ponderation'], 'position' => $answer['position'], 'hotspot_coordinates' => $answer['hotspot_coordinates'], 'hotspot_type' => $answer['hotspot_type']]; $answerId = Database::insert($table_ans, $params); if ($answerId) { $sql = "UPDATE {$table_ans} SET id = iid, id_auto = iid WHERE iid = {$answerId}"; Database::query($sql); } $correct_answers[$answerId] = $answer['correct']; } } //Current course id $course_id = api_get_course_int_id(); //Moving quiz_question_options if ($question->quiz_type == MULTIPLE_ANSWER_TRUE_FALSE) { $question_option_list = Question::readQuestionOption($id, $course_id); //Question copied from the current platform if ($question_option_list) { $old_option_ids = array(); foreach ($question_option_list as $item) { $old_id = $item['id']; unset($item['id']); if (isset($item['iid'])) { unset($item['iid']); } $item['question_id'] = $new_id; $item['c_id'] = $this->destination_course_id; $question_option_id = Database::insert($table_options, $item); if ($question_option_id) { $old_option_ids[$old_id] = $question_option_id; $sql = "UPDATE {$table_options} SET id = iid WHERE iid = {$question_option_id}"; Database::query($sql); } } if ($old_option_ids) { $new_answers = Database::select('iid, correct', $table_ans, array('WHERE' => array('question_id = ? AND c_id = ? ' => array($new_id, $this->destination_course_id)))); foreach ($new_answers as $answer_item) { $params = array(); $params['correct'] = $old_option_ids[$answer_item['correct']]; Database::update($table_ans, $params, array('iid = ? AND c_id = ? AND question_id = ? ' => array($answer_item['iid'], $this->destination_course_id, $new_id)), false); } } } else { $new_options = array(); if (isset($question->question_options)) { foreach ($question->question_options as $obj) { $item = array(); $item['question_id'] = $new_id; $item['c_id'] = $this->destination_course_id; $item['name'] = $obj->obj->name; $item['position'] = $obj->obj->position; $question_option_id = Database::insert($table_options, $item); if ($question_option_id) { $new_options[$obj->obj->id] = $question_option_id; $sql = "UPDATE {$table_options} SET id = iid WHERE iid = {$question_option_id}"; Database::query($sql); } } foreach ($correct_answers as $answer_id => $correct_answer) { $params = array(); $params['correct'] = $new_options[$correct_answer]; Database::update($table_ans, $params, array('id = ? AND c_id = ? AND question_id = ? ' => array($answer_id, $this->destination_course_id, $new_id)), false); } } } } $this->course->resources[RESOURCE_QUIZQUESTION][$id]->destination_id = $new_id; } return $new_id; }
if ($item['answer'] != '0' && !empty($item['answer'])) { $exercise_result[] = $question_id; break; } } } echo Display::label(get_lang('QuestionWithNoAnswer'), 'warning'); echo '<div class="clear"></div><br />'; $table = ''; $counter = 0; // Loop over all question to show results for each of them, one by one foreach ($question_list as $questionId) { // destruction of the Question object unset($objQuestionTmp); // creates a temporary Question object $objQuestionTmp = Question::read($questionId); $quesId = $objQuestionTmp->selectId(); $check_id = 'remind_list[' . $questionId . ']'; $attributes = array('id' => $check_id, 'onclick' => "save_remind_item(this, '{$questionId}');"); if (in_array($questionId, $remind_list)) { $attributes['checked'] = 1; } $label_attributes = array(); $label_attributes['class'] = 'checkbox'; $label_attributes['for'] = $check_id; $label_attributes['class'] = "checkbox"; $checkbox = Display::input('checkbox', 'remind_list[' . $questionId . ']', '', $attributes); $url = 'exercise_submit.php?exerciseId=' . $objExercise->id . '&num=' . $counter . '&reminder=1'; $counter++; if ($objExercise->type == ONE_PER_PAGE) { $question_title = Display::url($counter . '. ' . cut($objQuestionTmp->selectTitle(), 40), $url);
} if ($isSelected) { $option_lp = '<option value="0">' . get_lang('SelectTargetLP') . '</option>' . $option_lp; } else { $option_lp = '<option value="0" selected="selected" >' . get_lang('SelectTargetLP') . '</option>' . $option_lp; } //Feedback SELECT $question_list = $objExercise->selectQuestionList(); $option_feed = ''; $option_feed .= '<option value="0">' . get_lang('SelectTargetQuestion') . '</option>'; $details = isset($details) ? $details : null; $id = isset($id) ? $id : 0; $selectQuestionNoError = isset($selectQuestionNoError) ? $selectQuestionNoError : null; foreach ($question_list as $key => $questionid) { $selected = ''; $question = Question::read($questionid); $val = 'Q' . $key . ' :' . substrwords($question->selectTitle(), ICON_SIZE_SMALL); $select_lp_id[$id] = $details['lp_name']; if ($questionid == $selectQuestionNoError) { $selected = 'selected="selected"'; } $option_feed .= '<option value="' . $questionid . '" ' . $selected . ' >' . $val . '</option>'; } if ($selectQuestionNoError == -1) { $option_feed .= '<option value="-1" selected="selected" >' . get_lang('ExitTest') . '</option>'; } else { $option_feed .= '<option value="-1">' . get_lang('ExitTest') . '</option>'; } if ($answerType == HOT_SPOT_DELINEATION) { ?> <tr>
/** * Display the exercise results * @param Exercise $objExercise * @param int $exe_id * @param bool $save_user_result save users results (true) or just show the results (false) */ public static function display_question_list_by_attempt($objExercise, $exe_id, $save_user_result = false) { global $origin; // Getting attempt info $exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exe_id); // Getting question list $question_list = array(); if (!empty($exercise_stat_info['data_tracking'])) { $question_list = explode(',', $exercise_stat_info['data_tracking']); } else { // Try getting the question list only if save result is off if ($save_user_result == false) { $question_list = $objExercise->get_validated_question_list(); } } $counter = 1; $total_score = $total_weight = 0; $exercise_content = null; // Hide results $show_results = false; $show_only_score = false; if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS) { $show_results = true; } if (in_array($objExercise->results_disabled, array(RESULT_DISABLE_SHOW_SCORE_ONLY, RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES))) { $show_only_score = true; } // Not display expected answer, but score, and feedback $show_all_but_expected_answer = false; if ($objExercise->results_disabled == RESULT_DISABLE_SHOW_SCORE_ONLY && $objExercise->feedback_type == EXERCISE_FEEDBACK_TYPE_END) { $show_all_but_expected_answer = true; $show_results = true; $show_only_score = false; } if ($show_results || $show_only_score) { $user_info = api_get_user_info($exercise_stat_info['exe_user_id']); //Shows exercise header echo $objExercise->show_exercise_result_header($user_info, api_convert_and_format_date($exercise_stat_info['start_date'], DATE_TIME_FORMAT_LONG), $exercise_stat_info['duration'], $exercise_stat_info['user_ip']); } // Display text when test is finished #4074 and for LP #4227 $end_of_message = $objExercise->selectTextWhenFinished(); if (!empty($end_of_message)) { Display::display_normal_message($end_of_message, false); echo "<div class='clear'> </div>"; } $question_list_answers = array(); $media_list = array(); $category_list = array(); // Loop over all question to show results for each of them, one by one if (!empty($question_list)) { foreach ($question_list as $questionId) { // creates a temporary Question object $objQuestionTmp = Question::read($questionId); // This variable came from exercise_submit_modal.php ob_start(); // We're inside *one* question. Go through each possible answer for this question $result = $objExercise->manage_answer($exercise_stat_info['exe_id'], $questionId, null, 'exercise_result', array(), $save_user_result, true, $show_results, $objExercise->selectPropagateNeg(), array()); if (empty($result)) { continue; } // In case of global score, make sure the calculated total score is integer /*if (!is_int($result['score'])) { $result['score'] = round($result['score']); }*/ $total_score += $result['score']; $total_weight += $result['weight']; $question_list_answers[] = array('question' => $result['open_question'], 'answer' => $result['open_answer'], 'answer_type' => $result['answer_type']); $my_total_score = $result['score']; $my_total_weight = $result['weight']; // Category report $category_was_added_for_this_test = false; if (isset($objQuestionTmp->category) && !empty($objQuestionTmp->category)) { if (!isset($category_list[$objQuestionTmp->category]['score'])) { $category_list[$objQuestionTmp->category]['score'] = 0; } if (!isset($category_list[$objQuestionTmp->category]['total'])) { $category_list[$objQuestionTmp->category]['total'] = 0; } $category_list[$objQuestionTmp->category]['score'] += $my_total_score; $category_list[$objQuestionTmp->category]['total'] += $my_total_weight; $category_was_added_for_this_test = true; } if (isset($objQuestionTmp->category_list) && !empty($objQuestionTmp->category_list)) { foreach ($objQuestionTmp->category_list as $category_id) { $category_list[$category_id]['score'] += $my_total_score; $category_list[$category_id]['total'] += $my_total_weight; $category_was_added_for_this_test = true; } } // No category for this question! if ($category_was_added_for_this_test == false) { if (!isset($category_list['none']['score'])) { $category_list['none']['score'] = 0; } if (!isset($category_list['none']['total'])) { $category_list['none']['total'] = 0; } $category_list['none']['score'] += $my_total_score; $category_list['none']['total'] += $my_total_weight; } if ($objExercise->selectPropagateNeg() == 0 && $my_total_score < 0) { $my_total_score = 0; } $comnt = null; if ($show_results) { $comnt = Event::get_comments($exe_id, $questionId); if (!empty($comnt)) { echo '<b>' . get_lang('Feedback') . '</b>'; echo '<div id="question_feedback">' . $comnt . '</div>'; } } if ($show_results) { $score = array('result' => get_lang('Score') . " : " . self::show_score($my_total_score, $my_total_weight, false, true), 'pass' => $my_total_score >= $my_total_weight ? true : false, 'score' => $my_total_score, 'weight' => $my_total_weight, 'comments' => $comnt); } else { $score = array(); } $contents = ob_get_clean(); $question_content = ''; if ($show_results) { $question_content = '<div class="question_row_answer">'; $show_media = false; /*if ($objQuestionTmp->parent_id != 0 && !in_array($objQuestionTmp->parent_id, $media_list)) { $show_media = true; $media_list[] = $objQuestionTmp->parent_id; }*/ //Shows question title an description $question_content .= $objQuestionTmp->return_header(null, $counter, $score); } $counter++; $question_content .= $contents; if ($show_results) { $question_content .= '</div>'; } $exercise_content .= $question_content; } // end foreach() block that loops over all questions } $total_score_text = null; if ($origin != 'learnpath') { if ($show_results || $show_only_score) { $total_score_text .= '<div class="question_row_score">'; $total_score_text .= self::get_question_ribbon($objExercise, $total_score, $total_weight, true); $total_score_text .= '</div>'; } } if (!empty($category_list) && ($show_results || $show_only_score)) { //Adding total $category_list['total'] = array('score' => $total_score, 'total' => $total_weight); echo TestCategory::get_stats_table_by_attempt($objExercise->id, $category_list); } if ($show_all_but_expected_answer) { $exercise_content .= "<div class='normal-message'>" . get_lang("ExerciseWithFeedbackWithoutCorrectionComment") . "</div>"; } // Remove audio auto play from questions on results page - refs BT#7939 $exercise_content = preg_replace(['/autoplay[\\=\\".+\\"]+/', '/autostart[\\=\\".+\\"]+/'], '', $exercise_content); echo $total_score_text; echo $exercise_content; if (!$show_only_score) { echo $total_score_text; } if ($save_user_result) { // Tracking of results $learnpath_id = $exercise_stat_info['orig_lp_id']; $learnpath_item_id = $exercise_stat_info['orig_lp_item_id']; $learnpath_item_view_id = $exercise_stat_info['orig_lp_item_view_id']; if (api_is_allowed_to_session_edit()) { Event::update_event_exercice($exercise_stat_info['exe_id'], $objExercise->selectId(), $total_score, $total_weight, api_get_session_id(), $learnpath_id, $learnpath_item_id, $learnpath_item_view_id, $exercise_stat_info['exe_duration'], $question_list, '', array()); } // Send notification .. if (!api_is_allowed_to_edit(null, true) && !api_is_excluded_user_type()) { if (api_get_course_setting('email_alert_manager_on_new_quiz') == 1) { $objExercise->send_mail_notification_for_exam($question_list_answers, $origin, $exe_id); } $objExercise->send_notification_for_open_questions($question_list_answers, $origin, $exe_id); $objExercise->send_notification_for_oral_questions($question_list_answers, $origin, $exe_id); } } }
/** * This function exports the given Chamilo test * @param integer Test ID * @return string The test itself as an HTML string */ function export_exercise($item_id) { global $expdir, $_course, $_configuration, $_SESSION, $_SERVER, $language_interface, $langExerciseNotFound, $langQuestion, $langOk, $origin, $questionNum; $exerciseId = $item_id; require_once '../exercice/exercise.class.php'; require_once '../exercice/question.class.php'; require_once '../exercice/answer.class.php'; $TBL_EXERCISES = Database::get_course_table(TABLE_QUIZ_TEST); /* Clears the exercise session */ if (isset($_SESSION['objExercise'])) { Session::erase('objExercise'); } if (isset($_SESSION['objQuestion'])) { Session::erase('objQuestion'); } if (isset($_SESSION['objAnswer'])) { Session::erase('objAnswer'); } if (isset($_SESSION['questionList'])) { Session::erase('questionList'); } if (isset($_SESSION['exerciseResult'])) { Session::erase('exerciseResult'); } // If the object is not in the session: if (!isset($_SESSION['objExercise'])) { // Construction of Exercise. $objExercise = new Exercise(); $sql = "SELECT title,description,sound,type,random,active FROM {$TBL_EXERCISES} WHERE iid='{$exerciseId}'"; // If the specified exercise doesn't exist or is disabled: if (!$objExercise->read($exerciseId) || !$objExercise->selectStatus() && !api_is_allowed_to_edit() && $origin != 'learnpath') { die($langExerciseNotFound); } // Saves the object into the session. Session::write('objExercise', $objExercise); } $exerciseTitle = $objExercise->selectTitle(); $exerciseDescription = $objExercise->selectDescription(); $exerciseSound = $objExercise->selectSound(); $randomQuestions = $objExercise->isRandom(); $exerciseType = $objExercise->selectType(); if (!isset($_SESSION['questionList'])) { // Selects the list of question ID. $questionList = $randomQuestions ? $objExercise->selectRandomList() : $objExercise->selectQuestionList(); // Saves the question list into the session. Session::write('questionList', $questionList); } $nbrQuestions = sizeof($questionList); // If questionNum comes from POST and not from GET: if (!$questionNum || $_POST['questionNum']) { // Only used for sequential exercises (see $exerciseType). if (!$questionNum) { $questionNum = 1; } else { $questionNum++; } } $test .= "<h3>" . $exerciseTitle . "</h3>"; if (!empty($exerciseSound)) { $test .= "<a href=\"../document/download.php?doc_url=%2Faudio%2F" . $exerciseSound . "\"&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9 target=\"_blank\"><img src=\"../img/sound.gif\" border=\"0\" align=\"absmiddle\" alt=" . get_lang("Sound") . "\" /></a>"; } // Writing the .js file with to check the correct answers begin. $scriptfilename = "Exercice" . $item_id . ".js"; $s = "<script type=\"text/javascript\" src='../js/" . $scriptfilename . "'></script>"; $test .= $s; $content = "function evaluate() {\n alert('Test evaluated.');\n }\n "; if (!($handle = fopen($expdir . '/js/' . $scriptfilename, 'w'))) { echo "Cannot open file ({$scriptfilename})"; } if (fwrite($handle, $content) === false) { echo "Cannot write to file ({$filename})"; exit; } fclose($handle); // Writing the .js file with to check the correct answers end. $s = "\n <p>{$exerciseDescription}</p>\n <table width='100%' border='0' cellpadding='1' cellspacing='0'>\n <form method='post' action=''><input type=\"hidden\" name=\"SQMSESSID\" value=\"36812c2dea7d8d6e708d5e6a2f09b0b9\" />\n <input type='hidden' name='formSent' value='1' />\n <input type='hidden' name='exerciseType' value='" . $exerciseType . "' />\n <input type='hidden' name='questionNum' value='" . $questionNum . "' />\n <input type='hidden' name='nbrQuestions' value='" . $nbrQuestions . "' />\n <tr>\n <td>\n <table width='100%' cellpadding='4' cellspacing='2' border='0'>"; $exerciseType = 1; // So to list all questions in one page. $test .= $s; $i = 0; foreach ($questionList as $questionId) { $i++; // For sequential exercises. if ($exerciseType == 2) { // If it is not the right question, goes to the next loop iteration. if ($questionNum != $i) { continue; } else { // if the user has already answered this question: if (isset($exerciseResult[$questionId])) { // Construction of the Question object. $objQuestionTmp = new Question(); // Reads question informations. $objQuestionTmp->read($questionId); $questionName = $objQuestionTmp->selectTitle(); // Destruction of the Question object. unset($objQuestionTmp); $test .= '<tr><td>' . get_lang('AlreadyAnswered') . ' "' . $questionName . '"</td></tr>'; break; } } } echo $s = "<tr bgcolor='#e6e6e6'><td valign='top' colspan='2'>" . get_lang('Question') . " "; // Call the showQuestion(). This basically displays the question in a table. $question_obj = Question::read($questionId); $test .= $objExercise->showQuestion($question_obj, false, 'export', $i); } // end foreach() $s = "</table></td></tr><tr><td><br/><input type='button' value='" . $langOk . "' onclick=\"javascript: evaluate(); alert('Evaluated.');\">"; $s .= "</td></tr></form></table>"; $s .= "<script type='text/javascript'> loadPage(); </script>"; $b = 2; $test .= $s; return $test; }
function get_question_category_for_question($course_id, $question_id) { global $all_category_list; $objQuestionTmp = Question::read($question_id, $course_id); return Testcategory::return_category_labels($objQuestionTmp->category_list, $all_category_list); }
/** * Exports an exercise as a SCO. * This method is intended to be called from the prepare method. * * @note There's a lot of nearly cut-and-paste from exercise.lib.php here * because of some little differences... * Perhaps something that could be refactorised ? * * @see prepare * @param $quizId The quiz * @param $raw_to_pass The needed score to attain * @return False on error, True if everything went well. * @author Thanos Kyritsis <*****@*****.**> * @author Amand Tihon <*****@*****.**> */ function prepareQuiz($quizId, $raw_to_pass = 50) { global $langQuestion, $langOk, $langScore, $claro_stylesheet, $clarolineRepositorySys; global $charset, $langExerciseDone; // those two variables are needed by display_attached_file() global $attachedFilePathWeb; global $attachedFilePathSys; $attachedFilePathWeb = 'Exercises'; $attachedFilePathSys = $this->destDir . '/Exercises'; // Generate standard page header $pageHeader = '<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=' . $charset . '"> <meta http-equiv="expires" content="Tue, 05 DEC 2000 07:00:00 GMT"> <meta http-equiv="Pragma" content="no-cache"> <link rel="stylesheet" type="text/css" href="bootstrap-custom.css" /> <link rel="stylesheet" type="text/css" href="' . $claro_stylesheet . '" media="screen, projection, tv" /> <script language="javascript" type="text/javascript" src="APIWrapper.js"></script> <script language="javascript" type="text/javascript" src="scores.js"></script> ' . "\n"; $pageBody = '<body onload="loadPage()"> <div id="claroBody"><form id="quiz"> <table class="table-default"><tr><td>' . "\n"; // read the exercise $quiz = new Exercise(); if (!$quiz->read($quizId)) { $this->error[] = $GLOBALS['langErrorLoadingExercise']; return false; } // Get the question list $questionList = $quiz->selectQuestionList(); $questionCount = $quiz->selectNbrQuestions(); // Keep track of raw scores (ponderation) for each question $questionPonderationList = array(); // Keep track of correct texts for fill-in type questions $fillAnswerList = array(); // Counter used to generate the elements' id. Incremented after every <input> or <select> $idCounter = 0; // Display each question $questionCount = 0; foreach ($questionList as $questionId) { // Update question number $questionCount++; // read the question, abort on error $question = new Question(); if (!$question->read($questionId)) { $this->error[] = $GLOBALS['langErrorLoadingQuestion']; return false; } $qtype = $question->selectType(); $qtitle = $question->selectTitle(); $qdescription = $question->selectDescription(); $questionPonderationList[$questionId] = $question->selectWeighting(); // Generic display, valid for all kind of question $pageBody .= '<table class="table-default"> <tr><th valign="top" colspan="2">' . $langQuestion . ' ' . $questionCount . '</th></tr> <tfoot> <tr><td valign="top" colspan="2">' . $qtitle . '</td></tr> <tr><td valign="top" colspan="2"><i>' . parse_user_text($qdescription) . '</i></td></tr>' . "\n"; // Attached file, if it exists. //$attachedFile = $question->selectAttachedFile(); if (!empty($attachedFile)) { // copy the attached file if (!claro_copy_file($this->srcDirExercise . '/' . $attachedFile, $this->destDir . '/Exercises')) { $this->error[] = $GLOBALS['langErrorCopyAttachedFile'] . $attachedFile; return false; } // Ok, if it was an mp3, we need to copy the flash mp3-player too. $extension = substr(strrchr($attachedFile, '.'), 1); if ($extension == 'mp3') { $this->mp3Found = true; } $pageBody .= '<tr><td colspan="2">' . display_attached_file($attachedFile) . '</td></tr>' . "\n"; } /* * Display the possible answers */ $answer = new Answer($questionId); $answerCount = $answer->selectNbrAnswers(); // Used for matching: $letterCounter = 'A'; $choiceCounter = 1; $Select = array(); for ($answerId = 1; $answerId <= $answerCount; $answerId++) { $answerText = $answer->selectAnswer($answerId); $answerCorrect = $answer->isCorrect($answerId); // Unique answer if ($qtype == UNIQUE_ANSWER || $qtype == TRUE_FALSE) { // Construct the identifier $htmlQuestionId = 'unique_' . $questionCount . '_x'; $pageBody .= '<tr><td width="5%" align="center"> <input type="radio" name="' . $htmlQuestionId . '" id="scorm_' . $idCounter . '" value="' . $answer->selectWeighting($answerId) . '"></td> <td width="95%"><label for="scorm_' . $idCounter . '">' . $answerText . '</label> </td></tr>'; $idCounter++; } // Multiple answers elseif ($qtype == MULTIPLE_ANSWER) { // Construct the identifier $htmlQuestionId = 'multiple_' . $questionCount . '_' . $answerId; // Compute the score modifier if this answer is checked $raw = $answer->selectWeighting($answerId); $pageBody .= '<tr><td width="5%" align="center"> <input type="checkbox" name="' . $htmlQuestionId . '" id="scorm_' . $idCounter . '" value="' . $raw . '"></td> <td width="95%"><label for="scorm_' . $idCounter . '">' . $answerText . '</label> </td></tr>'; $idCounter++; } // Fill in blanks elseif ($qtype == FILL_IN_BLANKS || $qtype == FILL_IN_BLANKS_TOLERANT) { $pageBody .= '<tr><td colspan="2">'; // We must split the text, to be able to treat each input independently // separate the text and the scorings $explodedAnswer = explode('::', $answerText); $phrase = (isset($explodedAnswer[0])) ? $explodedAnswer[0] : ''; $weighting = (isset($explodedAnswer[1])) ? $explodedAnswer[1] : ''; $fillType = (!empty($explodedAnswer[2])) ? $explodedAnswer[2] : 1; // default value if value is invalid if ($fillType != TEXTFIELD_FILL && $fillType != LISTBOX_FILL) { $fillType = TEXTFIELD_FILL; } $wrongAnswers = (!empty($explodedAnswer[3])) ? explode('[', $explodedAnswer[3]) : array(); // get the scorings as a list $fillScoreList = explode(',', $weighting); $fillScoreCounter = 0; //listbox if ($fillType == LISTBOX_FILL) { // get the list of propositions (good and wrong) to display in lists // add wrongAnswers in the list $answerList = $wrongAnswers; // add good answers in the list // we save the answer because it will be modified $temp = $phrase; while (1) { // quits the loop if there are no more blanks if (($pos = strpos($temp, '[')) === false) { break; } // removes characters till '[' $temp = substr($temp, $pos + 1); // quits the loop if there are no more blanks if (($pos = strpos($temp, ']')) === false) { break; } // stores the found blank into the array $answerList[] = substr($temp, 0, $pos); // removes the character ']' $temp = substr($temp, $pos + 1); } // alphabetical sort of the array natcasesort($answerList); } // Split after each blank $responsePart = explode(']', $phrase); $acount = 0; foreach ($responsePart as $part) { // Split between text and (possible) blank if (strpos($part, '[') !== false) { list($rawtext, $blankText) = explode('[', $part); } else { $rawtext = $part; $blankText = ""; } $pageBody .= $rawtext; // If there's a blank to fill-in after the text (this is usually not the case at the end) if (!empty($blankText)) { // Build the element's name $name = 'fill_' . $questionCount . '_' . $acount; // Keep track of the correspondance between element's name and correct value + scoring $fillAnswerList[$name] = array($blankText, $fillScoreList[$fillScoreCounter]); if ($fillType == LISTBOX_FILL) {// listbox $pageBody .= '<select name="' . $name . '" id="scorm_' . $idCounter . '">' . "\n" . '<option value=""> </option>'; foreach ($answerList as $answer) { $pageBody .= '<option value="' . htmlspecialchars($answer) . '">' . $answer . '</option>' . "\n"; } $pageBody .= '</select>' . "\n"; } else { $pageBody .= '<input type="text" name="' . $name . '" size="10" id="scorm_' . $idCounter . '">'; } $fillScoreCounter++; $idCounter++; } $acount++; } $pageBody .= '</td></tr>' . "\n"; } // Matching elseif ($qtype == MATCHING) { if (!$answer->isCorrect($answerId)) { // Add the option as a possible answer. $Select[$answerId] = $answerText; } else { $pageBody .= '<tr><td colspan="2"> <table border="0" cellpadding="0" cellspacing="0" width="99%"> <tr> <td width="40%" valign="top"><b>' . $choiceCounter . '.</b> ' . $answerText . '</td> <td width="20%" valign="center"> <select name="matching_' . $questionCount . '_' . $answerId . '" id="scorm_' . $idCounter . '"> <option value="0">--</option>'; $idCounter++; // fills the list-box $letter = 'A'; foreach ($Select as $key => $val) { $scoreModifier = ( $key == $answer->isCorrect($answerId) ) ? $answer->selectWeighting($answerId) : 0; $pageBody .= '<option value="' . $scoreModifier . '">' . $letter++ . '</option>'; } $pageBody .= '</select></td><td width="40%" valign="top">'; if (isset($Select[$choiceCounter])) { $pageBody .= '<b>' . $letterCounter . '.</b> ' . $Select[$choiceCounter]; } $pageBody .= ' </td></tr></table></td></tr>' . "\n"; // Done with this one $letterCounter++; $choiceCounter++; // If the left side has been completely displayed : if ($answerId == $answerCount) { // Add all possibly remaining answers to the right while (isset($Select[$choiceCounter])) { $pageBody .= '<tr><td colspan="2"> <table border="0" cellpadding="0" cellspacing="0" width="99%"> <tr> <td width="40%"> </td> <td width="20%"> </td> <td width="40%"><b>' . $letterCounter . '.</b> ' . $Select[$choiceCounter] . '</td> </tr> </table> </td></tr>' . "\n"; $letterCounter++; $choiceCounter++; } // end while } // end if } // else } // end if (MATCHING) } // end for each answer // End of the question $pageBody .= '</tfoot></table>' . "\n\n"; } // foreach($questionList as $questionId) // No more questions, add the button. $pageEnd = '</td></tr> <tr> <td align="center"><br><input class="btn btn-primary" type="button" value="' . $langOk . '" onClick="calcScore()"></td> </tr> </table> </form> </div></body></html>' . "\n"; /* Generate the javascript that'll calculate the score * We have the following variables to help us : * $idCounter : number of elements to check. their id are "scorm_XY" * $raw_to_pass : score (on 100) needed to pass the quiz * $fillAnswerList : a list of arrays (text, score) indexed on <input>'s names * */ $pageHeader .= ' <script type="text/javascript" language="javascript"> var raw_to_pass = '******'; var weighting = ' . array_sum($questionPonderationList) . '; var rawScore; var scoreCommited = false; var showScore = true; var fillAnswerList = new Array();' . "\n"; // Add the data for fillAnswerList foreach ($fillAnswerList as $key => $val) { $pageHeader .= " fillAnswerList['" . $key . "'] = new Array('" . $val[0] . "', '" . $val[1] . "');\n"; } // This is the actual code present in every exported exercise. $pageHeader .= ' function calcScore() { if( !scoreCommited ) { rawScore = CalculateRawScore(document, ' . $idCounter . ', fillAnswerList); var score = Math.max(Math.round(rawScore * 100 / weighting), 0); var oldScore = doGetValue("cmi.score.raw"); doSetValue("cmi.score.max", weighting); doSetValue("cmi.score.min", 0); computeTime(); if (score > oldScore) // Update only if score is better than the previous time. { doSetValue("cmi.score.raw", rawScore); } var oldStatus = doGetValue( "cmi.success_status" ) if (score >= raw_to_pass) { doSetValue("cmi.success_status", "passed"); } else if (oldStatus != "passed" ) // If passed once, never mark it as failed. { doSetValue("cmi.success_status", "failed"); } doCommit(); doTerminate(); scoreCommited = true; if(showScore) alert(\'' . clean_str_for_javascript($langScore) . ' :\n\' + rawScore + \'/\' + weighting + \'\n\' + \'' . clean_str_for_javascript($langExerciseDone) . '\'); } } </script> '; // Construct the HTML file and save it. $filename = "quiz_" . $quizId . ".html"; $pageContent = $pageHeader . $pageBody . $pageEnd; if (!$f = fopen($this->destDir . '/' . $filename, 'w')) { $this->error[] = $GLOBALS['langErrorCreatingFile'] . $filename; return false; } fwrite($f, $pageContent); fclose($f); // Went well. return True; }
/** * Restore quiz-questions * @params int question id */ function restore_quiz_question($id) { $resources = $this->course->resources; $question = isset($resources[RESOURCE_QUIZQUESTION][$id]) ? $resources[RESOURCE_QUIZQUESTION][$id] : null; $new_id = 0; if (is_object($question)) { if ($question->is_restored()) { return $question->destination_id; } $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION); $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER); $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION); // check resources inside html from ckeditor tool and copy correct urls into recipient course $question->description = DocumentManager::replace_urls_inside_content_html_from_copy_course($question->description, $this->course->code, $this->course->destination_path); $parent_id = 0; if (isset($question->parent_info) && !empty($question->parent_info)) { $question_obj = Question::readByTitle($question->parent_info['question'], $this->destination_course_id); if ($question_obj) { // Reuse media. $parent_id = $question_obj->selectId(); } else { // Create media. $question_obj = new MediaQuestion(); $question_obj->updateCourse($this->destination_course_id); $parent_id = $question_obj->saveMedia(array('questionName' => $question->parent_info['question'], 'questionDescription' => $question->parent_info['description'])); } } $sql = "INSERT INTO " . $table_que . " SET\n c_id = " . $this->destination_course_id . " ,\n question = '" . self::DBUTF8escapestring($question->question) . "',\n description = '" . self::DBUTF8escapestring($question->description) . "',\n ponderation = '" . self::DBUTF8escapestring($question->ponderation) . "',\n position = '" . self::DBUTF8escapestring($question->position) . "',\n type='" . self::DBUTF8escapestring($question->quiz_type) . "',\n picture='" . self::DBUTF8escapestring($question->picture) . "',\n level='" . self::DBUTF8escapestring($question->level) . "',\n parent_id = '" . $parent_id . "',\n extra='" . self::DBUTF8escapestring($question->extra) . "'"; Database::query($sql); $new_id = Database::insert_id(); if ($new_id) { if (!empty($question->picture)) { $question_temp = Question::read($new_id, $this->destination_course_info['real_id']); $documentPath = api_get_path(SYS_COURSE_PATH) . $this->destination_course_info['path'] . '/document'; // picture path $picturePath = $documentPath . '/images'; $old_picture = api_get_path(SYS_COURSE_PATH) . $this->course->info['path'] . '/document/images/' . $question->picture; if (file_exists($old_picture)) { $picture_name = 'quiz-' . $new_id . '.jpg'; $result = $question_temp->uploadPicture($old_picture, $picture_name, $picturePath); if ($result) { $sql = "UPDATE {$table_que} SET picture = '{$picture_name}' WHERE c_id = " . $this->destination_course_id . " AND id = {$new_id} "; Database::query($sql); } } } } if ($question->type == MATCHING) { $temp = array(); $matching_list = array(); $matching_to_update = array(); foreach ($question->answers as $index => $answer) { $temp[$answer['position']] = $answer; if (!empty($answer['correct'])) { $matching_to_update[$answer['iid']] = $answer['correct']; } } foreach ($temp as $index => $answer) { $sql = "INSERT INTO " . $table_ans . " SET\n c_id = " . $this->destination_course_id . " ,\n question_id = '" . $new_id . "',\n answer = '" . self::DBUTF8escapestring($answer['answer']) . "',\n correct = '" . $answer['correct'] . "',\n comment = '" . self::DBUTF8escapestring($answer['comment']) . "',\n ponderation = '" . $answer['ponderation'] . "',\n position = '" . $answer['position'] . "',\n hotspot_coordinates = '" . $answer['hotspot_coordinates'] . "',\n hotspot_type = '" . $answer['hotspot_type'] . "'"; Database::query($sql); $new_answer_id = Database::insert_id(); $matching_list[$answer['iid']] = $new_answer_id; } foreach ($matching_to_update as $old_answer_id => $old_correct_id) { $new_correct = $matching_list[$old_correct_id]; $new_fixed_id = $matching_list[$old_answer_id]; $sql = "UPDATE {$table_ans} SET correct = '{$new_correct}' WHERE iid = {$new_fixed_id} "; Database::query($sql); } } else { $correct_answers = array(); foreach ($question->answers as $index => $answer) { // check resources inside html from fckeditor tool and copy correct urls into recipient course $answer['answer'] = DocumentManager::replace_urls_inside_content_html_from_copy_course($answer['answer'], $this->course->code, $this->course->destination_path, $this->course->backup_path, $this->course->info['path']); $answer['comment'] = DocumentManager::replace_urls_inside_content_html_from_copy_course($answer['comment'], $this->course->code, $this->course->destination_path, $this->course->backup_path, $this->course->info['path']); $sql = "INSERT INTO " . $table_ans . " SET\n c_id = " . $this->destination_course_id . " ,\n id = '" . ($index + 1) . "',\n question_id = '" . $new_id . "',\n answer = '" . self::DBUTF8escapestring($answer['answer']) . "',\n correct = '" . $answer['correct'] . "',\n comment = '" . self::DBUTF8escapestring($answer['comment']) . "',\n ponderation = '" . $answer['ponderation'] . "',\n position = '" . $answer['position'] . "',\n hotspot_coordinates = '" . $answer['hotspot_coordinates'] . "',\n hotspot_type = '" . $answer['hotspot_type'] . "'"; Database::query($sql); $new_answer_id = Database::insert_id(); $correct_answers[$new_answer_id] = $answer['correct']; } } //Current course id $course_id = api_get_course_int_id(); //Moving quiz_question_options if ($question->type == MULTIPLE_ANSWER_TRUE_FALSE) { $question_option_list = Question::readQuestionOption($id, $course_id); //Question copied from the current platform if ($question_option_list) { $old_option_ids = array(); foreach ($question_option_list as $item) { $old_id = $item['iid']; unset($item['iid']); $item['question_id'] = $new_id; $item['c_id'] = $this->destination_course_id; $question_option_id = Database::insert($table_options, $item); $old_option_ids[$old_id] = $question_option_id; } if ($old_option_ids) { $new_answers = Database::select('iid, correct', $table_ans, array('WHERE' => array('question_id = ? AND c_id = ? ' => array($new_id, $this->destination_course_id)))); foreach ($new_answers as $answer_item) { $params = array(); $params['correct'] = $old_option_ids[$answer_item['correct']]; $question_option_id = Database::update($table_ans, $params, array('iid = ? AND c_id = ? AND question_id = ? ' => array($answer_item['iid'], $this->destination_course_id, $new_id)), false); } } } else { $new_options = array(); if (isset($question->question_options)) { foreach ($question->question_options as $obj) { $item = array(); $item['question_id'] = $new_id; $item['c_id'] = $this->destination_course_id; $item['name'] = $obj->obj->name; $item['position'] = $obj->obj->position; $question_option_id = Database::insert($table_options, $item); $new_options[$obj->obj->iid] = $question_option_id; } foreach ($correct_answers as $answer_id => $correct_answer) { $params = array(); $params['correct'] = $new_options[$correct_answer]; Database::update($table_ans, $params, array('iid = ? AND c_id = ? AND question_id = ? ' => array($answer_id, $this->destination_course_id, $new_id)), false); } } } } if ($question->categories) { $cats = array(); foreach ($question->categories as $cat) { $new_category = new Testcategory($cat['category_id']); $new_category = $new_category->get_category_by_title($cat['title'], $this->destination_course_id); if (empty($new_category)) { //Create a new category in this portal if ($cat['category_id'] == 0) { $category_c_id = 0; } else { $category_c_id = $this->destination_course_id; } $new_cat = new Testcategory(null, $cat['title'], $cat['description'], null, 'simple', $category_c_id); $new_cat_id = $new_cat->addCategoryInBDD(); $cats[] = $new_cat_id; } else { $cats[] = $new_category['iid']; } } $question = Question::read($new_id, $this->destination_course_id); if (!empty($cats)) { $question->saveCategories($cats); } } $this->course->resources[RESOURCE_QUIZQUESTION][$id]->destination_id = $new_id; } return $new_id; }
/** * Handles a given Excel spreadsheets as in the template provided */ function lp_upload_quiz_action_handling() { global $debug; $_course = api_get_course_info(); $courseId = $_course['real_id']; if (!isset($_POST['submit_upload_quiz'])) { return; } // Get the extension of the document. $path_info = pathinfo($_FILES['user_upload_quiz']['name']); // Check if the document is an Excel document if ($path_info['extension'] != 'xls') { return; } // Read the Excel document $data = new Spreadsheet_Excel_Reader(); // Set output Encoding. $data->setOutputEncoding(api_get_system_encoding()); // Reading the xls document. $data->read($_FILES['user_upload_quiz']['tmp_name']); $correctScore = isset($_POST['correct_score']) ? $_POST['correct_score'] : null; $incorrectScore = isset($_POST['incorrect_score']) ? $_POST['incorrect_score'] : null; $useCustomScore = isset($_POST['user_custom_score']) ? true : false; $propagateNegative = 0; if ($useCustomScore && !empty($incorrectScore)) { if ($incorrectScore < 0) { $propagateNegative = 1; } } // Variables $quiz_index = 0; $question_title_index = array(); $question_name_index_init = array(); $question_name_index_end = array(); $score_index = array(); $feedback_true_index = array(); $feedback_false_index = array(); $number_questions = 0; $question_description_index = array(); // Reading all the first column items sequentially to create breakpoints for ($i = 1; $i <= $data->sheets[0]['numRows']; $i++) { if ($data->sheets[0]['cells'][$i][1] == 'Quiz' && $i == 1) { $quiz_index = $i; // Quiz title position, only occurs once } elseif ($data->sheets[0]['cells'][$i][1] == 'Question') { $question_title_index[] = $i; // Question title position line $question_name_index_init[] = $i + 1; // Questions name 1st position line $number_questions++; } elseif ($data->sheets[0]['cells'][$i][1] == 'Score') { $question_name_index_end[] = $i - 1; // Question name position $score_index[] = $i; // Question score position } elseif ($data->sheets[0]['cells'][$i][1] == 'FeedbackTrue') { $feedback_true_index[] = $i; // FeedbackTrue position (line) } elseif ($data->sheets[0]['cells'][$i][1] == 'FeedbackFalse') { $feedback_false_index[] = $i; // FeedbackFalse position (line) } elseif ($data->sheets[0]['cells'][$i][1] == 'EnrichQuestion') { $question_description_index[] = $i; } } // Variables $quiz = array(); $question = array(); $new_answer = array(); $score_list = array(); $feedback_true_list = array(); $feedback_false_list = array(); $question_description = array(); // Getting questions. $k = $z = $q = $l = $m = 0; for ($i = 1; $i <= $data->sheets[0]['numRows']; $i++) { if (is_array($data->sheets[0]['cells'][$i])) { $column_data = $data->sheets[0]['cells'][$i]; // Fill all column with data to have a full array for ($x = 1; $x <= $data->sheets[0]['numCols']; $x++) { if (empty($column_data[$x])) { $data->sheets[0]['cells'][$i][$x] = ''; } } // Array filled with data $column_data = $data->sheets[0]['cells'][$i]; } else { $column_data = ''; } // Fill quiz data if ($quiz_index == $i) { // The title always in the first position $quiz = $column_data; } elseif (in_array($i, $question_title_index)) { //a complete line where 1st column is 'Question' $question[$k] = $column_data; $k++; } elseif (in_array($i, $score_index)) { //a complete line where 1st column is 'Score' $score_list[$z] = $column_data; $z++; } elseif (in_array($i, $feedback_true_index)) { //a complete line where 1st column is 'FeedbackTrue' $feedback_true_list[$q] = $column_data; $q++; } elseif (in_array($i, $feedback_false_index)) { //a complete line where 1st column is 'FeedbackFalse' for wrong answers $feedback_false_list[$l] = $column_data; $l++; } elseif (in_array($i, $question_description_index)) { //a complete line where 1st column is 'EnrichQuestion' $question_description[$m] = $column_data; $m++; } } // Get answers for ($i = 0; $i < count($question_name_index_init); $i++) { for ($j = $question_name_index_init[$i]; $j <= $question_name_index_end[$i]; $j++) { if (is_array($data->sheets[0]['cells'][$j])) { $column_data = $data->sheets[0]['cells'][$j]; // Fill all column with data for ($x = 1; $x <= $data->sheets[0]['numCols']; $x++) { if (empty($column_data[$x])) { $data->sheets[0]['cells'][$j][$x] = ''; } } $column_data = $data->sheets[0]['cells'][$j]; // Array filled of data if (is_array($data->sheets[0]['cells'][$j]) && count($data->sheets[0]['cells'][$j]) > 0) { $new_answer[$i][$j] = $data->sheets[0]['cells'][$j]; } } } } // Quiz title. $quiz_title = $quiz[2]; if ($quiz_title != '') { // Variables $type = 2; $random = $active = $results = $max_attempt = $expired_time = 0; // Make sure feedback is enabled (3 to disable), otherwise the fields // added to the XLS are not shown, which is confusing $feedback = 0; // Quiz object $exercise = new Exercise(); // $quiz_id = $exercise->createExercise($quiz_title, $expired_time, $type, $random, $active, $results, $max_attempt, $feedback, $propagateNegative); if ($quiz_id) { // insert into the item_property table api_item_property_update($_course, TOOL_QUIZ, $quiz_id, 'QuizAdded', api_get_user_id()); // Import questions. for ($i = 0; $i < $number_questions; $i++) { // Question name $question_title = $question[$i][2]; $question_description_text = "<p></p>"; if (isset($question_description[$i][2])) { // Question description. $question_description_text = "<p>" . $question_description[$i][2] . "</p>"; } // Unique answers are the only question types available for now // through xls-format import $question_id = null; $detectQuestionType = detectQuestionType($new_answer[$i], $score_list); /** @var Question $answer */ switch ($detectQuestionType) { case FREE_ANSWER: $answer = new FreeAnswer(); break; case GLOBAL_MULTIPLE_ANSWER: $answer = new GlobalMultipleAnswer(); break; case MULTIPLE_ANSWER: $answer = new MultipleAnswer(); break; case UNIQUE_ANSWER: default: $answer = new UniqueAnswer(); break; } if ($question_title != '') { $question_id = $answer->create_question($quiz_id, $question_title, $question_description_text, 0, $answer->type); } $total = 0; if (is_array($new_answer[$i]) && !empty($question_id)) { $id = 1; $answers_data = $new_answer[$i]; $globalScore = null; $objAnswer = new Answer($question_id, $courseId); $globalScore = $score_list[$i][3]; // Calculate the number of correct answers to divide the // score between them when importing from CSV $numberRightAnswers = 0; foreach ($answers_data as $answer_data) { if (strtolower($answer_data[3]) == 'x') { $numberRightAnswers++; } } foreach ($answers_data as $answer_data) { $answerValue = $answer_data[2]; $correct = 0; $score = 0; if (strtolower($answer_data[3]) == 'x') { $correct = 1; $score = $score_list[$i][3]; $comment = $feedback_true_list[$i][2]; } else { $comment = $feedback_false_list[$i][2]; $floatVal = (double) $answer_data[3]; if (is_numeric($floatVal)) { $score = $answer_data[3]; } } if ($useCustomScore) { if ($correct) { $score = $correctScore; } else { $score = $incorrectScore; } } // Fixing scores: switch ($detectQuestionType) { case GLOBAL_MULTIPLE_ANSWER: $score /= $numberRightAnswers; break; case UNIQUE_ANSWER: break; case MULTIPLE_ANSWER: if (!$correct) { //$total = $total - $score; } break; } $objAnswer->createAnswer($answerValue, $correct, $comment, $score, $id); $total += $score; $id++; } $objAnswer->save(); $questionObj = Question::read($question_id, $courseId); switch ($detectQuestionType) { case GLOBAL_MULTIPLE_ANSWER: $questionObj->updateWeighting($globalScore); break; case UNIQUE_ANSWER: case MULTIPLE_ANSWER: default: $questionObj->updateWeighting($total); break; } $questionObj->save(); } else { if ($detectQuestionType === FREE_ANSWER) { $questionObj = Question::read($question_id, $courseId); $globalScore = $score_list[$i][3]; $questionObj->updateWeighting($globalScore); $questionObj->save(); } } } } if (isset($_SESSION['lpobject'])) { if ($debug > 0) { error_log('New LP - SESSION[lpobject] is defined', 0); } $oLP = unserialize($_SESSION['lpobject']); if (is_object($oLP)) { if ($debug > 0) { error_log('New LP - oLP is object', 0); } if (empty($oLP->cc) or $oLP->cc != api_get_course_id()) { if ($debug > 0) { error_log('New LP - Course has changed, discard lp object', 0); } $oLP = null; Session::erase('oLP'); Session::erase('lpobject'); } else { $_SESSION['oLP'] = $oLP; } } } if (isset($_SESSION['oLP']) && isset($_GET['lp_id'])) { $previous = $_SESSION['oLP']->select_previous_item_id(); $parent = 0; // Add a Quiz as Lp Item $_SESSION['oLP']->add_item($parent, $previous, TOOL_QUIZ, $quiz_id, $quiz_title, ''); // Redirect to home page for add more content header('location: ../newscorm/lp_controller.php?' . api_get_cidreq() . '&action=add_item&type=step&lp_id=' . Security::remove_XSS($_GET['lp_id'])); exit; } else { // header('location: exercise.php?' . api_get_cidreq()); echo '<script>window.location.href = "' . api_get_path(WEB_CODE_PATH) . 'exercice/admin.php?' . api_get_cidReq() . '&exerciseId=' . $quiz_id . '&session_id=' . api_get_session_id() . '"</script>'; } } }
/** * Return the icon for the question type * @author hubert.borderiou 13-10-2011 */ function get_question_type_for_question($in_selectedcourse, $in_questionid) { $myObjQuestion = Question::read($in_questionid, $in_selectedcourse); $questionType = null; if (!empty($myObjQuestion)) { list($typeImg, $typeExpl) = $myObjQuestion->get_type_icon_html(); $questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, array(), 32), array()); unset($myObjQuestion); } return $questionType; }
$defaults['questionDescription'] = $objQuestion->description; $defaults['questionLevel'] = $objQuestion->level; $defaults['questionCategory'] = $objQuestion->category_list; $defaults['parent_id'] = $objQuestion->parent_id; $form->setDefaults($defaults); if ($form->validate()) { // question $objQuestion->processCreation($form, null); // answers $objQuestion->processAnswersCreation($form); } else { $form->display(); } break; case 'delete': $objQuestion = Question::read($_GET['id']); $objQuestion->delete(); break; } //jqgrid will use this URL to do the selects $url = api_get_path(WEB_AJAX_PATH) . 'model.ajax.php?a=get_course_exercise_medias'; //The order is important you need to check the the $column variable in the model.ajax.php file $columns = array(get_lang('Name'), get_lang('Actions')); //Column config $column_model = array(array('name' => 'name', 'index' => 'name', 'width' => '200', 'align' => 'left'), array('name' => 'actions', 'index' => 'actions', 'width' => '50', 'align' => 'left', 'formatter' => 'action_formatter', 'sortable' => 'false')); //Autowidth $extra_params['autowidth'] = 'true'; //height auto $extra_params['height'] = 'auto'; //With this function we can add actions to the jgrid (edit, delete, etc) $action_links = 'function action_formatter(cellvalue, options, rowObject) {
} if (!empty($gradebook) && $gradebook == 'view') { $interbreadcrumb[] = array('url' => '../gradebook/' . $_SESSION['gradebook_dest'], 'name' => get_lang('ToolGradebook')); } $interbreadcrumb[] = array("url" => "exercice.php", "name" => get_lang('Exercices')); Display::display_header($nameTools, "Exercise"); ?> <table border="0" align="center" cellpadding="2" cellspacing="2" width="100%"> <h4> <?php echo "Add Feedback"; ?> </h4> <?php $id = $_REQUEST['question']; $objQuestionTmp = Question::read($id); echo "<tr><td><b>" . get_lang('Question') . " : </b>"; echo $objQuestionTmp->selectTitle(); echo "</td></tr>"; echo " <br><tr><td><b><br>" . get_lang('Answer') . " : </b></td></tr>"; $objAnswerTmp = new Answer($id); $num = $objAnswerTmp->selectNbrAnswers(); $objAnswerTmp->read(); for ($i = 1; $i <= $num; $i++) { echo "<tr><td width='10%'> "; $ans = $objAnswerTmp->answer[$i]; $form = new FormValidator('feedbackform', 'post', api_get_self() . "?" . api_get_cidreq() . "&modifyQuestion=" . $modifyQuestion . "&newQuestion=" . $newQuestion); $obj_registration_form = new HTML_QuickForm('frmRegistration', 'POST'); $renderer =& $obj_registration_form->defaultRenderer(); $renderer->setElementTemplate('<tr> <td align="left" style="" valign="top" width=30%>{label}
<?php /* For licensing terms, see /license.txt */ /** * Statement (?) administration * This script allows to manage the statements of questions. * It is included from the script admin.php * @package chamilo.exercise * @author Olivier Brouckaert * @version $Id: question_admin.inc.php 22126 2009-07-15 22:38:39Z juliomontoya $ */ if (isset($_GET['editQuestion'])) { $objQuestion = Question::read($_GET['editQuestion']); $action = api_get_self() . "?" . api_get_cidreq() . "&myid=1&modifyQuestion=" . $modifyQuestion . "&editQuestion=" . $objQuestion->id; } else { $objQuestion = Question::getInstance($_REQUEST['answerType']); $action = api_get_self() . "?" . api_get_cidreq() . "&modifyQuestion=" . $modifyQuestion . "&newQuestion=" . $newQuestion; } if (is_object($objQuestion)) { // FORM CREATION $form = new FormValidator('question_admin_form', 'post', $action); if (isset($_GET['editQuestion'])) { $class = "btn btn-default"; $text = get_lang('ModifyQuestion'); $type = isset($_GET['type']) ? Security::remove_XSS($_GET['type']) : null; } else { $class = "btn btn-default"; $text = get_lang('AddQuestionToExercise'); $type = $_REQUEST['answerType']; } $typesInformation = Question::get_question_type_list();
public function show_media_content() { $html = null; if ($this->parent_id != 0) { $parent_question = Question::read($this->parent_id); $html = $parent_question->show_media_content(); } else { $html .= Display::page_subheader($this->selectTitle()); $html .= $this->selectDescription(); } return $html; }
* This file generates the ActionScript variables code used by the HotSpot .swf * @package chamilo.exercise * @author Toon Keppens * @version $Id: admin.php 10680 2007-01-11 21:26:23Z pcool $ */ /** * Code */ session_cache_limiter("none"); include 'exercise.class.php'; include 'question.class.php'; include 'answer.class.php'; include '../inc/global.inc.php'; // set vars $questionId = intval($_GET['modifyAnswers']); $objQuestion = Question::read($questionId); $answer_type = $objQuestion->selectType(); //very important $TBL_ANSWERS = Database::get_course_table(TABLE_QUIZ_ANSWER); $documentPath = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document'; $picturePath = $documentPath . '/images'; $pictureName = $objQuestion->selectPicture(); $pictureSize = getimagesize($picturePath . '/' . $objQuestion->selectPicture()); $pictureWidth = $pictureSize[0]; $pictureHeight = $pictureSize[1]; $courseLang = $_course['language']; $courseCode = $_course['sysCode']; $coursePath = $_course['path']; $course_id = api_get_course_int_id(); // Query db for answers if ($answer_type == HOT_SPOT_DELINEATION) {