protected function check_typical_in_query(qubaid_condition $qubaids, $expectedsql, $expectedparams)
 {
     $sql = "SELECT qa.id, qa.maxmark\n            FROM {question_attempts} qa\n            WHERE qa.questionusageid {$qubaids->usage_id_in()}";
     // NOTE: parameter names may change thanks to $DB->inorequaluniqueindex, normal comparison is very wrong!!
     list($sql, $params) = $this->normalize_sql($sql, $qubaids->usage_id_in_params());
     list($expectedsql, $expectedparams) = $this->normalize_sql($expectedsql, $expectedparams);
     $this->assertEquals($expectedsql, $sql);
     $this->assertEquals($expectedparams, $params);
 }
 /**
  * @param \qubaid_condition $qubaids
  * @param int               $questionid the question id
  * @param string            $subpartid
  * @param string            $responseclassid
  */
 public function cache($qubaids, $questionid, $subpartid, $responseclassid)
 {
     global $DB;
     $row = new \stdClass();
     $row->hashcode = $qubaids->get_hash_code();
     $row->questionid = $questionid;
     $row->subqid = $subpartid;
     if ($responseclassid === '') {
         $row->aid = null;
     } else {
         $row->aid = $responseclassid;
     }
     $row->response = $this->response;
     $row->rcount = $this->count;
     $row->credit = $this->fraction;
     $row->timemodified = time();
     $DB->insert_record('question_response_analysis', $row, false);
 }
Exemple #3
0
 /**
  * @param array $questionids of question ids.
  * @param qubaid_condition $qubaids ids of the usages to consider.
  * @return boolean whether any of these questions are being used by any of
  *      those usages.
  */
 public function questions_in_use(array $questionids, qubaid_condition $qubaids)
 {
     list($test, $params) = $this->db->get_in_or_equal($questionids);
     return $this->db->record_exists_select('question_attempts', 'questionid ' . $test . ' AND questionusageid ' . $qubaids->usage_id_in(), $params + $qubaids->usage_id_in_params());
 }
 /**
  * Find time of non-expired statistics in the database.
  *
  * @param \qubaid_condition $qubaids Which question usages to look for stats for?
  * @return int|bool Time of cached record that matches this qubaid_condition or false if non found.
  */
 public function get_last_calculated_time($qubaids)
 {
     global $DB;
     $timemodified = time() - self::TIME_TO_CACHE;
     return $DB->get_field_select('question_statistics', 'timemodified', 'hashcode = ? AND timemodified > ?', array($qubaids->get_hash_code(), $timemodified), IGNORE_MULTIPLE);
 }
Exemple #5
0
 /**
  * Get the ids of all the questions in a list of categories, with the number
  * of times they have already been used in a given set of usages.
  *
  * The result array is returned in order of increasing (count previous uses).
  *
  * @param array $categoryids an array question_category ids.
  * @param qubaid_condition $qubaids which question_usages to count previous uses from.
  * @param string $extraconditions extra conditions to AND with the rest of
  *      the where clause. Must use named parameters.
  * @param array $extraparams any parameters used by $extraconditions.
  * @return array questionid => count of number of previous uses.
  */
 public function get_questions_from_categories_with_usage_counts($categoryids, qubaid_condition $qubaids, $extraconditions = '', $extraparams = array())
 {
     global $DB;
     list($qcsql, $qcparams) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'qc');
     if ($extraconditions) {
         $extraconditions = ' AND (' . $extraconditions . ')';
     }
     return $DB->get_records_sql_menu("\n                    SELECT q.id, (SELECT COUNT(1)\n                                    FROM " . $qubaids->from_question_attempts('qa') . "\n                                   WHERE qa.questionid = q.id AND " . $qubaids->where() . "\n                                 ) AS previous_attempts\n\n                      FROM {question} q\n\n                     WHERE q.category {$qcsql} {$extraconditions}\n\n                  ORDER BY previous_attempts\n                ", $qubaids->from_where_params() + $qcparams + $extraparams);
 }
