swapSimpleAnswerTypes();
Session::write('objQuestion', $objQuestion);
}
$objAnswer = Session::read('objAnswer');
$_course = api_get_course_info();
// tables used in the exercise tool.
if (!empty($_GET['action']) && 'exportqti2' === $_GET['action'] && !empty($_GET['questionId'])) {
require_once 'export/qti2/qti2_export.php';
$export = export_question_qti($_GET['questionId'], true);
$qid = (int) $_GET['questionId'];
$name = 'qti2_export_'.$qid.'.zip';
$zip = api_create_zip($name);
$zip->addFile("qti2export_$qid.xml", $export);
$zip->finish();
exit;
}
// Exercise object creation.
if (!($objExercise instanceof Exercise)) {
// creation of a new exercise if wrong or not specified exercise ID
if ($exerciseId) {
$objExercise = new Exercise();
$parseQuestionList = $showPagination > 0 ? false : true;
if ($editQuestion) {
$parseQuestionList = false;
$showPagination = true;
}
$objExercise->read($exerciseId, $parseQuestionList);
Session::write('objExercise', $objExercise);
}
}
// Exercise can be edited in their course.
if (empty($objExercise)) {
Session::erase('objExercise');
header('Location: '.api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq());
exit;
}
// Exercise can be edited in their course.
if ($objExercise->sessionId != $sessionId) {
api_not_allowed(true);
}
// doesn't select the exercise ID if we come from the question pool
if (!$fromExercise) {
// gets the right exercise ID, and if 0 creates a new exercise
if (!$exerciseId = $objExercise->getId()) {
$modifyExercise = 'yes';
}
}
$nbrQuestions = $objExercise->getQuestionCount();
// Question object creation.
if ($editQuestion || $newQuestion || $modifyQuestion || $modifyAnswers) {
if ($editQuestion || $newQuestion) {
// reads question data
if ($editQuestion) {
// question not found
if (!$objQuestion = Question::read($editQuestion)) {
api_not_allowed(true);
}
// saves the object into the session
Session::write('objQuestion', $objQuestion);
}
}
// checks if the object exists
if (is_object($objQuestion)) {
// gets the question ID
$questionId = $objQuestion->getId();
}
}
// if cancelling an exercise
if ($cancelExercise) {
// existing exercise
if ($exerciseId) {
unset($modifyExercise);
} else {
// new exercise
// goes back to the exercise list
header('Location: '.api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq());
exit();
}
}
// if cancelling question creation/modification
if ($cancelQuestion) {
// if we are creating a new question from the question pool
if (!$exerciseId && !$questionId) {
// goes back to the question pool
header('Location: question_pool.php?'.api_get_cidreq());
exit();
} else {
// goes back to the question viewing
$editQuestion = $modifyQuestion;
unset($newQuestion, $modifyQuestion);
}
}
if (!empty($cloneQuestion) && !empty($objExercise->getId())) {
$oldQuestionObj = Question::read($cloneQuestion);
$oldQuestionObj->question = $oldQuestionObj->question.' - '.get_lang('Copy');
$newId = $oldQuestionObj->duplicate(api_get_course_info());
$newQuestionObj = Question::read($newId);
$newQuestionObj->addToList($exerciseId);
// Save category to the destination course
if (!empty($oldQuestionObj->category)) {
$newQuestionObj->saveCategory($oldQuestionObj->category);
}
// This should be moved to the duplicate function
$newAnswerObj = new Answer($cloneQuestion);
$newAnswerObj->read();
$newAnswerObj->duplicate($newQuestionObj);
// Reloading tne $objExercise obj
$objExercise->read($objExercise->getId(), false);
Display::addFlash(Display::return_message(get_lang('Item copied')));
header('Location: admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->getId().'&page='.$page);
exit;
}
// if cancelling answer creation/modification
if ($cancelAnswers) {
// goes back to the question viewing
$editQuestion = $modifyAnswers;
unset($modifyAnswers);
}
$nameTools = '';
// modifies the query string that is used in the link of tool name
if ($editQuestion || $modifyQuestion || $newQuestion || $modifyAnswers) {
$nameTools = get_lang('Question / Answer management');
}
if (api_is_in_gradebook()) {
$interbreadcrumb[] = [
'url' => Category::getUrl(),
'name' => get_lang('Assessments'),
];
}
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'exercise/exercise.php?'.api_get_cidreq(),
'name' => get_lang('Tests'),
];
if (isset($_GET['newQuestion']) || isset($_GET['editQuestion'])) {
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'exercise/admin.php?exerciseId='.$objExercise->getId().'&'.api_get_cidreq(),
'name' => $objExercise->selectTitle(true),
];
} else {
$interbreadcrumb[] = [
'url' => '#',
'name' => $objExercise->selectTitle(true),
];
}
// shows a link to go back to the question pool
if (!$exerciseId && $nameTools != get_lang('Tests management')) {
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH)."exercise/question_pool.php?fromExercise=$fromExercise&".api_get_cidreq(),
'name' => get_lang('Recycle existing questions'),
];
}
// if the question is duplicated, disable the link of tool name
if ('thisExercise' === $modifyIn) {
if ($buttonBack) {
$modifyIn = 'allExercises';
}
}
$htmlHeadXtra[] = api_get_build_js('legacy_exercise.js');
$template = new Template();
$templateName = $template->get_template('exercise/submit.js.tpl');
$htmlHeadXtra[] = $template->fetch($templateName);
$htmlHeadXtra[] = api_get_js('d3/jquery.xcolor.js');
$htmlHeadXtra[] = '';
$htmlHeadXtra[] = '';
if (isset($_GET['message'])) {
if (in_array($_GET['message'], ['ExerciseStored', 'ItemUpdated', 'ItemAdded'])) {
Display::addFlash(Display::return_message(get_lang($_GET['message']), 'confirmation'));
}
}
Display::display_header($nameTools, 'Exercise');
// If we are in a test
$inATest = isset($exerciseId) && $exerciseId > 0;
if ($inATest) {
$actions = '';
if (isset($_GET['hotspotadmin']) || isset($_GET['newQuestion'])) {
$actions .= ''.
Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Go back to the questions list')).'';
}
if (!isset($_GET['hotspotadmin']) && !isset($_GET['newQuestion']) && !isset($_GET['editQuestion'])) {
$actions .= ''.
Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to tests list')).'';
}
$actions .= ''.
Display::getMdiIcon(ActionIcon::PREVIEW_CONTENT, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Preview')).'';
$actions .= Display::url(
Display::getMdiIcon('chart-box', 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Results and feedback')),
api_get_path(WEB_CODE_PATH).'exercise/exercise_report.php?'.api_get_cidreq().'&exerciseId='.$objExercise->getId()
);
$actions .= ''.
Display::getMdiIcon('cog', 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Edit test name and settings')).'';
$maxScoreAllQuestions = 0;
if (false === $showPagination) {
$questionList = $objExercise->selectQuestionList(true, $objExercise->random > 0 ? false : true);
if (!empty($questionList)) {
foreach ($questionList as $questionItemId) {
$question = Question::read($questionItemId);
if ($question) {
$maxScoreAllQuestions += $question->selectWeighting();
}
}
}
}
echo Display::toolbarAction('toolbar', [$actions]);
if ($objExercise->added_in_lp()) {
echo Display::return_message(
get_lang(
'This exercise has been included in a learning path, so it cannot be accessed by students directly from here. If you want to put the same exercise available through the exercises tool, please make a copy of the current exercise using the copy icon.'
),
'warning'
);
}
if ($editQuestion && $objQuestion->existsInAnotherExercise()) {
echo Display::return_message(
Display::getMdiIcon('alert', 'ch-tool-icon', null, ICON_SIZE_SMALL)
.get_lang('Warning: This question exists in another tests'),
'warning',
false
);
}
$alert = '';
if (false === $showPagination) {
$originalSelectionType = $objExercise->questionSelectionType;
$objExercise->questionSelectionType = EX_Q_SELECTION_ORDERED;
$outMaxScore = 0;
$outMaxScore = array_reduce(
$objExercise->selectQuestionList(true, true),
function ($acc, $questionId) {
$objQuestionTmp = Question::read($questionId);
return $acc + $objQuestionTmp->selectWeighting();
},
0
);
$objExercise->questionSelectionType = $originalSelectionType;
$alert .= sprintf(
get_lang('%d questions, for a total score (all questions) of %s.'),
$nbrQuestions,
$outMaxScore
);
}
if ($objExercise->random > 0) {
$alert .= '
'.sprintf(get_lang('OnlyXQuestionsPickedRandomly'), $objExercise->random);
$alert .= sprintf(
'
'.get_lang('XQuestionsSelectedWithTotalScoreY'),
$objExercise->random,
$maxScoreAllQuestions
);
}
if ($objExercise->random > 0) {
$alert .= '
'.sprintf(get_lang('OnlyXQuestionsPickedRandomly'), $objExercise->random);
$alert .= sprintf(
'
'.get_lang('XQuestionsSelectedWithTotalScoreY'),
$objExercise->random,
$maxScoreAllQuestions
);
}
if (false === $showPagination) {
if ($objExercise->questionSelectionType >= EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED) {
$alert .= sprintf(
'
'.get_lang(
'Only %d questions will be selected based on the test configuration, for a total score of %s.'
),
count($questionList),
$maxScoreAllQuestions
);
}
}
echo Display::return_message($alert, 'normal', false);
} elseif (isset($_GET['newQuestion'])) {
// we are in create a new question from question pool not in a test
$actions = ''.
Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Go back to the questions list')).'';
echo Display::toolbarAction('toolbar', [$actions]);
} else {
// If we are in question_pool but not in a test, go back to the questions created in pool
$actions = ''.
Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Go back to the questions list')).
'';
echo Display::toolbarAction('toolbar', [$actions]);
}
if ($newQuestion || $editQuestion) {
// Question management
$type = isset($_REQUEST['answerType']) ? Security::remove_XSS($_REQUEST['answerType']) : null;
echo '';
if ('yes' === $newQuestion) {
$objExercise->edit_exercise_in_lp = true;
require 'question_admin.inc.php';
}
if ($editQuestion) {
// Question preview if teacher clicked the "switch to student"
if ($studentViewActive && $is_allowedToEdit) {
echo '