コード例 #1
0
ファイル: questiontype_test.php プロジェクト: pzhu2004/moodle
 public function test_question_saving_sumwithvariants()
 {
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $questiondata = test_question_maker::get_question_data('calculatedsimple', 'sumwithvariants');
     $formdata = test_question_maker::get_question_form_data('calculatedsimple', 'sumwithvariants');
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category(array());
     $formdata->category = "{$cat->id},{$cat->contextid}";
     qtype_calculatedsimple_edit_form::mock_submit((array) $formdata);
     $form = qtype_calculatedsimple_test_helper::get_question_editing_form($cat, $questiondata);
     $this->assertTrue($form->is_validated());
     $fromform = $form->get_data();
     $returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
     $actualquestionsdata = question_load_questions(array($returnedfromsave->id));
     $actualquestiondata = end($actualquestionsdata);
     foreach ($questiondata as $property => $value) {
         if (!in_array($property, array('id', 'version', 'timemodified', 'timecreated', 'options'))) {
             $this->assertAttributeEquals($value, $property, $actualquestiondata);
         }
     }
     foreach ($questiondata->options as $optionname => $value) {
         if ($optionname != 'answers') {
             $this->assertAttributeEquals($value, $optionname, $actualquestiondata->options);
         }
     }
     foreach ($questiondata->options->answers as $answer) {
         $actualanswer = array_shift($actualquestiondata->options->answers);
         foreach ($answer as $ansproperty => $ansvalue) {
             if (!in_array($ansproperty, array('id', 'question', 'answerformat'))) {
                 $this->assertAttributeEquals($ansvalue, $ansproperty, $actualanswer);
             }
         }
     }
     $datasetloader = new qtype_calculated_dataset_loader($actualquestiondata->id);
     $this->assertEquals(10, $datasetloader->get_number_of_items());
     for ($itemno = 1; $itemno <= 10; $itemno++) {
         $item = $datasetloader->get_values($itemno);
         $this->assertEquals($formdata->number[($itemno - 1) * 2 + 2], $item['a']);
         $this->assertEquals($formdata->number[($itemno - 1) * 2 + 1], $item['b']);
     }
 }
コード例 #2
0
ファイル: questiontype_test.php プロジェクト: evltuma/moodle
 public function test_question_saving_true()
 {
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $questiondata = test_question_maker::get_question_data('truefalse');
     $formdata = test_question_maker::get_question_form_data('truefalse');
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category(array());
     $formdata->category = "{$cat->id},{$cat->contextid}";
     qtype_truefalse_edit_form::mock_submit((array) $formdata);
     $form = qtype_truefalse_test_helper::get_question_editing_form($cat, $questiondata);
     $this->assertTrue($form->is_validated());
     $fromform = $form->get_data();
     $returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
     $actualquestionsdata = question_load_questions(array($returnedfromsave->id));
     $actualquestiondata = end($actualquestionsdata);
     foreach ($questiondata as $property => $value) {
         if (!in_array($property, array('options'))) {
             $this->assertAttributeEquals($value, $property, $actualquestiondata);
         }
     }
     foreach ($questiondata->options as $optionname => $value) {
         if (!in_array($optionname, array('trueanswer', 'falseanswer', 'answers'))) {
             $this->assertAttributeEquals($value, $optionname, $actualquestiondata->options);
         }
     }
     $answerindexes = array();
     foreach ($questiondata->options->answers as $ansindex => $answer) {
         $actualanswer = array_shift($actualquestiondata->options->answers);
         foreach ($answer as $ansproperty => $ansvalue) {
             // This question does not use 'answerformat', will ignore it.
             if (!in_array($ansproperty, array('id', 'question', 'answerformat'))) {
                 $this->assertAttributeEquals($ansvalue, $ansproperty, $actualanswer);
             }
         }
         $answerindexes[$answer->answer] = $ansindex;
     }
     $this->assertEquals($questiondata->options->trueanswer, $answerindexes['True']);
     $this->assertEquals($questiondata->options->falseanswer, $answerindexes['False']);
 }
コード例 #3
0
 public function test_question_saving()
 {
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $questiondata = test_question_maker::get_question_data('linkerdesc');
     $formdata = test_question_maker::get_question_form_data('linkerdesc');
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category(array());
     $formdata->category = "{$cat->id},{$cat->contextid}";
     qtype_linkerdesc_edit_form::mock_submit((array) $formdata);
     $form = qtype_linkerdesc_test_helper::get_question_editing_form($cat, $questiondata);
     $this->assertTrue($form->is_validated());
     $fromform = $form->get_data();
     $returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
     $actualquestionsdata = question_load_questions(array($returnedfromsave->id));
     $actualquestiondata = end($actualquestionsdata);
     foreach ($questiondata as $property => $value) {
         if (!in_array($property, array('id', 'version', 'timemodified', 'timecreated'))) {
             $this->assertAttributeEquals($value, $property, $actualquestiondata);
         }
     }
 }
 /**
  * Load cached statistics from the database.
  *
  * @param \qubaid_condition $qubaids Which question usages to load stats for?
  */
 public function get_cached($qubaids)
 {
     global $DB;
     $timemodified = time() - self::TIME_TO_CACHE;
     $questionstatrecs = $DB->get_records_select('question_statistics', 'hashcode = ? AND timemodified > ?', array($qubaids->get_hash_code(), $timemodified));
     $questionids = array();
     foreach ($questionstatrecs as $fromdb) {
         if (is_null($fromdb->variant) && !$fromdb->slot) {
             $questionids[] = $fromdb->questionid;
         }
     }
     $this->subquestions = question_load_questions($questionids);
     foreach ($questionstatrecs as $fromdb) {
         if (is_null($fromdb->variant)) {
             if ($fromdb->slot) {
                 $this->questionstats[$fromdb->slot]->populate_from_record($fromdb);
                 // Array created in constructor and populated from question.
             } else {
                 $this->subquestionstats[$fromdb->questionid] = new calculated_for_subquestion();
                 $this->subquestionstats[$fromdb->questionid]->populate_from_record($fromdb);
                 $this->subquestionstats[$fromdb->questionid]->question = $this->subquestions[$fromdb->questionid];
             }
         }
     }
     // Add cached variant stats to data structure.
     foreach ($questionstatrecs as $fromdb) {
         if (!is_null($fromdb->variant)) {
             if ($fromdb->slot) {
                 $newcalcinstance = new calculated();
                 $this->questionstats[$fromdb->slot]->variantstats[$fromdb->variant] = $newcalcinstance;
                 $newcalcinstance->question = $this->questionstats[$fromdb->slot]->question;
             } else {
                 $newcalcinstance = new calculated_for_subquestion();
                 $this->subquestionstats[$fromdb->questionid]->variantstats[$fromdb->variant] = $newcalcinstance;
                 $newcalcinstance->question = $this->subquestions[$fromdb->questionid];
             }
             $newcalcinstance->populate_from_record($fromdb);
         }
     }
 }