Exemple #6
0
 /**
  * Find time of non-expired analysis in the database.
  *
  * @param \qubaid_condition $qubaids    check for the analysis of which question usages?
  * @param string            $whichtries check for the analysis of which tries?
  * @return integer|boolean Time of cached record that matches this qubaid_condition or false if none found.
  */
 public function get_last_analysed_time($qubaids, $whichtries)
 {
     global $DB;
     $timemodified = time() - self::TIME_TO_CACHE;
     return $DB->get_field_select('question_response_analysis', 'timemodified', 'hashcode = ? AND whichtries = ? AND questionid = ? AND timemodified > ?', array($qubaids->get_hash_code(), $whichtries, $this->questiondata->id, $timemodified), IGNORE_MULTIPLE);
 }
 /**
  * Get all the STACK questions used in all the attempts at a quiz. (Note that
  * Moodle random questions may be being used.)
  * @param qubaid_condition $qubaids the attempts of interest.
  * @return array of rows from the question table.
  */
 protected function get_stack_questions_used_in_attempt(qubaid_condition $qubaids)
 {
     global $DB;
     return $DB->get_records_sql("\n                SELECT q.*\n                  FROM {question} q\n                  JOIN (\n                        SELECT qa.questionid, MIN(qa.slot) AS firstslot\n                          FROM {$qubaids->from_question_attempts('qa')}\n                         WHERE {$qubaids->where()}\n                      GROUP BY qa.questionid\n                       ) usedquestionids ON q.id = usedquestionids.questionid\n                 WHERE q.qtype = 'stack'\n              ORDER BY usedquestionids.firstslot\n                ", $qubaids->from_where_params());
 }
Exemple #8
0
 /**
  * Get the number of times each variant has been used for each question in a list
  * in a set of usages.
  * @param array $questionids of question ids.
  * @param qubaid_condition $qubaids ids of the usages to consider.
  * @return array questionid => variant number => num uses.
  */
 public function load_used_variants(array $questionids, qubaid_condition $qubaids)
 {
     list($test, $params) = $this->db->get_in_or_equal($questionids, SQL_PARAMS_NAMED, 'qid');
     $recordset = $this->db->get_recordset_sql("\n                SELECT qa.questionid, qa.variant, COUNT(1) AS usescount\n                  FROM " . $qubaids->from_question_attempts('qa') . "\n                 WHERE qa.questionid {$test}\n                   AND " . $qubaids->where() . "\n              GROUP BY qa.questionid, qa.variant\n              ORDER BY COUNT(1) ASC\n                ", $params + $qubaids->from_where_params());
     $usedvariants = array_combine($questionids, array_fill(0, count($questionids), array()));
     foreach ($recordset as $row) {
         $usedvariants[$row->questionid][$row->variant] = $row->usescount;
     }
     $recordset->close();
     return $usedvariants;
 }
Exemple #9
0
 /**
  * Cache calculated stats stored in this object in 'question_statistics' table.
  *
  * @param \qubaid_condition $qubaids
  */
 public function cache($qubaids)
 {
     global $DB;
     $toinsert = new \stdClass();
     $toinsert->hashcode = $qubaids->get_hash_code();
     $toinsert->timemodified = time();
     foreach ($this->fieldsindb as $field) {
         $toinsert->{$field} = $this->{$field};
     }
     $DB->insert_record('question_statistics', $toinsert, false);
 }
