/** * This page export the game millionaire to html * * @author bdaloukas * @version $Id: exporthtml_millionaire.php,v 1.14 2012/07/25 11:16:03 bdaloukas Exp $ * @package game **/ function game_millionaire_html_getquestions($game, $context, &$maxanswers, &$countofquestions, &$retfeedback, $destdir, &$files) { global $CFG, $DB, $USER; $maxanswers = 0; $countofquestions = 0; $files = array(); if ($game->sourcemodule != 'quiz' and $game->sourcemodule != 'question') { print_error(get_string('millionaire_sourcemodule_must_quiz_question', 'game', get_string('modulename', 'quiz')) . ' ' . get_string('modulename', $game->sourcemodule)); } if ($game->sourcemodule == 'quiz') { if ($game->quizid == 0) { print_error(get_string('must_select_quiz', 'game')); } $select = "qtype='multichoice' AND quiz='{$game->quizid}' " . " AND qqi.question=q.id"; $table = "{question} q,{quiz_question_instances} qqi"; } else { if ($game->questioncategoryid == 0) { print_error(get_string('must_select_questioncategory', 'game')); } //include subcategories $select = 'category=' . $game->questioncategoryid; if ($game->subcategories) { $cats = question_categorylist($game->questioncategoryid); if (strpos($cats, ',') > 0) { $select = 'category in (' . $cats . ')'; } } $select .= " AND qtype='multichoice'"; $table = "{question} q"; } $select .= " AND q.hidden=0"; $sql = "SELECT q.id as id, q.questiontext FROM {$table} WHERE {$select}"; $recs = $DB->get_records_sql($sql); $ret = ''; $retfeedback = ''; foreach ($recs as $rec) { $recs2 = $DB->get_records('question_answers', array('question' => $rec->id), 'fraction DESC', 'id,answer,feedback'); //Must parse the questiontext and get the name of files. $line = $rec->questiontext; $line = game_export_split_files($game->course, $context, 'questiontext', $rec->id, $rec->questiontext, $destdir, $files); $linefeedback = ''; foreach ($recs2 as $rec2) { $line .= '#' . str_replace(array('"', '#'), array("'", ' '), game_export_split_files($game->course, $context, 'answer', $rec2->id, $rec2->answer, $destdir, $files)); $linefeedback .= '#' . str_replace(array('"', '#'), array("'", ' '), $rec2->feedback); } if ($ret != '') { $ret .= ",\r"; } $ret .= '"' . base64_encode($line) . '"'; if ($retfeedback != '') { $retfeedback .= ",\r"; } $retfeedback .= '"' . base64_encode($linefeedback) . '"'; if (count($recs2) > $maxanswers) { $maxanswers = count($recs2); } $countofquestions++; } return $ret; }
/** * Function to read all questions for category into big array * * @param int $category category number * @param bool $noparent if true only questions with NO parent will be selected * @param bool $recurse include subdirectories * @param bool $export set true if this is called by questionbank export */ function get_questions_category($category, $noparent = false, $recurse = true, $export = true) { global $DB; // Build sql bit for $noparent $npsql = ''; if ($noparent) { $npsql = " and parent='0' "; } // Get list of categories if ($recurse) { $categorylist = question_categorylist($category->id); } else { $categorylist = array($category->id); } // Get the list of questions for the category list($usql, $params) = $DB->get_in_or_equal($categorylist); $questions = $DB->get_records_select('question', "category {$usql} {$npsql}", $params, 'qtype, name'); // Iterate through questions, getting stuff we need $qresults = array(); foreach ($questions as $key => $question) { $question->export_process = $export; $qtype = question_bank::get_qtype($question->qtype, false); if ($export && $qtype->name() == 'missingtype') { // Unrecognised question type. Skip this question when exporting. continue; } $qtype->get_question_options($question); $qresults[] = $question; } return $qresults; }
/** * Initialize the object so it will be ready to return where() and params() */ private function init() { global $DB; if (!($this->category = $this->get_current_category($this->cat))) { return; } if ($this->recurse) { $categoryids = question_categorylist($this->category->id); } else { $categoryids = array($this->category->id); } list($catidtest, $this->params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'cat'); $this->where = 'q.category ' . $catidtest; }
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { global $QTYPE_EXCLUDE_FROM_RANDOM; // Choose a random question from the category: // We need to make sure that no question is used more than once in the // quiz. Therfore the following need to be excluded: // 1. All questions that are explicitly assigned to the quiz // 2. All random questions // 3. All questions that are already chosen by an other random question // 4. Deleted questions if (!isset($cmoptions->questionsinuse)) { $cmoptions->questionsinuse = $attempt->layout; } if (!isset($this->catrandoms[$question->category][$question->questiontext])) { // Need to fetch random questions from category $question->category" // (Note: $this refers to the questiontype, not the question.) global $CFG; if ($question->questiontext == "1") { // recurse into subcategories $categorylist = question_categorylist($question->category); } else { $categorylist = $question->category; } if ($catrandoms = get_records_select('question', "category IN ({$categorylist})\n AND parent = '0'\n AND hidden = '0'\n AND id NOT IN ({$cmoptions->questionsinuse})\n AND qtype NOT IN ({$QTYPE_EXCLUDE_FROM_RANDOM})", '', 'id')) { $this->catrandoms[$question->category][$question->questiontext] = draw_rand_array($catrandoms, count($catrandoms)); // from bug 1889 } else { $this->catrandoms[$question->category][$question->questiontext] = array(); } } while ($wrappedquestion = array_pop($this->catrandoms[$question->category][$question->questiontext])) { if (!ereg("(^|,){$wrappedquestion->id}(,|\$)", $cmoptions->questionsinuse)) { /// $randomquestion is not in use and will therefore be used /// as the randomquestion here... $wrappedquestion = get_record('question', 'id', $wrappedquestion->id); global $QTYPES; $QTYPES[$wrappedquestion->qtype]->get_question_options($wrappedquestion); $QTYPES[$wrappedquestion->qtype]->create_session_and_responses($wrappedquestion, $state, $cmoptions, $attempt); $wrappedquestion->name_prefix = $question->name_prefix; $wrappedquestion->maxgrade = $question->maxgrade; $cmoptions->questionsinuse .= ",{$wrappedquestion->id}"; $state->options->question =& $wrappedquestion; return true; } } $question->questiontext = '<span class="notifyproblem">' . get_string('toomanyrandom', 'quiz') . '</span>'; $question->qtype = 'description'; $state->responses = array('' => ''); return true; }
/** * This page export the game millionaire to html * * @author bdaloukas * @version $Id: exporthtml_millionaire.php,v 1.9 2010/07/26 00:43:58 bdaloukas Exp $ * @package game **/ function game_millionaire_html_getquestions($game, &$max) { global $CFG, $DB, $USER; $max = 0; if ($game->sourcemodule != 'quiz' and $game->sourcemodule != 'question') { print_error(get_string('millionaire_sourcemodule_must_quiz_question', 'game', get_string('modulename', 'quiz')) . ' ' . get_string('modulename', $attempt->sourcemodule)); } if ($game->sourcemodule == 'quiz') { if ($game->quizid == 0) { print_error(get_string('must_select_quiz', 'game')); } $select = "qtype='multichoice' AND quiz='{$game->quizid}' " . " AND qqi.question=q.id"; $table = "{question} q,{quiz_question_instances} qqi"; } else { if ($game->questioncategoryid == 0) { print_error(get_string('must_select_questioncategory', 'game')); } //include subcategories $select = 'category=' . $game->questioncategoryid; if ($game->subcategories) { $cats = question_categorylist($game->questioncategoryid); if (strpos($cats, ',') > 0) { $select = 'category in (' . $cats . ')'; } } $select .= " AND qtype='multichoice'"; $table = "{question} q"; } $select .= " AND q.hidden=0"; $sql = "SELECT q.id as id, q.questiontext FROM {$table} WHERE {$select}"; $recs = $DB->get_records_sql($sql); $ret = ''; foreach ($recs as $rec) { $recs2 = $DB->get_records('question_answers', array('question' => $rec->id), 'fraction DESC', 'id,answer'); $line = $rec->questiontext; foreach ($recs2 as $rec2) { $line .= '#' . str_replace(array('"', '#'), array("'", ' '), $rec2->answer); } if ($ret != '') { $ret .= ",\r"; } $ret .= '"' . base64_encode($line) . '"'; if (count($recs2) > $max) { $max = count($recs2); } } return $ret; }
function game_showanswers_question($game) { global $DB; if ($game->gamekind != 'bookquiz') { $select = ' category=' . $game->questioncategoryid; if ($game->subcategories) { $cats = question_categorylist($game->questioncategoryid); if (strpos($cats, ',') > 0) { $select = ' category in (' . $cats . ')'; } } } else { $context = get_context_instance(50, $COURSE->id); $select = " contextid in ({$context->id})"; $select2 = ''; if ($recs = $DB->get_records_select('question_categories', $select, null, 'id,id')) { foreach ($recs as $rec) { $select2 .= ',' . $rec->id; } } $select = ' AND category IN (' . substr($select2, 1) . ')'; } $select .= ' AND hidden = 0 '; $select .= game_showanswers_appendselect($game); $showcategories = $game->gamekind == 'bookquiz'; $order = $showcategories ? 'category,questiontext' : 'questiontext'; game_showanswers_question_select($game, '{question} q', $select, '*', $order, $showcategories, $game->course); }
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { // Choose a random shortanswer question from the category: // We need to make sure that no question is used more than once in the // quiz. Therfore the following need to be excluded: // 1. All questions that are explicitly assigned to the quiz // 2. All random questions // 3. All questions that are already chosen by an other random question global $QTYPES; if (!isset($cmoptions->questionsinuse)) { $cmoptions->questionsinuse = $cmoptions->questions; } if ($question->options->subcats) { // recurse into subcategories $categorylist = question_categorylist($question->category); } else { $categorylist = $question->category; } $saquestions = $this->get_sa_candidates($categorylist, $cmoptions->questionsinuse); $count = count($saquestions); $wanted = $question->options->choose; $errorstr = ''; if ($count < $wanted && isteacherinanycourse()) { if ($count >= 2) { $errorstr = "Error: could not get enough Short-Answer questions!\n Got {$count} Short-Answer questions, but wanted {$wanted}.\n Reducing number to choose from to {$count}!"; $wanted = $question->options->choose = $count; } else { $errorstr = "Error: could not get enough Short-Answer questions!\n This can happen if all available Short-Answer questions are already\n taken up by other Random questions or Random Short-Answer question.\n Another possible cause for this error is that Short-Answer\n questions were deleted after this Random Short-Answer question was\n created."; } notify($errorstr); $errorstr = '<span class="notifyproblem">' . $errorstr . '</span>'; } if ($count < $wanted) { $question->questiontext = "{$errorstr}<br /><br />Insufficient selection options are\n available for this question, therefore it is not available in this\n quiz. Please inform your teacher."; // Treat this as a description from this point on $question->qtype = DESCRIPTION; return true; } $saquestions = draw_rand_array($saquestions, $question->options->choose); // from bug 1889 foreach ($saquestions as $key => $wrappedquestion) { if (!$QTYPES[$wrappedquestion->qtype]->get_question_options($wrappedquestion)) { return false; } // Now we overwrite the $question->options->answers field to only // *one* (the first) correct answer. This loop can be deleted to // take all answers into account (i.e. put them all into the // drop-down menu. $foundcorrect = false; foreach ($wrappedquestion->options->answers as $answer) { if ($foundcorrect || $answer->fraction != 1.0) { unset($wrappedquestion->options->answers[$answer->id]); } else { if (!$foundcorrect) { $foundcorrect = true; } } } if (!$QTYPES[$wrappedquestion->qtype]->create_session_and_responses($wrappedquestion, $state, $cmoptions, $attempt)) { return false; } $wrappedquestion->name_prefix = $question->name_prefix; $wrappedquestion->maxgrade = $question->maxgrade; $cmoptions->questionsinuse .= ",{$wrappedquestion->id}"; $state->options->subquestions[$key] = clone $wrappedquestion; } // Shuffle the answers (Do this always because this is a random question type) $subquestionids = array_values(array_map(create_function('$val', 'return $val->id;'), $state->options->subquestions)); $subquestionids = swapshuffle($subquestionids); // Create empty responses foreach ($subquestionids as $val) { $state->responses[$val] = ''; } return true; }
/** * Return all the question types used in this quiz. * * @param boolean $includepotential if the quiz include random questions, setting this flag to true will make the function to * return all the possible question types in the random questions category * @return array a sorted array including the different question types * @since Moodle 3.1 */ public function get_all_question_types_used($includepotential = false) { $questiontypes = array(); // To control if we need to look in categories for questions. $qcategories = array(); // We must be careful with random questions, if we find a random question we must assume that the quiz may content // any of the questions in the referenced category (or subcategories). foreach ($this->get_questions() as $questiondata) { if ($questiondata->qtype == 'random' and $includepotential) { $includesubcategories = (bool) $questiondata->questiontext; if (!isset($qcategories[$questiondata->category])) { $qcategories[$questiondata->category] = false; } if ($includesubcategories) { $qcategories[$questiondata->category] = true; } } else { if (!in_array($questiondata->qtype, $questiontypes)) { $questiontypes[] = $questiondata->qtype; } } } if (!empty($qcategories)) { // We have to look for all the question types in these categories. $categoriestolook = array(); foreach ($qcategories as $cat => $includesubcats) { if ($includesubcats) { $categoriestolook = array_merge($categoriestolook, question_categorylist($cat)); } else { $categoriestolook[] = $cat; } } $questiontypesincategories = question_bank::get_all_question_types_in_categories($categoriestolook); $questiontypes = array_merge($questiontypes, $questiontypesincategories); } $questiontypes = array_unique($questiontypes); sort($questiontypes); return $questiontypes; }
function game_questions_shortanswer_question($game) { if ($game->questioncategoryid == 0) { print_error(get_string('must_select_questioncategory', 'game')); } //include subcategories $select = 'q.category=' . $game->questioncategoryid; if ($game->subcategories) { $cats = question_categorylist($game->questioncategoryid); if (strpos($cats, ',') > 0) { $select = 'q.category in (' . $cats . ')'; } } $select .= " AND qtype='shortanswer' " . " AND qa.question=q.id" . " AND q.hidden=0"; $table = "{question} q,{question_answers} qa"; $fields = "qa.id as qaid, q.id, q.questiontext as questiontext, " . "qa.answer as answertext, q.id as questionid"; return game_questions_shortanswer_question_fraction($table, $fields, $select); }
/** * @return array of question category ids of the category and all subcategories. */ function question_categorylist($categoryid) { global $DB; $subcategories = $DB->get_records('question_categories', array('parent' => $categoryid), 'sortorder ASC', 'id, 1'); $categorylist = array($categoryid); foreach ($subcategories as $subcategory) { $categorylist = array_merge($categorylist, question_categorylist($subcategory->id)); } return $categorylist; }
/** * Get all the usable questions from a particular question category. * * @param integer $categoryid the id of a question category. * @param boolean whether to include questions from subcategories. * @param string $questionsinuse comma-separated list of question ids to exclude from consideration. * @return array of question records. */ function get_usable_questions_from_category($categoryid, $subcategories, $questionsinuse) { global $DB; $this->init_qtype_lists(); if ($subcategories) { $categorylist = question_categorylist($categoryid); } else { $categorylist = $categoryid; } if (!$catrandoms = $DB->get_records_select('question', "category IN ($categorylist) AND parent = 0 AND hidden = 0 AND id NOT IN ($questionsinuse) AND qtype NOT IN ($this->excludedqtypes)", null, '', 'id')) { $catrandoms = array(); } return $catrandoms; }
/** * Randomly add a number of multichoice questions to an offlinequiz group. * * @param unknown_type $offlinequiz * @param unknown_type $addonpage * @param unknown_type $categoryid * @param unknown_type $number * @param unknown_type $includesubcategories */ function offlinequiz_add_random_questions($offlinequiz, $offlinegroup, $categoryid, $number, $recurse) { global $DB; $category = $DB->get_record('question_categories', array('id' => $categoryid)); if (!$category) { print_error('invalidcategoryid', 'error'); } $catcontext = context::instance_by_id($category->contextid); require_capability('moodle/question:useall', $catcontext); if ($recurse) { $categoryids = question_categorylist($category->id); } else { $categoryids = array($category->id); } list($qcsql, $qcparams) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'qc'); // Find all questions in the selected categories that are not in the offline group yet. $sql = "SELECT id\n FROM {question} q\n WHERE q.category {$qcsql}\n AND q.parent = 0\n AND q.hidden = 0\n AND q.qtype IN ('multichoice', 'multichoiceset')\n AND NOT EXISTS (SELECT 1 \n FROM {offlinequiz_group_questions} ogq\n WHERE ogq.questionid = q.id\n AND ogq.offlinequizid = :offlinequizid\n AND ogq.offlinegroupid = :offlinegroupid)"; $qcparams['offlinequizid'] = $offlinequiz->id; $qcparams['offlinegroupid'] = $offlinegroup->id; $questionids = $DB->get_fieldset_sql($sql, $qcparams); srand(microtime() * 1000000); shuffle($questionids); $chosenids = array(); while (($questionid = array_shift($questionids)) && $number > 0) { $chosenids[] = $questionid; $number -= 1; } $maxmarks = array(); if ($chosenids) { // Get the old maxmarks in case questions are already in other offlinequiz groups. list($qsql, $params) = $DB->get_in_or_equal($chosenids, SQL_PARAMS_NAMED); $sql = "SELECT id, questionid, maxmark\n FROM {offlinequiz_group_questions}\n WHERE offlinequizid = :offlinequizid\n AND questionid {$qsql}"; $params['offlinequizid'] = $offlinequiz->id; if ($slots = $DB->get_records_sql($sql, $params)) { foreach ($slots as $slot) { if (!array_key_exists($slot->questionid, $maxmarks)) { $maxmarks[$slot->questionid] = $slot->maxmark; } } } } offlinequiz_add_questionlist_to_group($chosenids, $offlinequiz, $offlinegroup, null, $maxmarks); }
/** * Returns a comma separated list of ids of the category and all subcategories */ function question_categorylist($categoryid) { global $DB; // returns a comma separated list of ids of the category and all subcategories $categorylist = $categoryid; if ($subcategories = $DB->get_records('question_categories', array('parent' => $categoryid), 'sortorder ASC', 'id, 1')) { foreach ($subcategories as $subcategory) { $categorylist .= ',' . question_categorylist($subcategory->id); } } return $categorylist; }
/** * Prints the table of questions in a category with interactions * * @param object $course The course object * @param int $categoryid The id of the question category to be displayed * @param int $cm The course module record if we are in the context of a particular module, 0 otherwise * @param int $recurse This is 1 if subcategories should be included, 0 otherwise * @param int $page The number of the page to be displayed * @param int $perpage Number of questions to show per page * @param boolean $showhidden True if also hidden questions should be displayed * @param boolean $showquestiontext whether the text of each question should be shown in the list */ function question_list($contexts, $pageurl, $categoryandcontext, $cm = null, $recurse = 1, $page = 0, $perpage = 100, $showhidden = false, $sortorder = 'typename', $sortorderdecoded = 'qtype, name ASC', $showquestiontext = false, $addcontexts = array()) { global $USER, $CFG, $THEME, $COURSE; $lastchangedid = optional_param('lastchanged', 0, PARAM_INT); list($categoryid, $contextid) = explode(',', $categoryandcontext); $qtypemenu = question_type_menu(); $strcategory = get_string("category", "quiz"); $strquestion = get_string("question", "quiz"); $straddquestions = get_string("addquestions", "quiz"); $strimportquestions = get_string("importquestions", "quiz"); $strexportquestions = get_string("exportquestions", "quiz"); $strnoquestions = get_string("noquestions", "quiz"); $strselect = get_string("select", "quiz"); $strselectall = get_string("selectall", "quiz"); $strselectnone = get_string("selectnone", "quiz"); $strcreatenewquestion = get_string("createnewquestion", "quiz"); $strquestionname = get_string("questionname", "quiz"); $strdelete = get_string("delete"); $stredit = get_string("edit"); $strmove = get_string('moveqtoanothercontext', 'question'); $strview = get_string("view"); $straction = get_string("action"); $strrestore = get_string('restore'); $strtype = get_string("type", "quiz"); $strcreatemultiple = get_string("createmultiple", "quiz"); $strpreview = get_string("preview", "quiz"); if (!$categoryid) { echo "<p style=\"text-align:center;\"><b>"; print_string("selectcategoryabove", "quiz"); echo "</b></p>"; return; } if (!($category = get_record('question_categories', 'id', $categoryid, 'contextid', $contextid))) { notify('Category not found!'); return; } $catcontext = get_context_instance_by_id($contextid); $canadd = has_capability('moodle/question:add', $catcontext); //check for capabilities on all questions in category, will also apply to sub cats. $caneditall = has_capability('moodle/question:editall', $catcontext); $canuseall = has_capability('moodle/question:useall', $catcontext); $canmoveall = has_capability('moodle/question:moveall', $catcontext); if ($cm and $cm->modname == 'quiz') { $quizid = $cm->instance; } else { $quizid = 0; } $returnurl = $pageurl->out(); $questionurl = new moodle_url("{$CFG->wwwroot}/question/question.php", array('returnurl' => $returnurl)); if ($cm !== null) { $questionurl->param('cmid', $cm->id); } else { $questionurl->param('courseid', $COURSE->id); } $questionmoveurl = new moodle_url("{$CFG->wwwroot}/question/contextmoveq.php", array('returnurl' => $returnurl)); if ($cm !== null) { $questionmoveurl->param('cmid', $cm->id); } else { $questionmoveurl->param('courseid', $COURSE->id); } echo '<div class="boxaligncenter">'; $formatoptions = new stdClass(); $formatoptions->noclean = true; echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $COURSE->id); echo '<table><tr>'; if ($canadd) { echo '<td valign="top" align="right">'; popup_form($questionurl->out(false, array('category' => $category->id)) . '&qtype=', $qtypemenu, "addquestion", "", "choose", "", "", false, "self", "<strong>{$strcreatenewquestion}</strong>"); echo '</td><td valign="top" align="right">'; helpbutton("questiontypes", $strcreatenewquestion, "quiz"); echo '</td>'; } else { echo '<td>'; print_string('nopermissionadd', 'question'); echo '</td>'; } echo '</tr></table>'; echo '</div>'; $categorylist = $recurse ? question_categorylist($category->id) : $category->id; // hide-feature $showhidden = $showhidden ? '' : " AND hidden = '0'"; if (!($totalnumber = count_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}"))) { echo "<p style=\"text-align:center;\">"; print_string("noquestions", "quiz"); echo "</p>"; return; } if (!($questions = get_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}", $sortorderdecoded, '*', $page * $perpage, $perpage))) { // There are no questions on the requested page. $page = 0; if (!($questions = get_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}", $sortorderdecoded, '*', 0, $perpage))) { // There are no questions at all echo "<p style=\"text-align:center;\">"; print_string("noquestions", "quiz"); echo "</p>"; return; } } print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage'); echo question_sort_options($pageurl, $sortorder); echo '<form method="post" action="edit.php">'; echo '<fieldset class="invisiblefieldset" style="display: block;">'; echo '<input type="hidden" name="sesskey" value="' . $USER->sesskey . '" />'; echo $pageurl->hidden_params_out(); echo '<table id="categoryquestions" style="width: 100%"><tr>'; echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$straction}</th>"; echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">{$strquestionname}</th>\n <th style=\"white-space:nowrap; text-align: right;\" class=\"header\" scope=\"col\">{$strtype}</th>"; echo "</tr>\n"; foreach ($questions as $question) { $nameclass = ''; $textclass = ''; if ($question->hidden) { $nameclass = 'dimmed_text'; $textclass = 'dimmed_text'; } if ($showquestiontext) { $nameclass .= ' header'; } if ($question->id == $lastchangedid) { $nameclass = 'highlight'; } if ($nameclass) { $nameclass = 'class="' . $nameclass . '"'; } if ($textclass) { $textclass = 'class="' . $textclass . '"'; } echo "<tr>\n<td style=\"white-space:nowrap;\" {$nameclass}>\n"; $canuseq = question_has_capability_on($question, 'use', $question->category); if (function_exists('module_specific_actions')) { echo module_specific_actions($pageurl, $question->id, $cm->id, $canuseq); } // preview if ($canuseq) { $quizorcourseid = $quizid ? '&quizid=' . $quizid : '&courseid=' . $COURSE->id; link_to_popup_window('/question/preview.php?id=' . $question->id . $quizorcourseid, 'questionpreview', "<img src=\"{$CFG->pixpath}/t/preview.gif\" class=\"iconsmall\" alt=\"{$strpreview}\" />", 0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS); } // edit, hide, delete question, using question capabilities, not quiz capabilieies if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) { echo "<a title=\"{$stredit}\" href=\"" . $questionurl->out(false, array('id' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/t/edit.gif\" alt=\"{$stredit}\" /></a> "; } elseif (question_has_capability_on($question, 'view', $question->category)) { echo "<a title=\"{$strview}\" href=\"" . $questionurl->out(false, array('id' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/i/info.gif\" alt=\"{$strview}\" /></a> "; } if (question_has_capability_on($question, 'move', $question->category) && question_has_capability_on($question, 'view', $question->category)) { echo "<a title=\"{$strmove}\" href=\"" . $questionurl->out(false, array('id' => $question->id, 'movecontext' => 1)) . "\"><img\n src=\"{$CFG->pixpath}/t/move.gif\" alt=\"{$strmove}\" /></a> "; } if (question_has_capability_on($question, 'edit', $question->category)) { // hide-feature if ($question->hidden) { echo "<a title=\"{$strrestore}\" href=\"edit.php?" . $pageurl->get_query_string() . "&unhide={$question->id}&sesskey={$USER->sesskey}\"><img\n src=\"{$CFG->pixpath}/t/restore.gif\" alt=\"{$strrestore}\" /></a>"; } else { echo "<a title=\"{$strdelete}\" href=\"edit.php?" . $pageurl->get_query_string() . "&deleteselected={$question->id}&q{$question->id}=1\"><img\n src=\"{$CFG->pixpath}/t/delete.gif\" alt=\"{$strdelete}\" /></a>"; } } if ($caneditall || $canmoveall || $canuseall) { echo " <input title=\"{$strselect}\" type=\"checkbox\" name=\"q{$question->id}\" value=\"1\" />"; } echo "</td>\n"; echo "<td {$nameclass}>" . format_string($question->name) . "</td>\n"; echo "<td {$nameclass} style='text-align: right'>\n"; print_question_icon($question); echo "</td>\n"; echo "</tr>\n"; if ($showquestiontext) { echo '<tr><td colspan="3" ' . $textclass . '>'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; echo format_text($question->questiontext, $question->questiontextformat, $formatoptions, $COURSE->id); echo "</td></tr>\n"; } } echo "</table>\n"; $paging = print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage', false, true); if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) { if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) { $showall = '<a href="edit.php?' . $pageurl->get_query_string(array('qperpage' => 1000)) . '">' . get_string('showall', 'moodle', $totalnumber) . '</a>'; } else { $showall = '<a href="edit.php?' . $pageurl->get_query_string(array('qperpage' => DEFAULT_QUESTIONS_PER_PAGE)) . '">' . get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE) . '</a>'; } if ($paging) { $paging = substr($paging, 0, strrpos($paging, '</div>')); $paging .= "<br />{$showall}</div>"; } else { $paging = "<div class='paging'>{$showall}</div>"; } } echo $paging; if ($caneditall || $canmoveall || $canuseall) { echo '<a href="javascript:select_all_in(\'TABLE\',null,\'categoryquestions\');">' . $strselectall . '</a> /' . ' <a href="javascript:deselect_all_in(\'TABLE\',null,\'categoryquestions\');">' . $strselectnone . '</a>'; echo '<br />'; echo '<strong> ' . get_string('withselected', 'quiz') . ':</strong><br />'; if (function_exists('module_specific_buttons')) { echo module_specific_buttons($cm->id); } // print delete and move selected question if ($caneditall) { echo '<input type="submit" name="deleteselected" value="' . $strdelete . "\" />\n"; } if ($canmoveall && count($addcontexts)) { echo '<input type="submit" name="move" value="' . get_string('moveto', 'quiz') . "\" />\n"; question_category_select_menu($addcontexts, false, 0, "{$category->id},{$category->contextid}"); } if (function_exists('module_specific_controls') && $canuseall) { echo module_specific_controls($totalnumber, $recurse, $category, $cm->id); } } echo '</fieldset>'; echo "</form>\n"; }
/** * Get all the usable shortanswer questions from a particular question category. * * @param integer $categoryid the id of a question category. * @param bool $subcategories whether to include questions from subcategories. * @return array of question records. */ public function get_available_saquestions_from_category($categoryid, $subcategories) { if (isset($this->availablesaquestionsbycategory[$categoryid][$subcategories])) { return $this->availablesaquestionsbycategory[$categoryid][$subcategories]; } if ($subcategories) { $categoryids = question_categorylist($categoryid); } else { $categoryids = array($categoryid); } $questionids = question_bank::get_finder()->get_questions_from_categories($categoryids, "qtype = 'shortanswer'"); $this->availablesaquestionsbycategory[$categoryid][$subcategories] = $questionids; return $questionids; }
private function get_categories() { $cmid = optional_param('cmid', 0, PARAM_INT); $categoryparam = optional_param('category', '', PARAM_TEXT); $courseid = optional_param('courseid', 0, PARAM_INT); if ($cmid) { list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = question_edit_setup('editq', '/mod/quiz/edit.php', true); if ($pagevars['cat']) { $categoryparam = $pagevars['cat']; } } if ($categoryparam) { $catandcontext = explode(',', $categoryparam); $cats = question_categorylist($catandcontext[0]); return $cats; } else { if ($cmid) { list($module, $cm) = get_module_from_cmid($cmid); $courseid = $cm->course; require_login($courseid, false, $cm); $thiscontext = context_module::instance($cmid); } else { $module = null; $cm = null; if ($courseid) { $thiscontext = context_course::instance($courseid); } else { $thiscontext = null; } } } $cats = get_categories_for_contexts($thiscontext->id); return array_keys($cats); }
function game_millionaire_selectquestion(&$aanswer, $game, $attempt, &$millionaire, &$query, $context) { global $DB, $USER; if ($game->sourcemodule != 'quiz' and $game->sourcemodule != 'question') { print_error(get_string('millionaire_sourcemodule_must_quiz_question', 'game', get_string('modulename', 'quiz')) . ' ' . get_string('modulename', $attempt->sourcemodule)); } if ($millionaire->queryid != 0) { game_millionaire_loadquestions($game, $millionaire, $query, $aanswer, $context); return; } if ($game->sourcemodule == 'quiz') { if ($game->quizid == 0) { print_error(get_string('must_select_quiz', 'game')); } if (game_get_moodle_version() < '02.07') { $select = "qtype='multichoice' AND quiz='{$game->quizid}' AND qmo.questionid=q.id" . " AND qqi.question=q.id"; $table = "{quiz_question_instances} qqi,{question} q, {qtype_multichoice_options} qmo"; $order = ''; } else { $select = "qtype='multichoice' AND qs.quizid='{$game->quizid}' AND qmo.questionid=q.id" . " AND qs.questionid=q.id"; $table = "{quiz_slots} qs,{question} q, {qtype_multichoice_options} qmo"; $order = 'qs.page,qs.slot'; } } else { if ($game->questioncategoryid == 0) { print_error(get_string('must_select_questioncategory', 'game')); } // Include subcategories. $select = 'category=' . $game->questioncategoryid; if ($game->subcategories) { $cats = question_categorylist($game->questioncategoryid); if (count($cats)) { $select = 'q.category in (' . implode(',', $cats) . ')'; } } $select .= " AND qtype='multichoice' AND qmo.single=1 AND qmo.questionid=q.id"; $table = '{question} q, {qtype_multichoice_options} qmo'; } $select .= ' AND hidden=0'; if ($game->shuffle or $game->quizid == 0) { $questionid = game_question_selectrandom($game, $table, $select, 'q.id as id', true); } else { $questionid = game_millionaire_select_serial_question($game, $table, $select, 'q.id as id', $millionaire->level, $order); } if ($questionid == 0) { print_error(get_string('no_questions', 'game')); } $q = $DB->get_record('question', array('id' => $questionid), 'id,questiontext'); $recs = $DB->get_records('question_answers', array('question' => $questionid)); if ($recs === false) { print_error(get_string('no_questions', 'game')); } $correct = 0; $ids = array(); foreach ($recs as $rec) { $aanswer[] = game_filterquestion_answer(str_replace('\\"', '"', $rec->answer), $rec->id, $context->id, $game->course); $ids[] = $rec->id; if ($rec->fraction == 1) { $correct = $rec->id; } } $count = count($aanswer); for ($i = 1; $i <= $count; $i++) { $sel = mt_rand(0, $count - 1); $temp = array_splice($aanswer, $sel, 1); $aanswer[] = $temp[0]; $temp = array_splice($ids, $sel, 1); $ids[] = $temp[0]; } $query = new StdClass(); $query->attemptid = $attempt->id; $query->gamekind = $game->gamekind; $query->gameid = $game->id; $query->userid = $USER->id; $query->sourcemodule = $game->sourcemodule; $query->glossaryentryid = 0; $query->questionid = $questionid; $query->questiontext = addslashes($q->questiontext); $query->answertext = implode(',', $ids); $query->correct = array_search($correct, $ids) + 1; if (!($query->id = $DB->insert_record('game_queries', $query))) { print_error('error inserting to game_queries'); } $updrec = new StdClass(); $updrec->id = $millionaire->id; $updrec->queryid = $query->id; if (!($newid = $DB->update_record('game_millionaire', $updrec))) { print_error('error updating in game_millionaire'); } $score = $millionaire->level / 15; game_updateattempts($game, $attempt, $score, 0); game_update_queries($game, $attempt, $query, $score, ''); }
/** * The difference between this method an get_all_responses is that this * method is not passed a state object. It is the possible answers to a * question no matter what the state. * This method is not called for random questions. * @return array of possible answers. */ function get_possible_responses(&$question) { global $QTYPES; static $answers = array(); if (!isset($answers[$question->id])) { if ($question->options->subcats) { // recurse into subcategories $categorylist = question_categorylist($question->category); } else { $categorylist = $question->category; } $question->options->subquestions = $this->get_sa_candidates($categorylist); foreach ($question->options->subquestions as $key => $wrappedquestion) { if (!$QTYPES[$wrappedquestion->qtype]->get_question_options($wrappedquestion)) { return false; } // Now we overwrite the $question->options->answers field to only // *one* (the first) correct answer. This loop can be deleted to // take all answers into account (i.e. put them all into the // drop-down menu. $foundcorrect = false; foreach ($wrappedquestion->options->answers as $answer) { if ($foundcorrect || $answer->fraction != 1.0) { unset($wrappedquestion->options->answers[$answer->id]); } else { if (!$foundcorrect) { $foundcorrect = true; } } } } $answers[$question->id] = array(); if (is_array($question->options->subquestions)) { foreach ($question->options->subquestions as $subqid => $answer) { if ($answer->questiontext) { $ans = array_shift($answer->options->answers); $answer->answertext = $ans->answer; $r = new stdClass(); $r->answer = $answer->questiontext . ": " . $answer->answertext; $r->credit = 1; $answers[$question->id][$subqid] = array($ans->id => $r); } } } } return $answers[$question->id]; }
/** * Get all the usable questions from a particular question category. * * @param integer $categoryid the id of a question category. * @param boolean whether to include questions from subcategories. * @param string $questionsinuse comma-separated list of question ids to exclude from consideration. * @return array of question records. */ function get_usable_questions_from_category($categoryid, $subcategories, $questionsinuse) { $this->init_qtype_lists(); if ($subcategories) { $categorylist = question_categorylist($categoryid); } else { $categorylist = $categoryid; } if (!($catrandoms = get_records_select('question', "category IN ({$categorylist})\n AND parent = 0\n AND hidden = 0\n AND id NOT IN ({$questionsinuse})\n AND qtype NOT IN ({$this->excludedqtypes})", '', 'id'))) { $catrandoms = array(); } return $catrandoms; }
if (!($toparent = $DB->get_record('question_categories', array('id' => $toparent)))) { print_error('invalidcategoryidforparent', 'question', $onerrorurl); } $contextto = $toparent->contextid; } else { $toparent = new object(); $toparent->id = 0; $toparent->contextid = $contextto; } if (!($cattomove = $DB->get_record('question_categories', array('id' => $cattomove)))) { print_error('invalidcategoryidtomove', 'question', $onerrorurl); } if ($cattomove->contextid == $contextto) { print_error('contexterror', '', $onerrorurl); } $cattomove->categorylist = question_categorylist($cattomove->id); $thispageurl->params(array('cattomove' => $cattomove->id, 'toparent' => "{$toparent->id},{$toparent->contextid}", 'totop' => $totop)); $contextfrom = get_context_instance_by_id($cattomove->contextid); $contextto = get_context_instance_by_id($contextto); $contexttostring = print_context_name($contextto); require_capability('moodle/question:managecategory', $contextfrom); require_capability('moodle/question:managecategory', $contextto); $fromcoursefilesid = get_filesdir_from_context($contextfrom); //siteid or courseid $tocoursefilesid = get_filesdir_from_context($contextto); //siteid or courseid if ($fromcoursefilesid != $tocoursefilesid) { list($usql, $params) = $DB->get_in_or_equal(explode(',', $cattomove->categorylist)); $questions = $DB->get_records_select('question', "category {$usql}", $params); $urls = array(); if ($questions) {
function game_millionaire_SelectQuestion(&$aAnswer, $game, $attempt, &$millionaire, &$query) { global $CFG, $USER; if ($game->sourcemodule != 'quiz' and $game->sourcemodule != 'question') { error(get_string('millionaire_sourcemodule_must_quiz_question', 'game', get_string('modulename', 'quiz')) . ' ' . get_string('modulename', $attempt->sourcemodule)); } if ($millionaire->queryid != 0) { game_millionaire_loadquestions($millionaire, $query, $aAnswer); return; } if ($game->sourcemodule == 'quiz') { if ($game->quizid == 0) { error(get_string('must_select_quiz', 'game')); } $select = "qtype='multichoice' AND quiz='{$game->quizid}' " . " AND {$CFG->prefix}quiz_question_instances.question={$CFG->prefix}question.id"; $table = "question,{$CFG->prefix}quiz_question_instances"; } else { if ($game->questioncategoryid == 0) { error(get_string('must_select_questioncategory', 'game')); } //include subcategories $select = 'category=' . $game->questioncategoryid; if ($game->subcategories) { $cats = question_categorylist($game->questioncategoryid); if (strpos($cats, ',') > 0) { $select = 'category in (' . $cats . ')'; } } $select .= " AND qtype='multichoice'"; $table = "question"; } $select .= " AND {$CFG->prefix}question.hidden=0"; if ($game->shuffle or $game->quizid == 0) { $questionid = game_question_selectrandom($game, $table, $select, "{$CFG->prefix}question.id as id"); } else { $questionid = game_millionaire_select_serial_question($game, $table, $select, "{$CFG->prefix}question.id as id", $millionaire->level); } if ($questionid == 0) { error(get_string('millionaire_nowords', 'game')); } $q = get_record_select('question', "id={$questionid}", 'id,questiontext'); $recs = get_records_select('question_answers', "question={$questionid}"); if ($recs === false) { error(get_string('millionaire_no_questions', 'game')); } $correct = 0; $ids = array(); foreach ($recs as $rec) { $aAnswer[] = $rec->answer; $ids[] = $rec->id; if ($rec->fraction == 1) { $correct = $rec->id; } } $count = count($aAnswer); for ($i = 1; $i <= $count; $i++) { $sel = mt_rand(0, $count - 1); $temp = array_splice($aAnswer, $sel, 1); $aAnswer[] = $temp[0]; $temp = array_splice($ids, $sel, 1); $ids[] = $temp[0]; } $query = new StdClass(); $query->attemptid = $attempt->id; $query->gamekind = $game->gamekind; $query->gameid = $game->id; $query->userid = $USER->id; $query->sourcemodule = $game->sourcemodule; $query->questionid = $questionid; $query->questiontext = addslashes($q->questiontext); $query->answertext = implode(',', $ids); $query->correct = array_search($correct, $ids) + 1; if (!($query->id = insert_record('game_queries', $query))) { print_object($query); error('error inserting to game_queries'); } $updrec->id = $millionaire->id; $updrec->queryid = $query->id; if (!($newid = update_record('game_millionaire', $updrec))) { error('error updating in game_millionaire'); } $score = $millionaire->level / 15; game_updateattempts($game, $attempt, $score, 0); game_update_queries($game, $attempt, $query, $score, ''); }
/** * Returns a comma separated list of ids of the category and all subcategories */ function question_categorylist($categoryid) { // returns a comma separated list of ids of the category and all subcategories $categorylist = $categoryid; if ($subcategories = get_records('question_categories', 'parent', $categoryid, 'sortorder ASC', 'id, 1 AS notused')) { foreach ($subcategories as $subcategory) { $categorylist .= ',' . question_categorylist($subcategory->id); } } return $categorylist; }
protected function build_query_sql($category, $recurse, $showhidden) { global $DB; /// Get the required tables. $joins = array(); foreach ($this->requiredcolumns as $column) { $extrajoins = $column->get_extra_joins(); foreach ($extrajoins as $prefix => $join) { if (isset($joins[$prefix]) && $joins[$prefix] != $join) { throw new coding_exception('Join ' . $join . ' conflicts with previous join ' . $joins[$prefix]); } $joins[$prefix] = $join; } } /// Get the required fields. $fields = array('q.hidden', 'q.category'); foreach ($this->visiblecolumns as $column) { $fields = array_merge($fields, $column->get_required_fields()); } foreach ($this->extrarows as $row) { $fields = array_merge($fields, $row->get_required_fields()); } $fields = array_unique($fields); /// Build the order by clause. $sorts = array(); foreach ($this->sort as $sort => $order) { list($colname, $subsort) = $this->parse_subsort($sort); $sorts[] = $this->requiredcolumns[$colname]->sort_expression($order < 0, $subsort); } /// Build the where clause. $tests = array('q.parent = 0'); if (!$showhidden) { $tests[] = 'q.hidden = 0'; } if ($recurse) { $categoryids = question_categorylist($category->id); } else { $categoryids = array($category->id); } list($catidtest, $params) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'cat'); $tests[] = 'q.category ' . $catidtest; $this->sqlparams = $params; /// Build the SQL. $sql = ' FROM {question} q ' . implode(' ', $joins); $sql .= ' WHERE ' . implode(' AND ', $tests); $this->countsql = 'SELECT count(1)' . $sql; $this->loadsql = 'SELECT ' . implode(', ', $fields) . $sql . ' ORDER BY ' . implode(', ', $sorts); $this->sqlparams = $params; }
/** * Prints the table of questions in a category with interactions * * @param object $course The course object * @param int $categoryid The id of the question category to be displayed * @param int $quizid The quiz id if we are in the context of a particular quiz, 0 otherwise * @param int $recurse This is 1 if subcategories should be included, 0 otherwise * @param int $page The number of the page to be displayed * @param int $perpage Number of questions to show per page * @param boolean $showhidden True if also hidden questions should be displayed * @param boolean $showquestiontext whether the text of each question should be shown in the list */ function question_list($course, $categoryid, $quizid = 0, $recurse = 1, $page = 0, $perpage = 100, $showhidden = false, $sortorder = 'qtype, name ASC', $showquestiontext = false) { global $USER, $CFG, $THEME; $qtypemenu = question_type_menu(); if ($rqp_types = get_records('question_rqp_types')) { foreach ($rqp_types as $type) { $qtypemenu['rqp_' . $type->id] = $type->name; } } $strcategory = get_string("category", "quiz"); $strquestion = get_string("question", "quiz"); $straddquestions = get_string("addquestions", "quiz"); $strimportquestions = get_string("importquestions", "quiz"); $strexportquestions = get_string("exportquestions", "quiz"); $strnoquestions = get_string("noquestions", "quiz"); $strselect = get_string("select", "quiz"); $strselectall = get_string("selectall", "quiz"); $strselectnone = get_string("selectnone", "quiz"); $strcreatenewquestion = get_string("createnewquestion", "quiz"); $strquestionname = get_string("questionname", "quiz"); $strdelete = get_string("delete"); $stredit = get_string("edit"); $straction = get_string("action"); $strrestore = get_string('restore'); $straddtoquiz = get_string("addtoquiz", "quiz"); $strtype = get_string("type", "quiz"); $strcreatemultiple = get_string("createmultiple", "quiz"); $strpreview = get_string("preview", "quiz"); if (!$categoryid) { echo "<p style=\"text-align:center;\"><b>"; print_string("selectcategoryabove", "quiz"); echo "</b></p>"; if ($quizid) { echo "<p>"; print_string("addingquestions", "quiz"); echo "</p>"; } return; } if (!($category = get_record('question_categories', 'id', $categoryid))) { notify('Category not found!'); return; } $canedit = has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $category->course)); $editingquiz = false; if ($quizid) { $cm = get_coursemodule_from_instance('quiz', $quizid); $editingquiz = has_capability('mod/quiz:manage', get_context_instance(CONTEXT_MODULE, $cm->id)); } echo '<div class="boxaligncenter">'; $formatoptions = new stdClass(); $formatoptions->noclean = true; echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $course->id); echo '<table><tr>'; // check if editing questions in this category is allowed if ($canedit) { echo "<td valign=\"top\"><b>{$strcreatenewquestion}:</b></td>"; echo '<td valign="top" align="right">'; popup_form("{$CFG->wwwroot}/question/question.php?category={$category->id}&qtype=", $qtypemenu, "addquestion", "", "choose", "", "", false, "self"); echo '</td><td valign="top" align="right">'; helpbutton("questiontypes", $strcreatenewquestion, "quiz"); echo '</td>'; } else { echo '<td>'; print_string("publishedit", "quiz"); echo '</td>'; } echo '</tr></table>'; echo '</div>'; $categorylist = $recurse ? question_categorylist($category->id) : $category->id; // hide-feature $showhidden = $showhidden ? '' : " AND hidden = '0'"; if (!($totalnumber = count_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}"))) { echo "<p style=\"text-align:center;\">"; print_string("noquestions", "quiz"); echo "</p>"; return; } if (!($questions = get_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}", $sortorder, '*', $page * $perpage, $perpage))) { // There are no questions on the requested page. $page = 0; if (!($questions = get_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}", $sortorder, '*', 0, $perpage))) { // There are no questions at all echo "<p style=\"text-align:center;\">"; print_string("noquestions", "quiz"); echo "</p>"; return; } } print_paging_bar($totalnumber, $page, $perpage, "edit.php?courseid={$course->id}&perpage={$perpage}&"); echo '<form method="post" action="edit.php?courseid=' . $course->id . '">'; echo '<fieldset class="invisiblefieldset" style="display: block;">'; echo '<input type="hidden" name="sesskey" value="' . $USER->sesskey . '" />'; echo '<table id="categoryquestions" style="width: 100%"><tr>'; echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$straction}</th>"; $sortoptions = array('name, qtype ASC' => get_string("sortalpha", "quiz"), 'qtype, name ASC' => get_string("sorttypealpha", "quiz"), 'id ASC' => get_string("sortage", "quiz")); $orderselect = choose_from_menu($sortoptions, 'sortorder', $sortorder, false, 'this.form.submit();', '0', true); $orderselect .= '<noscript><div><input type="submit" value="' . get_string("sortsubmit", "quiz") . '" /></div></noscript>'; echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">{$strquestionname} {$orderselect}</th>\n <th style=\"white-space:nowrap; text-align: right;\" class=\"header\" scope=\"col\">{$strtype}</th>"; echo "</tr>\n"; foreach ($questions as $question) { $nameclass = ''; $textclass = ''; if ($question->hidden) { $nameclass = 'dimmed_text'; $textclass = 'dimmed_text'; } if ($showquestiontext) { $nameclass .= ' header'; } if ($nameclass) { $nameclass = 'class="' . $nameclass . '"'; } if ($textclass) { $textclass = 'class="' . $textclass . '"'; } echo "<tr>\n<td style=\"white-space:nowrap;\" {$nameclass}>\n"; // add to quiz if ($editingquiz) { echo "<a title=\"{$straddtoquiz}\" href=\"edit.php?addquestion={$question->id}&quizid={$quizid}&sesskey={$USER->sesskey}\"><img\n src=\"{$CFG->pixpath}/t/moveleft.gif\" alt=\"{$straddtoquiz}\" /></a> "; } // preview link_to_popup_window('/question/preview.php?id=' . $question->id . '&quizid=' . $quizid, 'questionpreview', "<img src=\"{$CFG->pixpath}/t/preview.gif\" class=\"iconsmall\" alt=\"{$strpreview}\" />", 0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS); // edit, hide, delete question, using question capabilities, not quiz capabilieies if ($canedit) { echo "<a title=\"{$stredit}\" href=\"{$CFG->wwwroot}/question/question.php?id={$question->id}\"><img\n src=\"{$CFG->pixpath}/t/edit.gif\" alt=\"{$stredit}\" /></a> "; // hide-feature if ($question->hidden) { echo "<a title=\"{$strrestore}\" href=\"edit.php?courseid={$course->id}&unhide={$question->id}&sesskey={$USER->sesskey}\"><img\n src=\"{$CFG->pixpath}/t/restore.gif\" alt=\"{$strrestore}\" /></a>"; } else { echo "<a title=\"{$strdelete}\" href=\"edit.php?courseid={$course->id}&deleteselected={$question->id}&q{$question->id}=1\"><img\n src=\"{$CFG->pixpath}/t/delete.gif\" alt=\"{$strdelete}\" /></a>"; } } echo " <input title=\"{$strselect}\" type=\"checkbox\" name=\"q{$question->id}\" value=\"1\" />"; echo "</td>\n"; echo "<td {$nameclass}>" . format_string($question->name) . "</td>\n"; echo "<td {$nameclass} style='text-align: right'>\n"; print_question_icon($question); echo "</td>\n"; echo "</tr>\n"; if ($showquestiontext) { echo '<tr><td colspan="3" ' . $textclass . '>'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; echo format_text($question->questiontext, $question->questiontextformat, $formatoptions, $course->id); echo "</td></tr>\n"; } } echo "</table>\n"; $paging = print_paging_bar($totalnumber, $page, $perpage, "edit.php?courseid={$course->id}&perpage={$perpage}&", 'page', false, true); if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) { if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) { $showall = '<a href="edit.php?courseid=' . $course->id . '&perpage=1000">' . get_string('showall', 'moodle', $totalnumber) . '</a>'; } else { $showall = '<a href="edit.php?courseid=' . $course->id . '&perpage=' . DEFAULT_QUESTIONS_PER_PAGE . '">' . get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE) . '</a>'; } if ($paging) { $paging = substr($paging, 0, strrpos($paging, '</div>')); $paging .= "<br />{$showall}</div>"; } else { $paging = "<div class='paging'>{$showall}</div>"; } } echo $paging; echo '<table class="quiz-edit-selected"><tr><td colspan="2">'; echo '<a href="javascript:select_all_in(\'TABLE\',null,\'categoryquestions\');">' . $strselectall . '</a> /' . ' <a href="javascript:deselect_all_in(\'TABLE\',null,\'categoryquestions\');">' . $strselectnone . '</a>' . '</td><td align="right"><b> ' . get_string('withselected', 'quiz') . ':</b></td></tr><tr><td>'; if ($editingquiz) { echo "<input type=\"submit\" name=\"add\" value=\"{$THEME->larrow} {$straddtoquiz}\" />\n"; echo '</td><td>'; } // print delete and move selected question if ($canedit) { echo '<input type="submit" name="deleteselected" value="' . $strdelete . "\" /></td><td>\n"; echo '<input type="submit" name="move" value="' . get_string('moveto', 'quiz') . "\" />\n"; question_category_select_menu($course->id, false, true, $category->id); } echo "</td></tr></table>"; // add random question if ($editingquiz) { for ($i = 1; $i <= min(10, $totalnumber); $i++) { $randomcount[$i] = $i; } for ($i = 20; $i <= min(100, $totalnumber); $i += 10) { $randomcount[$i] = $i; } echo '<br />'; print_string('addrandom', 'quiz', choose_from_menu($randomcount, 'randomcount', '1', '', '', '', true)); echo '<input type="hidden" name="recurse" value="' . $recurse . '" />'; echo "<input type=\"hidden\" name=\"categoryid\" value=\"{$category->id}\" />"; echo ' <input type="submit" name="addrandom" value="' . get_string('add') . '" />'; helpbutton('random', get_string('random', 'quiz'), 'quiz'); } echo '</fieldset>'; echo "</form>\n"; }
public function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) { // Choose a random shortanswer question from the category: // We need to make sure that no question is used more than once in the // quiz. Therfore the following need to be excluded: // 1. All questions that are explicitly assigned to the quiz // 2. All random questions // 3. All questions that are already chosen by an other random question. global $QTYPES, $OUTPUT, $USER; if (!isset($cmoptions->questionsinuse)) { $cmoptions->questionsinuse = $cmoptions->questions; } if ($question->options->subcats) { // Recurse into subcategories. $categorylist = question_categorylist($question->category); } else { $categorylist = array($question->category); } $saquestions = $this->get_sa_candidates($categorylist, $cmoptions->questionsinuse); $count = count($saquestions); $wanted = $question->options->choose; if ($count < $wanted) { $question->questiontext = "Insufficient selection options are\n available for this question, therefore it is not available in this\n quiz. Please inform your teacher."; // Treat this as a description from this point on. $question->qtype = 'description'; return true; } $saquestions = draw_rand_array($saquestions, $question->options->choose); // From bug 1889. foreach ($saquestions as $key => $wrappedquestion) { if (!$QTYPES[$wrappedquestion->qtype]->get_question_options($wrappedquestion)) { return false; } // Now we overwrite the $question->options->answers field to only // *one* (the first) correct answer. This loop can be deleted to // take all answers into account (i.e. put them all into the // drop-down menu. $foundcorrect = false; foreach ($wrappedquestion->options->answers as $answer) { if ($foundcorrect || $answer->fraction != 1.0) { unset($wrappedquestion->options->answers[$answer->id]); } else { if (!$foundcorrect) { $foundcorrect = true; } } } if (!$QTYPES[$wrappedquestion->qtype]->create_session_and_responses($wrappedquestion, $state, $cmoptions, $attempt)) { return false; } $wrappedquestion->name_prefix = $question->name_prefix; $wrappedquestion->maxgrade = $question->maxgrade; $cmoptions->questionsinuse .= ",{$wrappedquestion->id}"; $state->options->subquestions[$key] = clone $wrappedquestion; } // Shuffle the answers (Do this always because this is a random question type). $subquestionids = array_values(array_map(create_function('$val', 'return $val->id;'), $state->options->subquestions)); $subquestionids = swapshuffle($subquestionids); // Create empty responses. foreach ($subquestionids as $val) { $state->responses[$val] = ''; } return true; }
/** * Get all the usable questions from a particular question category. * * @param int $categoryid the id of a question category. * @param bool whether to include questions from subcategories. * @param string $questionsinuse comma-separated list of question ids to * exclude from consideration. * @return array of question records. */ public function get_available_questions_from_category($categoryid, $subcategories) { if (isset($this->availablequestionsbycategory[$categoryid][$subcategories])) { return $this->availablequestionsbycategory[$categoryid][$subcategories]; } $this->init_qtype_lists(); if ($subcategories) { $categoryids = question_categorylist($categoryid); } else { $categoryids = array($categoryid); } $questionids = question_bank::get_finder()->get_questions_from_categories( $categoryids, 'qtype NOT IN (' . $this->excludedqtypes . ')'); $this->availablequestionsbycategory[$categoryid][$subcategories] = $questionids; return $questionids; }
/** * Populate {@link $availablequestionscache} for this combination of options. * @param int $categoryid the id of a category in the question bank. * @param bool $includesubcategories wether to pick a question from exactly * that category, or that category and subcategories. */ protected function ensure_questions_for_category_loaded($categoryid, $includesubcategories) { global $DB; $categorykey = $this->get_category_key($categoryid, $includesubcategories); if (isset($this->availablequestionscache[$categorykey])) { // Data is already in the cache, nothing to do. return; } // Load the available questions from the question bank. if ($includesubcategories) { $categoryids = question_categorylist($categoryid); } else { $categoryids = array($categoryid); } list($extraconditions, $extraparams) = $DB->get_in_or_equal($this->excludedqtypes, SQL_PARAMS_NAMED, 'excludedqtype', false); $questionidsandcounts = \question_bank::get_finder()->get_questions_from_categories_with_usage_counts($categoryids, $this->qubaids, 'q.qtype ' . $extraconditions, $extraparams); if (!$questionidsandcounts) { // No questions in this category. $this->availablequestionscache[$categorykey] = array(); return; } // Put all the questions with each value of $prevusecount in separate arrays. $idsbyusecount = array(); foreach ($questionidsandcounts as $questionid => $prevusecount) { if (isset($this->recentlyusedquestions[$questionid])) { // Recently used questions are never returned. continue; } $idsbyusecount[$prevusecount][] = $questionid; } // Now put that data into our cache. For each count, we need to shuffle // questionids, and make those the keys of an array. $this->availablequestionscache[$categorykey] = array(); foreach ($idsbyusecount as $prevusecount => $questionids) { shuffle($questionids); $this->availablequestionscache[$categorykey][$prevusecount] = array_combine($questionids, array_fill(0, count($questionids), 1)); } ksort($this->availablequestionscache[$categorykey]); }