コード例 #5
0
ファイル: report.php プロジェクト: nuckey/moodle
    function regrade_selected_attempts($quiz, $attemptids, $groupstudents) {
        global $DB;
        require_capability('mod/quiz:regrade', $this->context);
        if ($groupstudents) {
            list($usql, $params) = $DB->get_in_or_equal($groupstudents);
            $where = "qa.userid $usql AND ";
        } else {
            $params = array();
            $where = '';
        }
        list($asql, $aparams) = $DB->get_in_or_equal($attemptids);
        $where = "qa.id $asql AND ";
        $params = array_merge($params, $aparams);

        $where .= "qa.quiz = ? AND qa.preview = 0";
        $params[] = $quiz->id;
        if (!$attempts = $DB->get_records_sql('SELECT qa.* FROM {quiz_attempts} qa WHERE '. $where, $params)) {
            print_error('noattemptstoregrade', 'quiz_overview');
        }

        // Fetch all questions
        $questions = question_load_questions(explode(',',quiz_questions_in_quiz($quiz->questions)), 'qqi.grade AS maxgrade, qqi.id AS instance',
            '{quiz_question_instances} qqi ON qqi.quiz = ' . $quiz->id . ' AND q.id = qqi.question');
        $updateoverallgrades = array();
        foreach($attempts as $attempt) {
            foreach ($questions as $question) {
                $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
            }
            $updateoverallgrades[] = $attempt->uniqueid;
        }
        $this->check_overall_grades($quiz, array(), $updateoverallgrades);
    }
コード例 #6
0
ファイル: report.php プロジェクト: alanaipe2015/moodle
 /**
  * Load the questions in this quiz and add some properties to the objects needed in the reports.
  *
  * @param object $quiz the quiz.
  * @return array of questions for this quiz.
  */
 public function load_and_initialise_questions_for_calculations($quiz)
 {
     // Load the questions.
     $questions = quiz_report_get_significant_questions($quiz);
     $questionids = array();
     foreach ($questions as $question) {
         $questionids[] = $question->id;
     }
     $fullquestions = question_load_questions($questionids);
     foreach ($questions as $qno => $question) {
         $q = $fullquestions[$question->id];
         $q->maxmark = $question->maxmark;
         $q->slot = $qno;
         $q->number = $question->number;
         $questions[$qno] = $q;
     }
     return $questions;
 }
