Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  /**
  17   * @package   moodlecore
  18   * @subpackage backup-imscc
  19   * @copyright 2009 Mauro Rondinelli (mauro.rondinelli [AT] uvcms.com)
  20   * @copyright 2011 Darko Miletic (dmiletic@moodlerooms.com)
  21   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
  25  
  26  class cc_quiz extends entities {
  27  
  28      public function generate_node_question_categories () {
  29  
  30          $instances = $this->generate_instances();
  31  
  32          $node_course_question_categories = $this->create_node_course_question_categories($instances);
  33          $node_course_question_categories = empty($node_course_question_categories) ? '' : $node_course_question_categories;
  34  
  35          return $node_course_question_categories;
  36  
  37      }
  38  
  39      public function generate_node_course_modules_mod () {
  40  
  41          cc2moodle::log_action('Creating Quiz mods');
  42  
  43          $node_course_modules_mod = '';
  44          $instances = $this->generate_instances();
  45  
  46          if (!empty($instances)) {
  47              foreach ($instances as $instance) {
  48                  if ($instance['is_question_bank'] == 0) {
  49                      $node_course_modules_mod .= $this->create_node_course_modules_mod($instance);
  50                  }
  51              }
  52          }
  53  
  54          return $node_course_modules_mod;
  55  
  56      }
  57  
  58      private function create_node_course_modules_mod_quiz_feedback () {
  59  
  60          $sheet_question_mod_feedback = cc2moodle::loadsheet(SHEET_COURSE_SECTIONS_SECTION_MODS_MOD_QUIZ_FEEDBACK);
  61  
  62          return $sheet_question_mod_feedback;
  63      }
  64  
  65      private function generate_instances () {
  66  
  67          $last_instance_id = 0;
  68          $last_question_id = 0;
  69          $last_answer_id = 0;
  70  
  71          $instances = array();
  72  
  73          $types = array(MOODLE_TYPE_QUIZ, MOODLE_TYPE_QUESTION_BANK);
  74  
  75          foreach ($types as $type) {
  76  
  77              if (!empty(cc2moodle::$instances['instances'][$type])) {
  78  
  79                  foreach (cc2moodle::$instances['instances'][$type] as $instance) {
  80  
  81                      if ($type == MOODLE_TYPE_QUIZ) {
  82                          $is_question_bank = 0;
  83                      } else {
  84                          $is_question_bank = 1;
  85                      }
  86  
  87                      $assessment_file = $this->get_external_xml($instance['resource_indentifier']);
  88  
  89                      if (!empty($assessment_file)) {
  90  
  91                          $assessment = $this->load_xml_resource(
  92                              cc2moodle::$path_to_manifest_folder . DIRECTORY_SEPARATOR . $assessment_file
  93                          );
  94  
  95                          if (!empty($assessment)) {
  96  
  97                              $replace_values = array('unlimited' => 0);
  98  
  99                              $questions = $this->get_questions(
 100                                  $assessment, $last_question_id, $last_answer_id, dirname($assessment_file), $is_question_bank
 101                              );
 102                              $question_count = count($questions);
 103  
 104                              if (!empty($question_count)) {
 105  
 106                                  $last_instance_id++;
 107  
 108                                  $instances[$instance['resource_indentifier']]['questions'] = $questions;
 109                                  $instances[$instance['resource_indentifier']]['id'] = $last_instance_id;
 110                                  $instances[$instance['resource_indentifier']]['title'] = $instance['title'];
 111                                  $instances[$instance['resource_indentifier']]['is_question_bank'] = $is_question_bank;
 112                                  $instances[$instance['resource_indentifier']]['options']['timelimit'] =
 113                                      $this->get_global_config($assessment, 'qmd_timelimit', 0);
 114                                  $instances[$instance['resource_indentifier']]['options']['max_attempts'] =
 115                                      $this->get_global_config($assessment, 'cc_maxattempts', 0, $replace_values);
 116                              }
 117                          }
 118                      }
 119                  }
 120              }
 121          }
 122  
 123          return $instances;
 124      }
 125  
 126  
 127      private function create_node_course_modules_mod ($instance) {
 128  
 129          $sheet_question_mod = cc2moodle::loadsheet(SHEET_COURSE_SECTIONS_SECTION_MODS_MOD_QUIZ);
 130  
 131          $node_course_modules_quiz_question_instances = $this->create_node_course_modules_mod_quiz_question_instances($instance);
 132          $node_course_modules_quiz_feedback = $this->create_node_course_modules_mod_quiz_feedback($instance);
 133  
 134          $questions_strings = $this->get_questions_string($instance);
 135          $quiz_stamp = 'localhost+' . time() . '+' . $this->generate_random_string(6);
 136  
 137          $find_tags = array('[#mod_id#]',
 138                             '[#mod_name#]',
 139                             '[#mod_intro#]',
 140                             '[#mod_stamp#]',
 141                             '[#question_string#]',
 142                             '[#date_now#]',
 143                             '[#mod_max_attempts#]',
 144                             '[#mod_timelimit#]',
 145                             '[#node_question_instance#]',
 146                             '[#node_questions_feedback#]');
 147  
 148          $replace_values = array($instance['id'],
 149                                  self::safexml($instance['title']),
 150                                  self::safexml($instance['title']),
 151                                  self::safexml($quiz_stamp),
 152                                  self::safexml($questions_strings),
 153                                  time(),
 154                                  $instance['options']['max_attempts'],
 155                                  $instance['options']['timelimit'],
 156                                  $node_course_modules_quiz_question_instances,
 157                                  $node_course_modules_quiz_feedback); // This one has tags.
 158  
 159          $node_question_mod = str_replace($find_tags, $replace_values, $sheet_question_mod);
 160  
 161          return $node_question_mod;
 162      }
 163  
 164      private function get_global_config ($assessment, $option, $default_value, $replace_values = '') {
 165  
 166          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 167          $metadata = $xpath->query('/xmlns:questestinterop/xmlns:assessment/xmlns:qtimetadata/xmlns:qtimetadatafield');
 168  
 169          foreach ($metadata as $field) {
 170              $field_label = $xpath->query('xmlns:fieldlabel', $field);
 171              $field_label = !empty($field_label->item(0)->nodeValue) ? $field_label->item(0)->nodeValue : '';
 172  
 173              if (strtolower($field_label) == strtolower($option)) {
 174                  $field_entry = $xpath->query('xmlns:fieldentry', $field);
 175                  $response = !empty($field_entry->item(0)->nodeValue) ? $field_entry->item(0)->nodeValue : '';
 176              }
 177          }
 178  
 179          $response = !empty($response) ? trim($response) : '';
 180  
 181          if (!empty($replace_values)) {
 182              foreach ($replace_values as $key => $value) {
 183                  $response = ($key == $response) ? $value : $response;
 184              }
 185          }
 186  
 187          $response = empty($response) ? $default_value : $response;
 188  
 189          return $response;
 190      }
 191  
 192      private function create_node_course_modules_mod_quiz_question_instances ($instance) {
 193  
 194          $node_course_module_mod_quiz_questions_instances = '';
 195          $sheet_question_mod_instance = cc2moodle::loadsheet(SHEET_COURSE_SECTIONS_SECTION_MODS_MOD_QUIZ_QUESTION_INSTANCE);
 196  
 197          $find_tags = array('[#question_id#]' , '[#instance_id#]');
 198  
 199          if (!empty($instance['questions'])) {
 200  
 201              foreach ($instance['questions'] as $question) {
 202                  $replace_values = array($question['id'] , $question['id']);
 203                  $node_course_module_mod_quiz_questions_instances .= str_replace(
 204                      $find_tags, $replace_values, $sheet_question_mod_instance
 205                  );
 206              }
 207  
 208              $node_course_module_mod_quiz_questions_instances = str_replace(
 209                  $find_tags, $replace_values, $node_course_module_mod_quiz_questions_instances
 210              );
 211          }
 212  
 213          return $node_course_module_mod_quiz_questions_instances;
 214      }
 215  
 216      private function get_questions_string ($instance) {
 217  
 218          $questions_string = '';
 219  
 220          if (!empty($instance['questions'])) {
 221              foreach ($instance['questions'] as $question) {
 222                  $questions_string .= $question['id'] . ',';
 223              }
 224          }
 225  
 226          $questions_string = !empty($questions_string) ? substr($questions_string, 0, strlen($questions_string) - 1) : '';
 227  
 228          return $questions_string;
 229      }
 230  
 231      private function create_node_course_question_categories($instances) {
 232  
 233          $sheet_question_categories = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES);
 234  
 235          if (!empty($instances)) {
 236  
 237              $node_course_question_categories_question_category = '';
 238  
 239              foreach ($instances as $instance) {
 240                  $node_course_question_categories_question_category .=
 241                      $this->create_node_course_question_categories_question_category($instance);
 242              }
 243  
 244              $find_tags = array('[#node_course_question_categories_question_category#]');
 245              $replace_values = array($node_course_question_categories_question_category);
 246  
 247              $node_course_question_categories = str_replace($find_tags, $replace_values, $sheet_question_categories);
 248          }
 249  
 250          $node_course_question_categories = empty($node_course_question_categories) ? '' : $node_course_question_categories;
 251  
 252          return $node_course_question_categories;
 253      }
 254  
 255      private function create_node_course_question_categories_question_category ($instance) {
 256  
 257          $sheet_question_categories_quetion_category = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY);
 258  
 259          $find_tags = array('[#quiz_id#]',
 260                             '[#quiz_name#]',
 261                             '[#quiz_stamp#]',
 262                             '[#node_course_question_categories_question_category_questions#]');
 263  
 264          $node_course_question_categories_questions =
 265              $this->create_node_course_question_categories_question_category_question($instance);
 266          $node_course_question_categories_questions =
 267              empty($node_course_question_categories_questions) ? '' : $node_course_question_categories_questions;
 268  
 269          $quiz_stamp = 'localhost+' . time() . '+' . $this->generate_random_string(6);
 270  
 271          $replace_values = array($instance['id'],
 272                                  self::safexml($instance['title']),
 273                                  $quiz_stamp,
 274                                  $node_course_question_categories_questions);
 275  
 276          $node_question_categories = str_replace($find_tags, $replace_values, $sheet_question_categories_quetion_category);
 277  
 278          return $node_question_categories;
 279      }
 280  
 281      private function create_node_course_question_categories_question_category_question ($instance) {
 282  
 283          global $USER;
 284  
 285          $node_course_question_categories_question = '';
 286  
 287          $find_tags = array('[#question_id#]',
 288                             '[#question_title#]',
 289                             '[#question_text#]',
 290                             '[#question_type#]',
 291                             '[#question_general_feedback#]',
 292                             '[#question_defaultgrade#]',
 293                             '[#date_now#]',
 294                             '[#question_type_nodes#]',
 295                             '[#question_stamp#]',
 296                             '[#question_version#]',
 297                             '[#logged_user#]');
 298  
 299          $sheet_question_categories_question = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY_QUESTION);
 300  
 301          $questions = $instance['questions'];
 302  
 303          if (!empty($questions)) {
 304  
 305              foreach ($questions as $question) {
 306  
 307                  $quiz_stamp = 'localhost+' . time() . '+' . $this->generate_random_string(6);
 308                  $quiz_version = 'localhost+' . time() . '+' . $this->generate_random_string(6);
 309  
 310                  $question_moodle_type = $question['moodle_type'];
 311                  $question_cc_type = $question['cc_type'];
 312  
 313                  $question_type_node = '';
 314  
 315                  $question_type_node = ($question_moodle_type == MOODLE_QUIZ_MULTIPLE_CHOICE) ? $this->create_node_course_question_categories_question_category_question_multiple_choice($question) : $question_type_node;
 316                  $question_type_node = ($question_moodle_type == MOODLE_QUIZ_TRUE_FALSE) ? $this->create_node_course_question_categories_question_category_question_true_false($question) : $question_type_node;
 317                  $question_type_node = ($question_moodle_type == MOODLE_QUIZ_ESSAY) ? $this->create_node_course_question_categories_question_category_question_eesay($question) : $question_type_node;
 318                  $question_type_node = ($question_moodle_type == MOODLE_QUIZ_SHORTANSWER) ? $this->create_node_course_question_categories_question_category_question_shortanswer($question) : $question_type_node;
 319  
 320                  $replace_values = array($question['id'],
 321                                          self::safexml($this->truncate_text($question['title'], 255, true)),
 322                                          self::safexml($question['title']),
 323                                          $question_moodle_type,
 324                                          self::safexml($question['feedback']),
 325                                          $question['defaultgrade'], //default grade
 326                                          time(),
 327                                          $question_type_node,
 328                                          $quiz_stamp,
 329                                          $quiz_version,
 330                                          $USER->id);
 331  
 332                  $node_course_question_categories_question .= str_replace($find_tags, $replace_values, $sheet_question_categories_question);
 333              }
 334          }
 335  
 336          $node_course_question_categories_question = empty($node_course_question_categories_question) ? '' : $node_course_question_categories_question;
 337  
 338          return $node_course_question_categories_question;
 339      }
 340  
 341      private function get_questions ($assessment, &$last_question_id, &$last_answer_id, $root_path, $is_question_bank) {
 342  
 343          $questions = array();
 344  
 345          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 346  
 347          if (!$is_question_bank) {
 348              $questions_items = $xpath->query('/xmlns:questestinterop/xmlns:assessment/xmlns:section/xmlns:item');
 349          } else {
 350              $questions_items = $xpath->query('/xmlns:questestinterop/xmlns:objectbank/xmlns:item');
 351          }
 352  
 353          foreach ($questions_items as $question_item) {
 354  
 355              $count_questions = $xpath->evaluate('count(xmlns:presentation/xmlns:flow/xmlns:material/xmlns:mattext)', $question_item);
 356  
 357              if ($count_questions == 0) {
 358                  $question_title = $xpath->query('xmlns:presentation/xmlns:material/xmlns:mattext', $question_item);
 359              } else {
 360                  $question_title = $xpath->query('xmlns:presentation/xmlns:flow/xmlns:material/xmlns:mattext', $question_item);
 361              }
 362  
 363              $question_title = !empty($question_title->item(0)->nodeValue) ? $question_title->item(0)->nodeValue : '';
 364  
 365              $question_identifier = $xpath->query('@ident', $question_item);
 366              $question_identifier = !empty($question_identifier->item(0)->nodeValue) ? $question_identifier->item(0)->nodeValue : '';
 367  
 368              if (!empty($question_identifier)) {
 369  
 370                  $question_type = $this->get_question_type($question_identifier, $assessment);
 371  
 372                  if (!empty($question_type['moodle'])) {
 373  
 374                      $last_question_id++;
 375  
 376                      $questions[$question_identifier]['id'] = $last_question_id;
 377  
 378                      $question_title = $this->update_sources($question_title, $root_path);
 379                      $question_title = !empty($question_title) ? str_replace("%24", "\$", $this->include_titles($question_title)) : '';
 380  
 381                      $questions[$question_identifier]['title'] = $question_title;
 382                      $questions[$question_identifier]['identifier'] = $question_identifier;
 383                      $questions[$question_identifier]['moodle_type'] = $question_type['moodle'];
 384                      $questions[$question_identifier]['cc_type'] = $question_type['cc'];
 385                      $questions[$question_identifier]['feedback'] = $this->get_general_feedback($assessment, $question_identifier);
 386                      $questions[$question_identifier]['defaultgrade'] = $this->get_defaultgrade($assessment, $question_identifier);
 387                      $questions[$question_identifier]['answers'] = $this->get_answers($question_identifier, $assessment, $last_answer_id);
 388  
 389                  }
 390              }
 391          }
 392  
 393          $questions = !empty($questions) ? $questions : '';
 394  
 395          return $questions;
 396      }
 397  
 398      private function str_replace_once ($search, $replace, $subject) {
 399  
 400          $first_char = strpos($subject, $search);
 401  
 402          if ($first_char !== false) {
 403  
 404              $before_str = substr($subject, 0, $first_char);
 405              $after_str = substr($subject, $first_char + strlen($search));
 406  
 407              return $before_str . $replace . $after_str;
 408  
 409          } else {
 410              return $subject;
 411          }
 412      }
 413  
 414      private function get_defaultgrade($assessment, $question_identifier) {
 415          $result = 1;
 416          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 417          $query = '//xmlns:item[@ident="' . $question_identifier . '"]';
 418          $query .= '//xmlns:qtimetadatafield[xmlns:fieldlabel="cc_weighting"]/xmlns:fieldentry';
 419          $defgrade = $xpath->query($query);
 420          if (!empty($defgrade) && ($defgrade->length > 0)) {
 421              $resp = (int)$defgrade->item(0)->nodeValue;
 422              if ($resp >= 0 && $resp <= 99) {
 423                  $result = $resp;
 424              }
 425          }
 426          return $result;
 427      }
 428  
 429      private function get_general_feedback ($assessment, $question_identifier) {
 430  
 431          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 432  
 433          $respconditions = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:resprocessing/xmlns:respcondition');
 434  
 435          if (!empty($respconditions)) {
 436  
 437              foreach ($respconditions as $respcondition) {
 438  
 439                  $continue = $respcondition->getAttributeNode('continue');
 440                  $continue = !empty($continue->nodeValue) ? strtolower($continue->nodeValue) : '';
 441  
 442                  if ($continue == 'yes') {
 443  
 444                      $display_feedback = $xpath->query('xmlns:displayfeedback', $respcondition);
 445  
 446                      if (!empty($display_feedback)) {
 447                          foreach ($display_feedback as $feedback) {
 448  
 449                              $feedback_identifier = $feedback->getAttributeNode('linkrefid');
 450                              $feedback_identifier = !empty($feedback_identifier->nodeValue) ? $feedback_identifier->nodeValue : '';
 451  
 452                              if (!empty($feedback_identifier)) {
 453                                  $feedbacks_identifiers[] = $feedback_identifier;
 454                              }
 455                          }
 456                      }
 457                  }
 458              }
 459          }
 460  
 461          $feedback = '';
 462          $feedbacks_identifiers = empty($feedbacks_identifiers) ? '' : $feedbacks_identifiers;
 463  
 464          if (!empty($feedbacks_identifiers)) {
 465              foreach ($feedbacks_identifiers as $feedback_identifier) {
 466                  $feedbacks = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:itemfeedback[@ident="' . $feedback_identifier . '"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
 467                  $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue . ' ' : '';
 468              }
 469          }
 470  
 471          return $feedback;
 472      }
 473  
 474      private function get_feedback ($assessment, $identifier, $item_identifier, $question_type) {
 475  
 476          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 477  
 478          $resource_processing = $xpath->query('//xmlns:item[@ident="' . $item_identifier . '"]/xmlns:resprocessing/xmlns:respcondition');
 479  
 480          if (!empty($resource_processing)) {
 481  
 482              foreach ($resource_processing as $response) {
 483  
 484                  $varequal = $xpath->query('xmlns:conditionvar/xmlns:varequal', $response);
 485                  $varequal = !empty($varequal->item(0)->nodeValue) ? $varequal->item(0)->nodeValue : '';
 486  
 487                  if (strtolower($varequal) == strtolower($identifier) || ($question_type == CC_QUIZ_ESSAY)) {
 488  
 489                      $display_feedback = $xpath->query('xmlns:displayfeedback', $response);
 490  
 491                      if (!empty($display_feedback)) {
 492                          foreach ($display_feedback as $feedback) {
 493  
 494                              $feedback_identifier = $feedback->getAttributeNode('linkrefid');
 495                              $feedback_identifier = !empty($feedback_identifier->nodeValue) ? $feedback_identifier->nodeValue : '';
 496  
 497                              if (!empty($feedback_identifier)) {
 498                                  $feedbacks_identifiers[] = $feedback_identifier;
 499                              }
 500                          }
 501                      }
 502                  }
 503              }
 504          }
 505  
 506          $feedback = '';
 507          $feedbacks_identifiers = empty($feedbacks_identifiers) ? '' : $feedbacks_identifiers;
 508  
 509          if (!empty($feedbacks_identifiers)) {
 510              foreach ($feedbacks_identifiers as $feedback_identifier) {
 511                  $feedbacks = $xpath->query('//xmlns:item[@ident="' . $item_identifier . '"]/xmlns:itemfeedback[@ident="' . $feedback_identifier . '"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
 512                  $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue . ' ' : '';
 513              }
 514          }
 515  
 516          return $feedback;
 517      }
 518  
 519      private function get_answers_fib ($question_identifier, $identifier, $assessment, &$last_answer_id) {
 520  
 521          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 522  
 523          $answers_fib = array();
 524  
 525          $response_items = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:resprocessing/xmlns:respcondition');
 526  
 527          foreach ($response_items as $response_item) {
 528  
 529              $setvar = $xpath->query('xmlns:setvar', $response_item);
 530              $setvar = is_object($setvar->item(0)) ? $setvar->item(0)->nodeValue : '';
 531  
 532              if ($setvar != '') {
 533  
 534                  $last_answer_id++;
 535  
 536                  $answer_title = $xpath->query('xmlns:conditionvar/xmlns:varequal[@respident="' . $identifier . '"]', $response_item);
 537                  $answer_title = !empty($answer_title->item(0)->nodeValue) ? $answer_title->item(0)->nodeValue : '';
 538  
 539              $case = $xpath->query('xmlns:conditionvar/xmlns:varequal/@case', $response_item);
 540              $case = is_object($case->item(0)) ? $case->item(0)->nodeValue : 'no'
 541                                      ;
 542              $case = strtolower($case) == 'yes' ? 1 :
 543                              0;
 544  
 545                  $display_feedback = $xpath->query('xmlns:displayfeedback', $response_item);
 546  
 547                  unset($feedbacks_identifiers);
 548  
 549                  if (!empty($display_feedback)) {
 550  
 551                      foreach ($display_feedback as $feedback) {
 552  
 553                          $feedback_identifier = $feedback->getAttributeNode('linkrefid');
 554                          $feedback_identifier = !empty($feedback_identifier->nodeValue) ? $feedback_identifier->nodeValue : '';
 555  
 556                          if (!empty($feedback_identifier)) {
 557                              $feedbacks_identifiers[] = $feedback_identifier;
 558                          }
 559                      }
 560                  }
 561  
 562                  $feedback = '';
 563                  $feedbacks_identifiers = empty($feedbacks_identifiers) ? '' : $feedbacks_identifiers;
 564  
 565                  if (!empty($feedbacks_identifiers)) {
 566                      foreach ($feedbacks_identifiers as $feedback_identifier) {
 567                          $feedbacks = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:itemfeedback[@ident="' . $feedback_identifier . '"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
 568                          $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue . ' ' : '';
 569                      }
 570                  }
 571  
 572                  $answers_fib[] = array('id' => $last_answer_id,
 573                                         'title' => $answer_title,
 574                                         'score' => $setvar,
 575                                         'feedback' => $feedback,
 576                                         'case' => $case);
 577              }
 578          }
 579  
 580          $answers_fib = empty($answers_fib) ? '' : $answers_fib;
 581  
 582          return $answers_fib;
 583      }
 584  
 585      private function get_answers_pattern_match ($question_identifier, $identifier, $assessment, &$last_answer_id) {
 586  
 587          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 588  
 589          $answers_fib = array();
 590  
 591          $response_items = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:resprocessing/xmlns:respcondition');
 592  
 593          foreach ($response_items as $response_item) {
 594  
 595              $setvar = $xpath->query('xmlns:setvar', $response_item);
 596              $setvar = is_object($setvar->item(0)) ? $setvar->item(0)->nodeValue : '';
 597  
 598              if ($setvar != '') {
 599  
 600                  $last_answer_id++;
 601  
 602                  $answer_title = $xpath->query('xmlns:conditionvar/xmlns:varequal[@respident="' . $identifier . '"]', $response_item);
 603                  $answer_title = !empty($answer_title->item(0)->nodeValue) ? $answer_title->item(0)->nodeValue : '';
 604  
 605                  if (empty($answer_title)) {
 606                      $answer_title = $xpath->query('xmlns:conditionvar/xmlns:varsubstring[@respident="' . $identifier . '"]', $response_item);
 607                      $answer_title = !empty($answer_title->item(0)->nodeValue) ? '*' . $answer_title->item(0)->nodeValue . '*' : '';
 608                  }
 609  
 610                  if (empty($answer_title)) {
 611                      $answer_title = '*';
 612                  }
 613  
 614              $case = $xpath->query('xmlns:conditionvar/xmlns:varequal/@case', $response_item);
 615              $case = is_object($case->item(0)) ? $case->item(0)->nodeValue : 'no'
 616                                      ;
 617              $case = strtolower($case) == 'yes' ? 1 :
 618                              0;
 619  
 620                  $display_feedback = $xpath->query('xmlns:displayfeedback', $response_item);
 621  
 622                  unset($feedbacks_identifiers);
 623  
 624                  if (!empty($display_feedback)) {
 625  
 626                      foreach ($display_feedback as $feedback) {
 627  
 628                          $feedback_identifier = $feedback->getAttributeNode('linkrefid');
 629                          $feedback_identifier = !empty($feedback_identifier->nodeValue) ? $feedback_identifier->nodeValue : '';
 630  
 631                          if (!empty($feedback_identifier)) {
 632                              $feedbacks_identifiers[] = $feedback_identifier;
 633                          }
 634                      }
 635                  }
 636  
 637                  $feedback = '';
 638                  $feedbacks_identifiers = empty($feedbacks_identifiers) ? '' : $feedbacks_identifiers;
 639  
 640                  if (!empty($feedbacks_identifiers)) {
 641                      foreach ($feedbacks_identifiers as $feedback_identifier) {
 642                          $feedbacks = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:itemfeedback[@ident="' . $feedback_identifier . '"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
 643                          $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue . ' ' : '';
 644                      }
 645                  }
 646  
 647                  $answers_fib[] = array('id' => $last_answer_id,
 648                                         'title' => $answer_title,
 649                                         'score' => $setvar,
 650                                         'feedback' => $feedback,
 651                                         'case' => $case);
 652              }
 653          }
 654  
 655          $answers_fib = empty($answers_fib) ? '' : $answers_fib;
 656  
 657          return $answers_fib;
 658      }
 659  
 660  
 661      private function get_answers ($identifier, $assessment, &$last_answer_id) {
 662  
 663          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 664  
 665          $answers = array();
 666  
 667          $question_cc_type = $this->get_question_type($identifier, $assessment);
 668          $question_cc_type = $question_cc_type['cc'];
 669          $is_multiresponse = ($question_cc_type == CC_QUIZ_MULTIPLE_RESPONSE);
 670  
 671          if ($question_cc_type == CC_QUIZ_MULTIPLE_CHOICE || $is_multiresponse || $question_cc_type == CC_QUIZ_TRUE_FALSE) {
 672  
 673              $query_answers = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
 674              $query_answers_with_flow = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:flow/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
 675  
 676              $query_indentifer = '@ident';
 677              $query_title = 'xmlns:material/xmlns:mattext';
 678          }
 679  
 680          if ($question_cc_type == CC_QUIZ_ESSAY) {
 681  
 682              $query_answers = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:response_str';
 683              $query_answers_with_flow = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:flow/xmlns:response_str';
 684  
 685              $query_indentifer = '@ident';
 686              $query_title = 'xmlns:render_fib';
 687          }
 688  
 689          if ($question_cc_type == CC_QUIZ_FIB || $question_cc_type == CC_QUIZ_PATTERN_MACHT) {
 690  
 691              $xpath_query = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:response_str/@ident';
 692              $xpath_query_with_flow = '//xmlns:item[@ident="' . $identifier . '"]/xmlns:presentation/xmlns:flow/xmlns:response_str/@ident';
 693  
 694              $count_response = $xpath->evaluate('count(' . $xpath_query_with_flow . ')');
 695  
 696              if ($count_response == 0) {
 697                  $answer_identifier = $xpath->query($xpath_query);
 698              } else {
 699                  $answer_identifier = $xpath->query($xpath_query_with_flow);
 700              }
 701  
 702              $answer_identifier = !empty($answer_identifier->item(0)->nodeValue) ? $answer_identifier->item(0)->nodeValue : '';
 703  
 704              if ($question_cc_type == CC_QUIZ_FIB) {
 705                  $answers = $this->get_answers_fib ($identifier, $answer_identifier, $assessment, $last_answer_id);
 706              } else {
 707                  $answers = $this->get_answers_pattern_match ($identifier, $answer_identifier, $assessment, $last_answer_id);
 708              }
 709  
 710          } else {
 711  
 712              $count_response = $xpath->evaluate('count(' . $query_answers_with_flow . ')');
 713  
 714              if ($count_response == 0) {
 715                  $response_items = $xpath->query($query_answers);
 716              } else {
 717                  $response_items = $xpath->query($query_answers_with_flow);
 718              }
 719  
 720              if (!empty($response_items)) {
 721                  if ($is_multiresponse) {
 722                      $correct_answer_score = 0;
 723                      //get the correct answers count
 724                      $canswers_query = "//xmlns:item[@ident='{$identifier}']//xmlns:setvar[@varname='SCORE'][.=100]/../xmlns:conditionvar//xmlns:varequal[@case='Yes'][not(parent::xmlns:not)]";
 725                      $canswers = $xpath->query($canswers_query);
 726                      if ($canswers->length > 0) {
 727                          $correct_answer_score = round(1.0 / (float)$canswers->length, 7); //weird
 728                          $correct_answers_ident = array();
 729                          foreach ($canswers as $cnode) {
 730                              $correct_answers_ident[$cnode->nodeValue] = true;
 731                          }
 732                      }
 733                  }
 734                  foreach ($response_items as $response_item) {
 735  
 736                      $last_answer_id++;
 737  
 738                      $answer_identifier = $xpath->query($query_indentifer, $response_item);
 739                      $answer_identifier = !empty($answer_identifier->item(0)->nodeValue) ? $answer_identifier->item(0)->nodeValue : '';
 740  
 741                      $answer_title = $xpath->query($query_title, $response_item);
 742                      $answer_title = !empty($answer_title->item(0)->nodeValue) ? $answer_title->item(0)->nodeValue : '';
 743  
 744                      $answer_feedback = $this->get_feedback($assessment, $answer_identifier, $identifier, $question_cc_type);
 745  
 746                      $answer_score = $this->get_score($assessment, $answer_identifier, $identifier);
 747  
 748                      if ($is_multiresponse && isset($correct_answers_ident[$answer_identifier])) {
 749                          $answer_score = $correct_answer_score;
 750                      }
 751  
 752                      $answers[] = array('id' => $last_answer_id,
 753                                         'title' => $answer_title,
 754                                         'score' => $answer_score,
 755                                         'identifier' => $answer_identifier,
 756                                         'feedback' => $answer_feedback);
 757                  }
 758              }
 759          }
 760  
 761          $answers = empty($answers) ? '' : $answers;
 762  
 763          return $answers;
 764  
 765      }
 766  
 767      private function get_score ($assessment, $identifier, $question_identifier) {
 768  
 769          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 770  
 771          $resource_processing = $xpath->query('//xmlns:item[@ident="' . $question_identifier . '"]/xmlns:resprocessing/xmlns:respcondition');
 772  
 773          if (!empty($resource_processing)) {
 774  
 775              foreach ($resource_processing as $response) {
 776  
 777                  $question_cc_type = $this->get_question_type($question_identifier, $assessment);
 778                  $question_cc_type = $question_cc_type['cc'];
 779  
 780                  $varequal = $xpath->query('xmlns:conditionvar/xmlns:varequal', $response);
 781                  $varequal = !empty($varequal->item(0)->nodeValue) ? $varequal->item(0)->nodeValue : '';
 782  
 783                  if (strtolower($varequal) == strtolower($identifier)) {
 784                      $score = $xpath->query('xmlns:setvar', $response);
 785                      $score = !empty($score->item(0)->nodeValue) ? $score->item(0)->nodeValue : '';
 786                  }
 787              }
 788          }
 789  
 790          $score = empty($score) ? 0 : sprintf("%.7F", $score);
 791  
 792          return $score;
 793      }
 794  
 795      private function create_node_course_question_categories_question_category_question_multiple_choice ($question) {
 796  
 797          $node_course_question_categories_question_answer = '';
 798          $sheet_question_categories_question = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY_QUESTION_MULTIPLE_CHOICE);
 799  
 800          if (!empty($question['answers'])) {
 801              foreach ($question['answers'] as $answer) {
 802                  $node_course_question_categories_question_answer .= $this->create_node_course_question_categories_question_category_question_answer($answer);
 803              }
 804          }
 805  
 806          $answer_string = $this->get_answers_string($question['answers']);
 807  
 808          $is_single = ($question['cc_type'] == CC_QUIZ_MULTIPLE_CHOICE) ? 1 : 0;
 809  
 810          $find_tags = array('[#node_course_question_categories_question_category_question_answer#]',
 811                             '[#answer_string#]',
 812                             '[#is_single#]');
 813  
 814          $replace_values = array($node_course_question_categories_question_answer,
 815                                  self::safexml($answer_string),
 816                                  $is_single);
 817  
 818          $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
 819  
 820          return $node_question_categories_question;
 821      }
 822  
 823      private function create_node_course_question_categories_question_category_question_eesay ($question) {
 824  
 825          $node_course_question_categories_question_answer = '';
 826  
 827          $sheet_question_categories_question = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY_QUESTION_EESAY);
 828  
 829          if (!empty($question['answers'])) {
 830              foreach ($question['answers'] as $answer) {
 831                  $node_course_question_categories_question_answer .= $this->create_node_course_question_categories_question_category_question_answer($answer);
 832              }
 833          }
 834  
 835          $find_tags = array('[#node_course_question_categories_question_category_question_answer#]');
 836          $replace_values = array($node_course_question_categories_question_answer);
 837  
 838          $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
 839  
 840          return $node_question_categories_question;
 841      }
 842  
 843      private function create_node_course_question_categories_question_category_question_shortanswer ($question) { //, &$fib_questions) {
 844  
 845          $sheet_question_categories_question = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY_QUESTION_SHORTANSWER);
 846          $node_course_question_categories_question_answer = '';
 847  
 848          if (!empty($question['answers'])) {
 849              foreach ($question['answers'] as $answer) {
 850                  $node_course_question_categories_question_answer .= $this->create_node_course_question_categories_question_category_question_answer($answer);
 851              }
 852          }
 853  
 854          $answers_string = $this->get_answers_string($question['answers']);
 855  
 856          $use_case = 0;
 857  
 858          foreach ($question['answers'] as $answer) {
 859  
 860              if ($answer['case'] == 1) {
 861                  $use_case = 1;
 862              }
 863  
 864          }
 865  
 866          $find_tags = array('[#answers_string#]',
 867                             '[#use_case#]',
 868                             '[#node_course_question_categories_question_category_question_answer#]');
 869  
 870          $replace_values = array(self::safexml($answers_string),
 871                                  self::safexml($use_case),
 872                                  $node_course_question_categories_question_answer);
 873  
 874  
 875  
 876          $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
 877  
 878          return $node_question_categories_question;
 879  
 880      }
 881  
 882      private function create_node_course_question_categories_question_category_question_true_false ($question) {
 883  
 884          $node_course_question_categories_question_answer = '';
 885  
 886          $sheet_question_categories_question = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY_QUESTION_TRUE_FALSE);
 887  
 888          $trueanswer  = null;
 889          $falseanswer = null;
 890  
 891          if (!empty($question['answers'])) {
 892  
 893              // Identify the true and false answers.
 894              foreach ($question['answers'] as $answer) {
 895                  if ($answer['identifier'] == 'true') {
 896                      $trueanswer = $answer;
 897                  } else if ($answer['identifier'] == 'false') {
 898                      $falseanswer = $answer;
 899                  } else {
 900                      // Should not happen, but just in case.
 901                      throw new coding_exception("Unknown answer identifier detected" .
 902                              " in true/false quiz question with id {$question['id']}.");
 903                  }
 904  
 905                  $node_course_question_categories_question_answer .= $this->create_node_course_question_categories_question_category_question_answer($answer);
 906              }
 907  
 908              // Make sure the true and false answer was found.
 909              if (is_null($trueanswer) || is_null($falseanswer)) {
 910                  throw new coding_exception("Unable to correctly identify the " .
 911                          "true and false answers in the question with id {$question['id']}.");
 912              }
 913          }
 914  
 915          $find_tags = array('[#node_course_question_categories_question_category_question_answer#]',
 916                             '[#true_answer_id#]',
 917                             '[#false_answer_id#]');
 918  
 919          $replace_values = array($node_course_question_categories_question_answer,
 920                                  $trueanswer['id'],
 921                                  $falseanswer['id']);
 922  
 923          $node_question_categories_question = str_replace($find_tags, $replace_values, $sheet_question_categories_question);
 924  
 925          return $node_question_categories_question;
 926      }
 927  
 928      private function get_answers_string ($answers) {
 929  
 930          $answer_string = '';
 931  
 932          if (!empty($answers)) {
 933              foreach ($answers as $answer) {
 934                  $answer_string .= $answer['id'] . ',';
 935              }
 936          }
 937  
 938          $answer_string = !empty($answer_string) ? substr($answer_string, 0, strlen($answer_string) - 1) : '';
 939  
 940          return $answer_string;
 941  
 942      }
 943  
 944      private function create_node_course_question_categories_question_category_question_answer ($answer) {
 945  
 946          $sheet_question_categories_question_answer = cc2moodle::loadsheet(SHEET_COURSE_QUESTION_CATEGORIES_QUESTION_CATEGORY_QUESTION_ANSWER);
 947  
 948          $find_tags = array('[#answer_id#]',
 949                             '[#answer_text#]',
 950                             '[#answer_score#]',
 951                             '[#answer_feedback#]');
 952  
 953          $replace_values = array($answer['id'],
 954                                  self::safexml($answer['title']),
 955                                  $answer['score'],
 956                                  self::safexml($answer['feedback']));
 957  
 958          $node_question_categories_question_answer = str_replace($find_tags, $replace_values, $sheet_question_categories_question_answer);
 959  
 960          return $node_question_categories_question_answer;
 961      }
 962  
 963      private function get_question_type ($identifier, $assessment) {
 964  
 965          $xpath = cc2moodle::newx_path($assessment, cc2moodle::getquizns());
 966  
 967          $metadata = $xpath->query('//xmlns:item[@ident="' . $identifier . '"]/xmlns:itemmetadata/xmlns:qtimetadata/xmlns:qtimetadatafield');
 968  
 969          foreach ($metadata as $field) {
 970  
 971              $field_label = $xpath->query('xmlns:fieldlabel', $field);
 972              $field_label = !empty($field_label->item(0)->nodeValue) ? $field_label->item(0)->nodeValue : '';
 973  
 974              if ($field_label == 'cc_profile') {
 975                  $field_entry = $xpath->query('xmlns:fieldentry', $field);
 976                  $type = !empty($field_entry->item(0)->nodeValue) ? $field_entry->item(0)->nodeValue : '';
 977              }
 978          }
 979  
 980          $return_type = array();
 981  
 982          $return_type['moodle'] = '';
 983          $return_type['cc'] = $type;
 984  
 985          if ($type == CC_QUIZ_MULTIPLE_CHOICE) {
 986              $return_type['moodle'] = MOODLE_QUIZ_MULTIPLE_CHOICE;
 987          }
 988          if ($type == CC_QUIZ_MULTIPLE_RESPONSE) {
 989              $return_type['moodle'] = MOODLE_QUIZ_MULTIPLE_CHOICE;
 990          }
 991          if ($type == CC_QUIZ_TRUE_FALSE) {
 992              $return_type['moodle'] = MOODLE_QUIZ_TRUE_FALSE;
 993          }
 994          if ($type == CC_QUIZ_ESSAY) {
 995              $return_type['moodle'] = MOODLE_QUIZ_ESSAY;
 996          }
 997          if ($type == CC_QUIZ_FIB) {
 998              $return_type['moodle'] = MOODLE_QUIZ_SHORTANSWER;
 999          }
1000          if ($type == CC_QUIZ_PATTERN_MACHT) {
1001              $return_type['moodle'] = MOODLE_QUIZ_SHORTANSWER;
1002          }
1003  
1004          return $return_type;
1005  
1006      }
1007  }