Exemple #10
0
 /**
  * Output the HTML needed to show the statistics graph.
  *
  * @param int|object $quizorid The quiz, or its ID.
  * @param qubaid_condition $qubaids the question usages whose responses to analyse.
  * @param string $whichattempts Which attempts constant.
  */
 protected function output_statistics_graph($quizorid, $qubaids)
 {
     global $DB, $PAGE;
     $quiz = $quizorid;
     if (!is_object($quiz)) {
         $quiz = $DB->get_record('quiz', array('id' => $quizorid), '*', MUST_EXIST);
     }
     // Load the rest of the required data.
     $questions = quiz_report_get_significant_questions($quiz);
     // Only load main question not sub questions.
     $questionstatistics = $DB->get_records_select('question_statistics', 'hashcode = ? AND slot IS NOT NULL', [$qubaids->get_hash_code()]);
     // Configure what to display.
     $fieldstoplot = ['facility' => get_string('facility', 'quiz_statistics'), 'discriminativeefficiency' => get_string('discriminative_efficiency', 'quiz_statistics')];
     $fieldstoplotfactor = ['facility' => 100, 'discriminativeefficiency' => 1];
     // Prepare the arrays to hold the data.
     $xdata = [];
     foreach (array_keys($fieldstoplot) as $fieldtoplot) {
         $ydata[$fieldtoplot] = [];
     }
     // Fill in the data for each question.
     foreach ($questionstatistics as $questionstatistic) {
         $number = $questions[$questionstatistic->slot]->number;
         $xdata[$number] = $number;
         foreach ($fieldstoplot as $fieldtoplot => $notused) {
             $value = $questionstatistic->{$fieldtoplot};
             if (is_null($value)) {
                 $value = 0;
             }
             $value *= $fieldstoplotfactor[$fieldtoplot];
             $ydata[$fieldtoplot][$number] = number_format($value, 2);
         }
     }
     // Create the chart.
     sort($xdata);
     $chart = new \core\chart_bar();
     $chart->get_xaxis(0, true)->set_label(get_string('position', 'quiz_statistics'));
     $chart->set_labels(array_values($xdata));
     foreach ($fieldstoplot as $fieldtoplot => $notused) {
         ksort($ydata[$fieldtoplot]);
         $series = new \core\chart_series($fieldstoplot[$fieldtoplot], array_values($ydata[$fieldtoplot]));
         $chart->add_series($series);
     }
     // Find max.
     $max = 0;
     foreach ($fieldstoplot as $fieldtoplot => $notused) {
         $max = max($max, max($ydata[$fieldtoplot]));
     }
     // Set Y properties.
     $yaxis = $chart->get_yaxis(0, true);
     $yaxis->set_stepsize(10);
     $yaxis->set_label('%');
     $output = $PAGE->get_renderer('mod_quiz');
     $graphname = get_string('statisticsreportgraph', 'quiz_statistics');
     echo $output->chart($chart, $graphname);
 }
 /**
  * Cache analysis for class.
  *
  * @param \qubaid_condition $qubaids    which question usages have been analysed.
  * @param string            $whichtries which tries have been analysed?
  * @param int               $questionid which question.
  * @param int               $variantno  which variant.
  * @param string            $subpartid which sub part is this actual response in?
  * @param string            $responseclassid which response class is this actual response in?
  */
 public function cache($qubaids, $whichtries, $questionid, $variantno, $subpartid, $responseclassid)
 {
     global $DB;
     $row = new \stdClass();
     $row->hashcode = $qubaids->get_hash_code();
     $row->whichtries = $whichtries;
     $row->questionid = $questionid;
     $row->variant = $variantno;
     $row->subqid = $subpartid;
     if ($responseclassid === '') {
         $row->aid = null;
     } else {
         $row->aid = $responseclassid;
     }
     $row->response = $this->response;
     $row->credit = $this->fraction;
     $row->timemodified = time();
     $analysisid = $DB->insert_record('question_response_analysis', $row);
     if ($whichtries === \question_attempt::ALL_TRIES) {
         foreach ($this->trycount as $try => $count) {
             $countrow = new \stdClass();
             $countrow->try = $try;
             $countrow->rcount = $count;
             $countrow->analysisid = $analysisid;
             $DB->insert_record('question_response_count', $countrow, false);
         }
     } else {
         $countrow = new \stdClass();
         $countrow->try = 0;
         $countrow->rcount = $this->totalcount;
         $countrow->analysisid = $analysisid;
         $DB->insert_record('question_response_count', $countrow, false);
     }
 }
Exemple #12
0
 /**
  * Retrieve the computed response analysis from the question_response_analysis table.
  *
  * @param \qubaid_condition $qubaids which attempts to get cached response analysis for.
  * @return analysis_for_question|boolean analysis or false if no cached analysis found.
  */
 public function load_cached($qubaids)
 {
     global $DB;
     $timemodified = time() - self::TIME_TO_CACHE;
     $rows = $DB->get_records_select('question_response_analysis', 'hashcode = ? AND questionid = ? AND timemodified > ?', array($qubaids->get_hash_code(), $this->questiondata->id, $timemodified));
     if (!$rows) {
         return false;
     }
     foreach ($rows as $row) {
         $class = $this->analysis->get_subpart($row->subqid)->get_response_class($row->aid);
         $class->add_response_and_count($row->response, $row->credit, $row->rcount);
     }
     return $this->analysis;
 }
 protected function check_typical_in_query(qubaid_condition $qubaids, $expectedsql, $expectedparams)
 {
     $sql = "SELECT qa.id, qa.maxmark\n            FROM {question_attempts} qa\n            WHERE qa.questionusageid {$qubaids->usage_id_in()}";
     $this->assertEqual($expectedsql, $sql);
     $this->assertEqual($expectedparams, $qubaids->usage_id_in_params());
 }