コード例 #7
0
ファイル: calculator.php プロジェクト: evltuma/moodle
 /**
  * Calculate the stats.
  *
  * @param \qubaid_condition $qubaids Which question usages to calculate the stats for?
  * @return all_calculated_for_qubaid_condition The calculated stats.
  */
 public function calculate($qubaids)
 {
     $this->progress->start_progress('', 6);
     list($lateststeps, $summarks) = $this->get_latest_steps($qubaids);
     if ($lateststeps) {
         $this->progress->start_progress('', count($lateststeps), 1);
         // Compute the statistics of position, and for random questions, work
         // out which questions appear in which positions.
         foreach ($lateststeps as $step) {
             $this->progress->increment_progress();
             $israndomquestion = $step->questionid != $this->stats->for_slot($step->slot)->questionid;
             $breakdownvariants = !$israndomquestion && $this->stats->for_slot($step->slot)->break_down_by_variant();
             // If this is a variant we have not seen before create a place to store stats calculations for this variant.
             if ($breakdownvariants && is_null($this->stats->for_slot($step->slot, $step->variant))) {
                 $question = $this->stats->for_slot($step->slot)->question;
                 $this->stats->initialise_for_slot($step->slot, $question, $step->variant);
                 $this->stats->for_slot($step->slot, $step->variant)->randomguessscore = $this->get_random_guess_score($question);
             }
             // Step data walker for main question.
             $this->initial_steps_walker($step, $this->stats->for_slot($step->slot), $summarks, true, $breakdownvariants);
             // If this is a random question do the calculations for sub question stats.
             if ($israndomquestion) {
                 if (is_null($this->stats->for_subq($step->questionid))) {
                     $this->stats->initialise_for_subq($step);
                 } else {
                     if ($this->stats->for_subq($step->questionid)->maxmark != $step->maxmark) {
                         $this->stats->for_subq($step->questionid)->differentweights = true;
                     }
                 }
                 // If this is a variant of this subq we have not seen before create a place to store stats calculations for it.
                 if (is_null($this->stats->for_subq($step->questionid, $step->variant))) {
                     $this->stats->initialise_for_subq($step, $step->variant);
                 }
                 $this->initial_steps_walker($step, $this->stats->for_subq($step->questionid), $summarks, false);
                 // Extra stuff we need to do in this loop for subqs to keep track of where they need to be displayed later.
                 $number = $this->stats->for_slot($step->slot)->question->number;
                 $this->stats->for_subq($step->questionid)->usedin[$number] = $number;
                 // Keep track of which random questions are actually selected from each pool of questions that random
                 // questions are pulled from.
                 $randomselectorstring = $this->stats->for_slot($step->slot)->random_selector_string();
                 if (!isset($this->randomselectors[$randomselectorstring])) {
                     $this->randomselectors[$randomselectorstring] = array();
                 }
                 $this->randomselectors[$randomselectorstring][$step->questionid] = $step->questionid;
             }
         }
         $this->progress->end_progress();
         foreach ($this->randomselectors as $key => $notused) {
             ksort($this->randomselectors[$key]);
             $this->randomselectors[$key] = implode(',', $this->randomselectors[$key]);
         }
         $this->stats->subquestions = question_load_questions($this->stats->get_all_subq_ids());
         // Compute the statistics for sub questions, if there are any.
         $this->progress->start_progress('', count($this->stats->subquestions), 1);
         foreach ($this->stats->subquestions as $qid => $subquestion) {
             $this->progress->increment_progress();
             $subquestion->maxmark = $this->stats->for_subq($qid)->maxmark;
             $this->stats->for_subq($qid)->question = $subquestion;
             $this->stats->for_subq($qid)->randomguessscore = $this->get_random_guess_score($subquestion);
             if ($variants = $this->stats->for_subq($qid)->get_variants()) {
                 foreach ($variants as $variant) {
                     $this->stats->for_subq($qid, $variant)->question = $subquestion;
                     $this->stats->for_subq($qid, $variant)->randomguessscore = $this->get_random_guess_score($subquestion);
                 }
                 $this->stats->for_subq($qid)->sort_variants();
             }
             $this->initial_question_walker($this->stats->for_subq($qid));
             if ($this->stats->for_subq($qid)->usedin) {
                 sort($this->stats->for_subq($qid)->usedin, SORT_NUMERIC);
                 $this->stats->for_subq($qid)->positions = implode(',', $this->stats->for_subq($qid)->usedin);
             } else {
                 $this->stats->for_subq($qid)->positions = '';
             }
         }
         $this->progress->end_progress();
         // Finish computing the averages, and put the sub-question data into the
         // corresponding questions.
         // This cannot be a foreach loop because we need to have both
         // $question and $nextquestion available, but apart from that it is
         // foreach ($this->questions as $qid => $question).
         $slots = $this->stats->get_all_slots();
         $this->progress->start_progress('', count($slots), 1);
         while (list(, $slot) = each($slots)) {
             $this->stats->for_slot($slot)->sort_variants();
             $this->progress->increment_progress();
             $nextslot = current($slots);
             $this->initial_question_walker($this->stats->for_slot($slot));
             // The rest of this loop is to finish working out where randomly selected question stats should be displayed.
             if ($this->stats->for_slot($slot)->question->qtype == 'random') {
                 $randomselectorstring = $this->stats->for_slot($slot)->random_selector_string();
                 if ($nextslot && $randomselectorstring == $this->stats->for_slot($nextslot)->random_selector_string()) {
                     continue;
                     // Next loop iteration.
                 }
                 if (isset($this->randomselectors[$randomselectorstring])) {
                     $this->stats->for_slot($slot)->subquestions = $this->randomselectors[$randomselectorstring];
                 }
             }
         }
         $this->progress->end_progress();
         // Go through the records one more time.
         $this->progress->start_progress('', count($lateststeps), 1);
         foreach ($lateststeps as $step) {
             $this->progress->increment_progress();
             $israndomquestion = $this->stats->for_slot($step->slot)->question->qtype == 'random';
             $this->secondary_steps_walker($step, $this->stats->for_slot($step->slot), $summarks);
             if ($israndomquestion) {
                 $this->secondary_steps_walker($step, $this->stats->for_subq($step->questionid), $summarks);
             }
         }
         $this->progress->end_progress();
         $slots = $this->stats->get_all_slots();
         $this->progress->start_progress('', count($slots), 1);
         $sumofcovariancewithoverallmark = 0;
         foreach ($this->stats->get_all_slots() as $slot) {
             $this->progress->increment_progress();
             $this->secondary_question_walker($this->stats->for_slot($slot));
             $this->sumofmarkvariance += $this->stats->for_slot($slot)->markvariance;
             if ($this->stats->for_slot($slot)->covariancewithoverallmark >= 0) {
                 $sumofcovariancewithoverallmark += sqrt($this->stats->for_slot($slot)->covariancewithoverallmark);
             }
         }
         $this->progress->end_progress();
         $subqids = $this->stats->get_all_subq_ids();
         $this->progress->start_progress('', count($subqids), 1);
         foreach ($subqids as $subqid) {
             $this->progress->increment_progress();
             $this->secondary_question_walker($this->stats->for_subq($subqid));
         }
         $this->progress->end_progress();
         foreach ($this->stats->get_all_slots() as $slot) {
             if ($sumofcovariancewithoverallmark) {
                 if ($this->stats->for_slot($slot)->negcovar) {
                     $this->stats->for_slot($slot)->effectiveweight = null;
                 } else {
                     $this->stats->for_slot($slot)->effectiveweight = 100 * sqrt($this->stats->for_slot($slot)->covariancewithoverallmark) / $sumofcovariancewithoverallmark;
                 }
             } else {
                 $this->stats->for_slot($slot)->effectiveweight = null;
             }
         }
         $this->stats->cache($qubaids);
         // All finished.
         $this->progress->end_progress();
     }
     return $this->stats;
 }
コード例 #8
0
 public function compute_statistics()
 {
     set_time_limit(0);
     $subquestionstats = array();
     // Compute the statistics of position, and for random questions, work
     // out which questions appear in which positions.
     foreach ($this->lateststeps as $step) {
         $this->initial_steps_walker($step, $this->questions[$step->slot]->_stats);
         // If this is a random question what is the real item being used?
         if ($step->questionid != $this->questions[$step->slot]->id) {
             if (!isset($subquestionstats[$step->questionid])) {
                 $subquestionstats[$step->questionid] = $this->make_blank_question_stats();
                 $subquestionstats[$step->questionid]->questionid = $step->questionid;
                 $subquestionstats[$step->questionid]->allattempts = $this->allattempts;
                 $subquestionstats[$step->questionid]->usedin = array();
                 $subquestionstats[$step->questionid]->subquestion = true;
                 $subquestionstats[$step->questionid]->differentweights = false;
                 $subquestionstats[$step->questionid]->maxmark = $step->maxmark;
             } else {
                 if ($subquestionstats[$step->questionid]->maxmark != $step->maxmark) {
                     $subquestionstats[$step->questionid]->differentweights = true;
                 }
             }
             $this->initial_steps_walker($step, $subquestionstats[$step->questionid], false);
             $number = $this->questions[$step->slot]->number;
             $subquestionstats[$step->questionid]->usedin[$number] = $number;
             $randomselectorstring = $this->questions[$step->slot]->category . '/' . $this->questions[$step->slot]->questiontext;
             if (!isset($this->randomselectors[$randomselectorstring])) {
                 $this->randomselectors[$randomselectorstring] = array();
             }
             $this->randomselectors[$randomselectorstring][$step->questionid] = $step->questionid;
         }
     }
     foreach ($this->randomselectors as $key => $notused) {
         ksort($this->randomselectors[$key]);
     }
     // Compute the statistics of question id, if we need any.
     $this->subquestions = question_load_questions(array_keys($subquestionstats));
     foreach ($this->subquestions as $qid => $subquestion) {
         $subquestion->_stats = $subquestionstats[$qid];
         $subquestion->maxmark = $subquestion->_stats->maxmark;
         $subquestion->_stats->randomguessscore = $this->get_random_guess_score($subquestion);
         $this->initial_question_walker($subquestion->_stats);
         if ($subquestionstats[$qid]->differentweights) {
             // TODO output here really sucks, but throwing is too severe.
             global $OUTPUT;
             echo $OUTPUT->notification(get_string('erroritemappearsmorethanoncewithdifferentweight', 'quiz_statistics', $this->subquestions[$qid]->name));
         }
         if ($subquestion->_stats->usedin) {
             sort($subquestion->_stats->usedin, SORT_NUMERIC);
             $subquestion->_stats->positions = implode(',', $subquestion->_stats->usedin);
         } else {
             $subquestion->_stats->positions = '';
         }
     }
     // Finish computing the averages, and put the subquestion data into the
     // corresponding questions.
     // This cannot be a foreach loop because we need to have both
     // $question and $nextquestion available, but apart from that it is
     // foreach ($this->questions as $qid => $question) {
     reset($this->questions);
     while (list($slot, $question) = each($this->questions)) {
         $nextquestion = current($this->questions);
         $question->_stats->allattempts = $this->allattempts;
         $question->_stats->positions = $question->number;
         $question->_stats->maxmark = $question->maxmark;
         $question->_stats->randomguessscore = $this->get_random_guess_score($question);
         $this->initial_question_walker($question->_stats);
         if ($question->qtype == 'random') {
             $randomselectorstring = $question->category . '/' . $question->questiontext;
             if ($nextquestion && $nextquestion->qtype == 'random') {
                 $nextrandomselectorstring = $nextquestion->category . '/' . $nextquestion->questiontext;
                 if ($randomselectorstring == $nextrandomselectorstring) {
                     continue;
                     // Next loop iteration
                 }
             }
             if (isset($this->randomselectors[$randomselectorstring])) {
                 $question->_stats->subquestions = implode(',', $this->randomselectors[$randomselectorstring]);
             }
         }
     }
     // Go through the records one more time
     foreach ($this->lateststeps as $step) {
         $this->secondary_steps_walker($step, $this->questions[$step->slot]->_stats);
         if ($this->questions[$step->slot]->qtype == 'random') {
             $this->secondary_steps_walker($step, $this->subquestions[$step->questionid]->_stats);
         }
     }
     $sumofcovariancewithoverallmark = 0;
     foreach ($this->questions as $slot => $question) {
         $this->secondary_question_walker($question->_stats);
         $this->sumofmarkvariance += $question->_stats->markvariance;
         if ($question->_stats->covariancewithoverallmark >= 0) {
             $sumofcovariancewithoverallmark += sqrt($question->_stats->covariancewithoverallmark);
             $question->_stats->negcovar = 0;
         } else {
             $question->_stats->negcovar = 1;
         }
     }
     foreach ($this->subquestions as $subquestion) {
         $this->secondary_question_walker($subquestion->_stats);
     }
     foreach ($this->questions as $question) {
         if ($sumofcovariancewithoverallmark) {
             if ($question->_stats->negcovar) {
                 $question->_stats->effectiveweight = null;
             } else {
                 $question->_stats->effectiveweight = 100 * sqrt($question->_stats->covariancewithoverallmark) / $sumofcovariancewithoverallmark;
             }
         } else {
             $question->_stats->effectiveweight = null;
         }
     }
 }
コード例 #9
0
ファイル: questiontype_test.php プロジェクト: evltuma/moodle
 public function test_question_saving_trims_answers()
 {
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $questiondata = test_question_maker::get_question_data('shortanswer');
     $formdata = test_question_maker::get_question_form_data('shortanswer');
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category(array());
     $formdata->category = "{$cat->id},{$cat->contextid}";
     $formdata->answer[0] = '   frog   ';
     qtype_shortanswer_edit_form::mock_submit((array) $formdata);
     $form = qtype_shortanswer_test_helper::get_question_editing_form($cat, $questiondata);
     $this->assertTrue($form->is_validated());
     $fromform = $form->get_data();
     $returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
     $actualquestionsdata = question_load_questions(array($returnedfromsave->id));
     $actualquestiondata = end($actualquestionsdata);
     $firstsavedanswer = reset($questiondata->options->answers);
     $this->assertEquals('frog', $firstsavedanswer->answer);
 }
コード例 #10
0
/**
 * Retrieves a template question usage for an offline group. Creates a new template if there is none.
 * While creating question usage it shuffles the group questions if shuffleanswers is created.
 *
 * @param object $offlinequiz
 * @param object $group
 * @param object $context
 * @return question_usage_by_activity
 */
function offlinequiz_get_group_template_usage($offlinequiz, $group, $context)
{
    global $CFG, $DB;
    if (!empty($group->templateusageid) && $group->templateusageid > 0) {
        $templateusage = question_engine::load_questions_usage_by_activity($group->templateusageid);
    } else {
        $questionids = offlinequiz_get_group_question_ids($offlinequiz, $group->id);
        if ($offlinequiz->shufflequestions) {
            $offlinequiz->groupid = $group->id;
            $questionids = offlinequiz_shuffle_questions($questionids);
        }
        // We have to use our own class s.t. we can use the clone function to create results.
        $templateusage = offlinequiz_make_questions_usage_by_activity('mod_offlinequiz', $context);
        $templateusage->set_preferred_behaviour('immediatefeedback');
        if (!$questionids) {
            print_error(get_string('noquestionsfound', 'offlinequiz'), 'view.php?q=' . $offlinequiz->id);
        }
        // Gets database raw data for the questions.
        $questiondata = question_load_questions($questionids);
        // Get the question instances for initial markmarks.
        $sql = "SELECT questionid, maxmark\n                  FROM {offlinequiz_group_questions}\n                 WHERE offlinequizid = :offlinequizid\n                   AND offlinegroupid = :offlinegroupid ";
        $groupquestions = $DB->get_records_sql($sql, array('offlinequizid' => $offlinequiz->id, 'offlinegroupid' => $group->id));
        foreach ($questionids as $questionid) {
            if ($questionid) {
                // Convert the raw data of multichoice questions to a real question definition object.
                if (!$offlinequiz->shuffleanswers) {
                    $questiondata[$questionid]->options->shuffleanswers = false;
                }
                $question = question_bank::make_question($questiondata[$questionid]);
                // We only add multichoice questions which are needed for grading.
                if ($question->get_type_name() == 'multichoice' || $question->get_type_name() == 'multichoiceset') {
                    $templateusage->add_question($question, $groupquestions[$question->id]->maxmark);
                }
            }
        }
        // Create attempts for all questions (fixes order of the answers if shuffleanswers is active).
        $templateusage->start_all_questions();
        // Save the template question usage to the DB.
        question_engine::save_questions_usage_by_activity($templateusage);
        // Save the templateusage-ID in the offlinequiz_groups table.
        $group->templateusageid = $templateusage->get_id();
        $DB->set_field('offlinequiz_groups', 'templateusageid', $group->templateusageid, array('id' => $group->id));
    }
    // End else.
    return $templateusage;
}
コード例 #11
0
ファイル: questiontype_test.php プロジェクト: evltuma/moodle
 public function test_question_saving_twosubq()
 {
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $questiondata = test_question_maker::get_question_data('multianswer');
     $formdata = test_question_maker::get_question_form_data('multianswer');
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category(array());
     $formdata->category = "{$cat->id},{$cat->contextid}";
     qtype_multianswer_edit_form::mock_submit((array) $formdata);
     $form = qtype_multianswer_test_helper::get_question_editing_form($cat, $questiondata);
     $this->assertTrue($form->is_validated());
     $fromform = $form->get_data();
     $returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
     $actualquestionsdata = question_load_questions(array($returnedfromsave->id));
     $actualquestiondata = end($actualquestionsdata);
     foreach ($questiondata as $property => $value) {
         if (!in_array($property, array('id', 'version', 'timemodified', 'timecreated', 'options', 'hints', 'stamp'))) {
             $this->assertAttributeEquals($value, $property, $actualquestiondata);
         }
     }
     foreach ($questiondata->options as $optionname => $value) {
         if ($optionname != 'questions') {
             $this->assertAttributeEquals($value, $optionname, $actualquestiondata->options);
         }
     }
     foreach ($questiondata->hints as $hint) {
         $actualhint = array_shift($actualquestiondata->hints);
         foreach ($hint as $property => $value) {
             if (!in_array($property, array('id', 'questionid', 'options'))) {
                 $this->assertAttributeEquals($value, $property, $actualhint);
             }
         }
     }
     $this->assertObjectHasAttribute('questions', $actualquestiondata->options);
     $subqpropstoignore = array('id', 'category', 'parent', 'contextid', 'question', 'options', 'stamp', 'version', 'timemodified', 'timecreated');
     foreach ($questiondata->options->questions as $subqno => $subq) {
         $actualsubq = $actualquestiondata->options->questions[$subqno];
         foreach ($subq as $subqproperty => $subqvalue) {
             if (!in_array($subqproperty, $subqpropstoignore)) {
                 $this->assertAttributeEquals($subqvalue, $subqproperty, $actualsubq);
             }
         }
         foreach ($subq->options as $optionname => $value) {
             if (!in_array($optionname, array('answers'))) {
                 $this->assertAttributeEquals($value, $optionname, $actualsubq->options);
             }
         }
         foreach ($subq->options->answers as $answer) {
             $actualanswer = array_shift($actualsubq->options->answers);
             foreach ($answer as $ansproperty => $ansvalue) {
                 // These questions do not use 'answerformat', will ignore it.
                 if (!in_array($ansproperty, array('id', 'question', 'answerformat'))) {
                     $this->assertAttributeEquals($ansvalue, $ansproperty, $actualanswer);
                 }
             }
         }
     }
 }
コード例 #12
0
 /**
  * add the questions to the question usage
  * This is called by the question_attmept class on construct of a new attempt
  *
  * @param \question_usage_by_activity $quba
  *
  * @return array
  */
 public function add_questions_to_quba(\question_usage_by_activity $quba)
 {
     // we need the questionids of our questions
     $questionids = array();
     foreach ($this->qbankOrderedQuestions as $qbankquestion) {
         /** @var activequiz_question $qbankquestion */
         if (!in_array($qbankquestion->getQuestion()->id, $questionids)) {
             $questionids[] = $qbankquestion->getQuestion()->id;
         }
     }
     $questions = question_load_questions($questionids);
     // loop through the ordered question bank questions and add them to the quba
     // object
     $attemptlayout = array();
     foreach ($this->qbankOrderedQuestions as $qbankquestion) {
         $questionid = $qbankquestion->getQuestion()->id;
         $q = \question_bank::make_question($questions[$questionid]);
         $attemptlayout[$qbankquestion->getId()] = $quba->add_question($q, $qbankquestion->getPoints());
     }
     // start the questions in the quba
     $quba->start_all_questions();
     /**
      * return the attempt layout which is a set of ids that are the slot ids from the question engine usage by activity instance
      * these are what are used during an actual attempt rather than the questionid themselves, since the question engine will handle
      * the translation
      */
     return $attemptlayout;
 }
コード例 #13
0
 /**
  * Load cached statistics from the database.
  *
  * @param $qubaids \qubaid_condition
  * @return array containing two arrays calculated[] and calculated_for_subquestion[].
  */
 public function get_cached($qubaids)
 {
     global $DB;
     $timemodified = time() - self::TIME_TO_CACHE;
     $questionstatrecs = $DB->get_records_select('question_statistics', 'hashcode = ? AND timemodified > ?', array($qubaids->get_hash_code(), $timemodified));
     $questionids = array();
     foreach ($questionstatrecs as $fromdb) {
         if (!$fromdb->slot) {
             $questionids[] = $fromdb->questionid;
         }
     }
     $subquestions = question_load_questions($questionids);
     foreach ($questionstatrecs as $fromdb) {
         if ($fromdb->slot) {
             $this->questionstats[$fromdb->slot]->populate_from_record($fromdb);
             // Array created in constructor and populated from question.
         } else {
             $this->subquestionstats[$fromdb->questionid] = new calculated_for_subquestion();
             $this->subquestionstats[$fromdb->questionid]->populate_from_record($fromdb);
             $this->subquestionstats[$fromdb->questionid]->question = $subquestions[$fromdb->questionid];
         }
     }
     return array($this->questionstats, $this->subquestionstats);
 }
コード例 #14
0
ファイル: report.php プロジェクト: ajv/Offline-Caching
 function quiz_questions_stats($quiz, $currentgroup, $nostudentsingroup, $useallattempts, $groupstudents, $questions)
 {
     global $DB;
     $timemodified = time() - QUIZ_REPORT_TIME_TO_CACHE_STATS;
     $params = array('quizid' => $quiz->id, 'groupid' => (int) $currentgroup, 'allattempts' => $useallattempts, 'timemodified' => $timemodified);
     if (!($quizstats = $DB->get_record_select('quiz_statistics', 'quizid = :quizid  AND groupid = :groupid AND allattempts = :allattempts AND timemodified > :timemodified', $params, '*', true))) {
         list($s, $usingattemptsstring, $quizstats, $qstats) = $this->quiz_stats($nostudentsingroup, $quiz->id, $currentgroup, $groupstudents, $questions, $useallattempts);
         if ($s) {
             $toinsert = (object) ((array) $quizstats + $params);
             $toinsert->timemodified = time();
             $quizstats->id = $DB->insert_record('quiz_statistics', $toinsert);
             foreach ($qstats->questions as $question) {
                 $question->_stats->quizstatisticsid = $quizstats->id;
                 $DB->insert_record('quiz_question_statistics', $question->_stats, false, true);
             }
             foreach ($qstats->subquestions as $subquestion) {
                 $subquestion->_stats->quizstatisticsid = $quizstats->id;
                 $DB->insert_record('quiz_question_statistics', $subquestion->_stats, false, true);
             }
             foreach ($qstats->responses as $response) {
                 $response->quizstatisticsid = $quizstats->id;
                 $DB->insert_record('quiz_question_response_stats', $response, false);
             }
         }
         if ($qstats) {
             $questions = $qstats->questions;
             $subquestions = $qstats->subquestions;
         } else {
             $questions = array();
             $subquestions = array();
         }
     } else {
         //use cached results
         if ($useallattempts) {
             $usingattemptsstring = get_string('allattempts', 'quiz_statistics');
             $s = $quizstats->allattemptscount;
         } else {
             $usingattemptsstring = get_string('firstattempts', 'quiz_statistics');
             $s = $quizstats->firstattemptscount;
         }
         $subquestions = array();
         $questionstats = $DB->get_records('quiz_question_statistics', array('quizstatisticsid' => $quizstats->id), 'subquestion ASC');
         $questionstats = quiz_report_index_by_keys($questionstats, array('subquestion', 'questionid'));
         if (1 < count($questionstats)) {
             list($mainquestionstats, $subquestionstats) = $questionstats;
             $subqstofetch = array_keys($subquestionstats);
             $subquestions = question_load_questions($subqstofetch);
             foreach (array_keys($subquestions) as $subqid) {
                 $subquestions[$subqid]->_stats = $subquestionstats[$subqid];
             }
         } elseif (count($questionstats)) {
             $mainquestionstats = $questionstats[0];
         }
         if (count($questionstats)) {
             foreach (array_keys($questions) as $qid) {
                 $questions[$qid]->_stats = $mainquestionstats[$qid];
             }
         }
     }
     return array($quizstats, $questions, $subquestions, $s, $usingattemptsstring);
 }
コード例 #15
0
ファイル: qstats.php プロジェクト: vuchannguyen/web
 function process_states()
 {
     global $DB, $OUTPUT;
     set_time_limit(0);
     $subquestionstats = array();
     foreach ($this->states as $state) {
         $this->_initial_states_walker($state, $this->questions[$state->question]->_stats);
         //if this is a random question what is the real item being used?
         if ($this->questions[$state->question]->qtype == 'random') {
             if ($realstate = question_get_real_state($state)) {
                 if (!isset($subquestionstats[$realstate->question])) {
                     $subquestionstats[$realstate->question] = $this->stats_init_object();
                     $subquestionstats[$realstate->question]->usedin = array();
                     $subquestionstats[$realstate->question]->subquestion = true;
                     $subquestionstats[$realstate->question]->differentweights = false;
                     $subquestionstats[$realstate->question]->maxgrade = $this->questions[$state->question]->maxgrade;
                 } else {
                     if ($subquestionstats[$realstate->question]->maxgrade != $this->questions[$state->question]->maxgrade) {
                         $subquestionstats[$realstate->question]->differentweights = true;
                     }
                 }
                 $this->_initial_states_walker($realstate, $subquestionstats[$realstate->question], false);
                 $number = $this->questions[$state->question]->number;
                 $subquestionstats[$realstate->question]->usedin[$number] = $number;
                 $randomselectorstring = $this->questions[$state->question]->category . '/' . $this->questions[$state->question]->questiontext;
                 if (!isset($this->randomselectors[$randomselectorstring])) {
                     $this->randomselectors[$randomselectorstring] = array();
                 }
                 $this->randomselectors[$randomselectorstring][$realstate->question] = $realstate->question;
             }
         }
     }
     foreach ($this->randomselectors as $key => $randomselector) {
         ksort($this->randomselectors[$key]);
     }
     $this->subquestions = question_load_questions(array_keys($subquestionstats));
     foreach (array_keys($this->subquestions) as $qid) {
         $this->subquestions[$qid]->_stats = $subquestionstats[$qid];
         $this->subquestions[$qid]->_stats->questionid = $qid;
         $this->subquestions[$qid]->maxgrade = $this->subquestions[$qid]->_stats->maxgrade;
         $this->_initial_question_walker($this->subquestions[$qid]->_stats);
         if ($subquestionstats[$qid]->differentweights) {
             echo $OUTPUT->notification(get_string('erroritemappearsmorethanoncewithdifferentweight', 'quiz_statistics', $this->subquestions[$qid]->name));
         }
         if ($this->subquestions[$qid]->_stats->usedin) {
             sort($this->subquestions[$qid]->_stats->usedin, SORT_NUMERIC);
             $this->subquestions[$qid]->_stats->positions = join($this->subquestions[$qid]->_stats->usedin, ',');
         } else {
             $this->subquestions[$qid]->_stats->positions = '';
         }
     }
     reset($this->questions);
     do {
         list($qid, $question) = each($this->questions);
         $nextquestion = current($this->questions);
         $this->questions[$qid]->_stats->questionid = $qid;
         $this->questions[$qid]->_stats->positions = $this->questions[$qid]->number;
         $this->questions[$qid]->_stats->maxgrade = $question->maxgrade;
         $this->_initial_question_walker($this->questions[$qid]->_stats);
         if ($question->qtype == 'random') {
             $randomselectorstring = $question->category . '/' . $question->questiontext;
             if ($nextquestion) {
                 $nextrandomselectorstring = $nextquestion->category . '/' . $nextquestion->questiontext;
                 if ($nextquestion->qtype == 'random' && $randomselectorstring == $nextrandomselectorstring) {
                     continue;
                     //next loop iteration
                 }
             }
             if (isset($this->randomselectors[$randomselectorstring])) {
                 $question->_stats->subquestions = join($this->randomselectors[$randomselectorstring], ',');
             }
         }
     } while ($nextquestion);
     //go through the records one more time
     foreach ($this->states as $state) {
         $this->_secondary_states_walker($state, $this->questions[$state->question]->_stats);
         if ($this->questions[$state->question]->qtype == 'random') {
             if ($realstate = question_get_real_state($state)) {
                 $this->_secondary_states_walker($realstate, $this->subquestions[$realstate->question]->_stats);
             }
         }
     }
     $sumofcovariancewithoverallgrade = 0;
     foreach (array_keys($this->questions) as $qid) {
         $this->_secondary_question_walker($this->questions[$qid]->_stats);
         $this->sumofgradevariance += $this->questions[$qid]->_stats->gradevariance;
         if ($this->questions[$qid]->_stats->covariancewithoverallgrade >= 0) {
             $sumofcovariancewithoverallgrade += sqrt($this->questions[$qid]->_stats->covariancewithoverallgrade);
             $this->questions[$qid]->_stats->negcovar = 0;
         } else {
             $this->questions[$qid]->_stats->negcovar = 1;
         }
     }
     foreach (array_keys($this->subquestions) as $qid) {
         $this->_secondary_question_walker($this->subquestions[$qid]->_stats);
     }
     foreach (array_keys($this->questions) as $qid) {
         if ($sumofcovariancewithoverallgrade) {
             if ($this->questions[$qid]->_stats->negcovar) {
                 $this->questions[$qid]->_stats->effectiveweight = null;
             } else {
                 $this->questions[$qid]->_stats->effectiveweight = 100 * sqrt($this->questions[$qid]->_stats->covariancewithoverallgrade) / $sumofcovariancewithoverallgrade;
             }
         } else {
             $this->questions[$qid]->_stats->effectiveweight = null;
         }
     }
 }
コード例 #16
0
ファイル: report.php プロジェクト: JP-Git/moodle
    /**
     * Load the cached statistics from the database.
     *
     * @param object $quiz the quiz settings
     * @param int $currentgroup the current group. 0 for none.
     * @param bool $nostudentsingroup true if there a no students.
     * @param bool $useallattempts use all attempts, or just first attempts.
     * @param array $groupstudents students in this group.
     * @param array $questions question definitions.
     * @return array with 4 elements:
     *     - $quizstats The statistics for overall attempt scores.
     *     - $questions The questions, with an additional _stats field.
     *     - $subquestions The subquestions, if any, with an additional _stats field.
     *     - $s Number of attempts included in the stats.
     * If there is no cached data in the database, returns an array of four nulls.
     */
    protected function try_loading_cached_stats($quiz, $currentgroup,
            $nostudentsingroup, $useallattempts, $groupstudents, $questions) {
        global $DB;

        $timemodified = time() - self::TIME_TO_CACHE_STATS;
        $quizstats = $DB->get_record_select('quiz_statistics',
                'quizid = ? AND groupid = ? AND allattempts = ? AND timemodified > ?',
                array($quiz->id, $currentgroup, $useallattempts, $timemodified));

        if (!$quizstats) {
            // No cached data found.
            return array(null, $questions, null, null);
        }

        if ($useallattempts) {
            $s = $quizstats->allattemptscount;
        } else {
            $s = $quizstats->firstattemptscount;
        }

        $subquestions = array();
        $questionstats = $DB->get_records('quiz_question_statistics',
                array('quizstatisticsid' => $quizstats->id));

        $subquestionstats = array();
        foreach ($questionstats as $stat) {
            if ($stat->slot) {
                $questions[$stat->slot]->_stats = $stat;
            } else {
                $subquestionstats[$stat->questionid] = $stat;
            }
        }

        if (!empty($subquestionstats)) {
            $subqstofetch = array_keys($subquestionstats);
            $subquestions = question_load_questions($subqstofetch);
            foreach ($subquestions as $subqid => $subq) {
                $subquestions[$subqid]->_stats = $subquestionstats[$subqid];
                $subquestions[$subqid]->maxmark = $subq->defaultmark;
            }
        }

        return array($quizstats, $questions, $subquestions, $s);
    }
コード例 #17
0
ファイル: questiontype_test.php プロジェクト: evltuma/moodle
 public function test_question_saving_foursubq()
 {
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $questiondata = test_question_maker::get_question_data('match');
     $formdata = test_question_maker::get_question_form_data('match');
     $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
     $cat = $generator->create_question_category(array());
     $formdata->category = "{$cat->id},{$cat->contextid}";
     qtype_match_edit_form::mock_submit((array) $formdata);
     $form = qtype_match_test_helper::get_question_editing_form($cat, $questiondata);
     $this->assertTrue($form->is_validated());
     $fromform = $form->get_data();
     $returnedfromsave = $this->qtype->save_question($questiondata, $fromform);
     $actualquestionsdata = question_load_questions(array($returnedfromsave->id));
     $actualquestiondata = end($actualquestionsdata);
     foreach ($questiondata as $property => $value) {
         if (!in_array($property, array('id', 'version', 'timemodified', 'timecreated', 'options', 'stamp'))) {
             $this->assertAttributeEquals($value, $property, $actualquestiondata);
         }
     }
     foreach ($questiondata->options as $optionname => $value) {
         if ($optionname != 'subquestions') {
             $this->assertAttributeEquals($value, $optionname, $actualquestiondata->options);
         }
     }
     $this->assertObjectHasAttribute('subquestions', $actualquestiondata->options);
     $subqpropstoignore = array('id');
     foreach ($questiondata->options->subquestions as $subq) {
         $actualsubq = array_shift($actualquestiondata->options->subquestions);
         foreach ($subq as $subqproperty => $subqvalue) {
             if (!in_array($subqproperty, $subqpropstoignore)) {
                 $this->assertAttributeEquals($subqvalue, $subqproperty, $actualsubq);
             }
         }
     }
 }