Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.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    backup-convert
  18   * @copyright  2011 Darko Miletic <dmiletic@moodlerooms.com>
  19   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  20   */
  21  
  22  defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
  23  
  24  require_once ('cc_utils.php');
  25  require_once ('cc_general.php');
  26  
  27  abstract class cc_xml_namespace {
  28      const xml = 'http://www.w3.org/XML/1998/namespace';
  29  }
  30  
  31  abstract class cc_qti_metadata {
  32      // Assessment.
  33      const qmd_assessmenttype       = 'qmd_assessmenttype';
  34      const qmd_scoretype            = 'qmd_scoretype';
  35      const qmd_feedbackpermitted    = 'qmd_feedbackpermitted';
  36      const qmd_hintspermitted       = 'qmd_hintspermitted';
  37      const qmd_solutionspermitted   = 'qmd_solutionspermitted';
  38      const qmd_timelimit            = 'qmd_timelimit';
  39      const cc_allow_late_submission = 'cc_allow_late_submission';
  40      const cc_maxattempts           = 'cc_maxattempts';
  41      const cc_profile               = 'cc_profile';
  42  
  43      // Items.
  44      const cc_weighting         = 'cc_weighting';
  45      const qmd_scoringpermitted = 'qmd_scoringpermitted';
  46      const qmd_computerscored   = 'qmd_computerscored';
  47      const cc_question_category = 'cc_question_category';
  48  }
  49  
  50  abstract class cc_qti_profiletype {
  51      const multiple_choice   = 'cc.multiple_choice.v0p1';
  52      const multiple_response = 'cc.multiple_response.v0p1';
  53      const true_false        = 'cc.true_false.v0p1';
  54      const field_entry       = 'cc.fib.v0p1';
  55      const pattern_match     = 'cc.pattern_match.v0p1';
  56      const essay             = 'cc.essay.v0p1';
  57  
  58      /**
  59       *
  60       * validates a profile value
  61       * @param string $value
  62       * @return boolean
  63       */
  64      public static function valid($value) {
  65          static $verification_values = array( self::essay,
  66                                               self::field_entry,
  67                                               self::multiple_choice,
  68                                               self::multiple_response,
  69                                               self::pattern_match,
  70                                               self::true_false
  71                                             );
  72          return in_array($value, $verification_values);
  73      }
  74  
  75  }
  76  
  77  abstract class cc_qti_values {
  78      const exam_profile = 'cc.exam.v0p1';
  79      const Yes          = 'Yes';
  80      const No           = 'No';
  81      const Response     = 'Response';
  82      const Solution     = 'Solution';
  83      const Hint         = 'Hint';
  84      const Examination  = 'Examination';
  85      const Percentage   = 'Percentage';
  86      const unlimited    = 'unlimited';
  87      const Single       = 'Single';
  88      const Multiple     = 'Multiple';
  89      const Ordered      = 'Ordered';
  90      const Asterisk     = 'Asterisk';
  91      const Box          = 'Box';
  92      const Dashline     = 'Dashline';
  93      const Underline    = 'Underline';
  94      const Decimal      = 'Decimal';
  95      const Integer      = 'Integer';
  96      const Scientific   = 'Scientific';
  97      const String       = 'String';
  98      const SCORE        = 'SCORE';
  99      const Set          = 'Set';
 100      const Complete     = 'Complete';
 101      const texttype     = 'text/plain';
 102      const htmltype     = 'text/html';
 103  }
 104  
 105  abstract class cc_qti_tags {
 106      const questestinterop = 'questestinterop';
 107      const assessment = 'assessment';
 108      const qtimetadata = 'qtimetadata';
 109      const qtimetadatafield = 'qtimetadatafield';
 110      const fieldlabel = 'fieldlabel';
 111      const fieldentry = 'fieldentry';
 112      const section = 'section';
 113      const ident = 'ident';
 114      const item = 'item';
 115      const title = 'title';
 116      const itemmetadata = 'itemmetadata';
 117      const presentation = 'presentation';
 118      const material = 'material';
 119      const mattext = 'mattext';
 120      const matref = 'matref';
 121      const matbreak = 'matbreak';
 122      const texttype = 'texttype';
 123      const response_lid = 'response_lid';
 124      const render_choice = 'render_choice';
 125      const response_label = 'response_label';
 126      const resprocessing = 'resprocessing';
 127      const outcomes = 'outcomes';
 128      const decvar = 'decvar';
 129      const respcondition = 'respcondition';
 130      const conditionvar = 'conditionvar';
 131      const other = 'other';
 132      const displayfeedback = 'displayfeedback';
 133      const maxvalue = 'maxvalue';
 134      const minvalue = 'minvalue';
 135      const varname = 'varname';
 136      const vartype = 'vartype';
 137      const continue_ = 'continue';
 138      const feedbacktype = 'feedbacktype';
 139      const linkrefid = 'linkrefid';
 140      const varequal = 'varequal';
 141      const respident = 'respident';
 142      const itemfeedback = 'itemfeedback';
 143      const flow_mat = 'flow_mat';
 144      const rcardinality = 'rcardinality';
 145      const charset = 'charset';
 146      const label = 'label';
 147      const uri = 'uri';
 148      const width = 'width';
 149      const height = 'height';
 150      const x0 = 'x0';
 151      const y0 = 'y0';
 152      const xml_lang = 'lang';
 153      const xml_space = 'space';
 154      const rubric = 'rubric';
 155      const altmaterial = 'altmaterial';
 156      const presentation_material = 'presentation_material';
 157      const t_class = 'class';
 158      const material_ref = 'material_ref';
 159      const rtiming = 'rtiming';
 160      const render_fib = 'render_fib';
 161      const shuffle = 'shuffle';
 162      const minnumber = 'minnumber';
 163      const maxnumber = 'maxnumber';
 164      const encoding = 'encoding';
 165      const maxchars = 'maxchars';
 166      const prompt = 'prompt';
 167      const fibtype = 'fibtype';
 168      const rows = 'rows';
 169      const columns = 'columns';
 170      const labelrefid = 'labelrefid';
 171      const rshuffle = 'rshuffle';
 172      const match_group = 'match_group';
 173      const match_max = 'match_max';
 174      const flow = 'flow';
 175      const response_str = 'response_str';
 176      const flow_label = 'flow_label';
 177      const setvar = 'setvar';
 178      const action = 'action';
 179      const and_ = 'and';
 180      const not_ = 'not';
 181      const case_ = 'case';
 182      const varsubstring = 'varsubstring';
 183      const hint = 'hint';
 184      const solution = 'solution';
 185      const feedbackstyle = 'feedbackstyle';
 186      const solutionmaterial = 'solutionmaterial';
 187      const hintmaterial = 'hintmaterial';
 188  }
 189  
 190  class cc_question_metadata_base {
 191      /**
 192       * @var array
 193       */
 194      protected $metadata = array();
 195  
 196      /**
 197       * @param string $setting
 198       * @param mixed $value
 199       */
 200      protected function set_setting($setting, $value = null) {
 201          $this->metadata[$setting] = $value;
 202      }
 203  
 204      /**
 205       * @param string $setting
 206       * @return mixed
 207       */
 208      protected function get_setting($setting) {
 209          $result = null;
 210          if (array_key_exists($setting, $this->metadata)) {
 211              $result = $this->metadata[$setting];
 212          }
 213          return $result;
 214      }
 215  
 216      /**
 217       * @param string $setting
 218       * @param string $namespace
 219       * @param string $value
 220       */
 221      protected function set_setting_wns($setting, $namespace, $value = null) {
 222          $this->metadata[$setting] = array($namespace => $value);
 223      }
 224  
 225      /**
 226       * @param string $setting
 227       * @param boolean $value
 228       */
 229      protected function enable_setting_yesno($setting, $value = true) {
 230          $svalue = $value ? cc_qti_values::Yes : cc_qti_values::No;
 231          $this->set_setting($setting, $svalue);
 232      }
 233  
 234      /**
 235       * @param XMLGenericDocument $doc
 236       * @param DOMNode $item
 237       * @param string $namespace
 238       */
 239      public function generate_attributes(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 240          foreach ($this->metadata as $attribute => $value) {
 241              if (!is_null($value)) {
 242                  if (!is_array($value)) {
 243                      $doc->append_new_attribute_ns($item, $namespace, $attribute, $value);
 244                  } else {
 245                      $ns = key($value);
 246                      $nval = current($value);
 247                      if (!is_null($nval)) {
 248                          $doc->append_new_attribute_ns($item, $ns, $attribute, $nval);
 249                      }
 250                  }
 251              }
 252          }
 253      }
 254  
 255      /**
 256       * @param XMLGenericDocument $doc
 257       * @param DOMNode $item
 258       * @param string $namespace
 259       */
 260      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 261          $qtimetadata = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::qtimetadata);
 262          foreach ($this->metadata as $label => $entry) {
 263              if (!is_null($entry)) {
 264                  $qtimetadatafield = $doc->append_new_element_ns($qtimetadata, $namespace, cc_qti_tags::qtimetadatafield);
 265                  $doc->append_new_element_ns($qtimetadatafield, $namespace, cc_qti_tags::fieldlabel, $label);
 266                  $doc->append_new_element_ns($qtimetadatafield, $namespace, cc_qti_tags::fieldentry, $entry);
 267              }
 268          }
 269      }
 270  }
 271  
 272  class cc_question_metadata extends cc_question_metadata_base {
 273  
 274      public function set_category($value) {
 275          $this->set_setting(cc_qti_metadata::cc_question_category, $value);
 276      }
 277  
 278      public function set_weighting($value) {
 279          $this->set_setting(cc_qti_metadata::cc_weighting, $value);
 280      }
 281  
 282      public function enable_scoringpermitted($value = true) {
 283          $this->enable_setting_yesno(cc_qti_metadata::qmd_scoringpermitted, $value);
 284      }
 285  
 286      public function enable_computerscored($value = true) {
 287          $this->enable_setting_yesno(cc_qti_metadata::qmd_computerscored, $value);
 288      }
 289  
 290      /**
 291       *
 292       * Constructs metadata
 293       * @param string $profile
 294       * @throws InvalidArgumentException
 295       */
 296      public function __construct($profile) {
 297          if (!cc_qti_profiletype::valid($profile)) {
 298              throw new InvalidArgumentException('Invalid profile type!');
 299          }
 300          $this->set_setting(cc_qti_metadata::cc_profile, $profile);
 301          $this->set_setting(cc_qti_metadata::cc_question_category);
 302          $this->set_setting(cc_qti_metadata::cc_weighting        );
 303          $this->set_setting(cc_qti_metadata::qmd_scoringpermitted);
 304          $this->set_setting(cc_qti_metadata::qmd_computerscored  );
 305      }
 306  }
 307  
 308  
 309  class cc_assesment_metadata extends cc_question_metadata_base {
 310  
 311      public function enable_hints($value = true) {
 312          $this->enable_setting_yesno(cc_qti_metadata::qmd_hintspermitted, $value);
 313      }
 314  
 315      public function enable_solutions($value = true) {
 316          $this->enable_setting_yesno(cc_qti_metadata::qmd_solutionspermitted, $value);
 317      }
 318  
 319      public function enable_latesubmissions($value = true) {
 320          $this->enable_setting_yesno(cc_qti_metadata::cc_allow_late_submission, $value);
 321      }
 322  
 323      public function enable_feedback($value = true) {
 324          $this->enable_setting_yesno(cc_qti_metadata::qmd_feedbackpermitted, $value);
 325      }
 326  
 327      public function set_timelimit($value) {
 328          $ivalue = (int)$value;
 329          if (($ivalue < 0) || ($ivalue > 527401)) {
 330              throw new OutOfRangeException('Time limit value out of permitted range!');
 331          }
 332  
 333          $this->set_setting(cc_qti_metadata::qmd_timelimit, $value);
 334      }
 335  
 336      public function set_maxattempts($value) {
 337          $valid_values = array(cc_qti_values::Examination, cc_qti_values::unlimited, 1, 2, 3, 4, 5);
 338          if (!in_array($value, $valid_values)) {
 339              throw new OutOfRangeException('Max attempts has invalid value');
 340          }
 341  
 342          $this->set_setting(cc_qti_metadata::cc_maxattempts, $value);
 343      }
 344  
 345      public function __construct() {
 346          //prepared default values
 347          $this->set_setting(cc_qti_metadata::cc_profile        , cc_qti_values::exam_profile);
 348          $this->set_setting(cc_qti_metadata::qmd_assessmenttype, cc_qti_values::Examination );
 349          $this->set_setting(cc_qti_metadata::qmd_scoretype     , cc_qti_values::Percentage  );
 350          //optional empty values
 351          $this->set_setting(cc_qti_metadata::qmd_feedbackpermitted   );
 352          $this->set_setting(cc_qti_metadata::qmd_hintspermitted      );
 353          $this->set_setting(cc_qti_metadata::qmd_solutionspermitted  );
 354          $this->set_setting(cc_qti_metadata::qmd_timelimit           );
 355          $this->set_setting(cc_qti_metadata::cc_allow_late_submission);
 356          $this->set_setting(cc_qti_metadata::cc_maxattempts          );
 357      }
 358  
 359  }
 360  
 361  class cc_assesment_mattext extends cc_question_metadata_base {
 362      protected $value = null;
 363  
 364      public function __construct($value = null) {
 365          $this->set_setting(cc_qti_tags::texttype, cc_qti_values::texttype);
 366          $this->set_setting(cc_qti_tags::charset);//, 'ascii-us');
 367          $this->set_setting(cc_qti_tags::label);
 368          $this->set_setting(cc_qti_tags::uri);
 369          $this->set_setting(cc_qti_tags::width);
 370          $this->set_setting(cc_qti_tags::height);
 371          $this->set_setting(cc_qti_tags::x0);
 372          $this->set_setting(cc_qti_tags::y0);
 373          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml);
 374          $this->set_setting_wns(cc_qti_tags::xml_space, cc_xml_namespace::xml);//, 'default');
 375          $this->value = $value;
 376      }
 377  
 378      public function set_label($value) {
 379          $this->set_setting(cc_qti_tags::label, $value);
 380      }
 381  
 382      public function set_uri($value) {
 383          $this->set_setting(cc_qti_tags::uri, $value);
 384      }
 385  
 386      public function set_width_height($width = null, $height = null) {
 387          $this->set_setting(cc_qti_tags::width, $width);
 388          $this->set_setting(cc_qti_tags::height, $height);
 389      }
 390  
 391      public function set_coor($x = null, $y = null) {
 392          $this->set_setting(cc_qti_tags::x0, $x);
 393          $this->set_setting(cc_qti_tags::y0, $y);
 394      }
 395  
 396      public function set_lang($lang = null) {
 397          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml, $lang);
 398      }
 399  
 400      public function set_content($content, $type = cc_qti_values::texttype, $charset = null) {
 401          $this->value = $content;
 402          $this->set_setting(cc_qti_tags::texttype, $type);
 403          $this->set_setting(cc_qti_tags::charset, $charset);
 404      }
 405  
 406      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 407          $mattext = $doc->append_new_element_ns_cdata($item, $namespace, cc_qti_tags::mattext, $this->value);
 408          $this->generate_attributes($doc, $mattext, $namespace);
 409      }
 410  }
 411  
 412  class cc_assesment_matref {
 413      protected $linkref = null;
 414  
 415      public function __construct($linkref) {
 416          $this->linkref = $linkref;
 417      }
 418  
 419      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 420          $doc->append_new_element_ns($item, $namespace, cc_qti_tags::matref, $this->linkref);
 421          $doc->append_new_attribute_ns($node, $namespace, cc_qti_tags::linkrefid, $this->linkref);
 422      }
 423  }
 424  
 425  class cc_assesment_response_matref extends cc_assesment_matref {
 426      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 427          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::material_ref);
 428          $doc->append_new_attribute_ns($node, $namespace, cc_qti_tags::linkrefid, $this->linkref);
 429      }
 430  }
 431  
 432  class cc_assesment_matbreak {
 433      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 434          $doc->append_new_element_ns($item, $namespace, cc_qti_tags::matbreak);
 435      }
 436  }
 437  
 438  abstract class cc_assesment_material_base extends cc_question_metadata_base {
 439      /**
 440      * @var mixed
 441      */
 442      protected $mattag = null;
 443      protected $tagname   = null;
 444  
 445      protected function set_tag_value($object) {
 446          $this->mattag  = $object;
 447      }
 448  
 449      public function set_mattext(cc_assesment_mattext $object) {
 450          $this->set_tag_value($object);
 451      }
 452  
 453      public function set_matref(cc_assesment_matref $object) {
 454          $this->set_tag_value($object);
 455      }
 456  
 457      public function set_matbreak(cc_assesment_matbreak $object) {
 458          $this->set_tag_value($object);
 459      }
 460  
 461      public function set_lang($value) {
 462          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml, $value);
 463      }
 464  
 465      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 466          $material = $doc->append_new_element_ns($item, $namespace, $this->tagname);
 467          $this->generate_attributes($doc, $material, $namespace);
 468          if (!empty($this->mattag)) {
 469              $this->mattag->generate($doc, $material, $namespace);
 470          }
 471          return $material;
 472      }
 473  }
 474  
 475  class cc_assesment_altmaterial extends cc_assesment_material_base {
 476      public function __construct($value = null) {
 477          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml);
 478          $this->tagname = cc_qti_tags::altmaterial;
 479      }
 480  }
 481  
 482  class cc_assesment_material extends cc_assesment_material_base {
 483  
 484      protected $altmaterial = null;
 485  
 486      public function __construct($value = null) {
 487          $this->set_setting(cc_qti_tags::label);
 488          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml);
 489          $this->tagname = cc_qti_tags::material;
 490      }
 491  
 492      public function set_label($value) {
 493          $this->set_setting(cc_qti_tags::label, $value);
 494      }
 495  
 496      public function set_altmaterial(cc_assesment_altmaterial $object) {
 497          $this->altmaterial = $object;
 498      }
 499  
 500      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 501          $material = parent::generate($doc, $item, $namespace);
 502          if (!empty($this->altmaterial)) {
 503              $this->altmaterial->generate($doc, $material, $namespace);
 504          }
 505      }
 506  }
 507  
 508  class cc_assesment_rubric_base extends cc_question_metadata_base {
 509  
 510      protected $material = null;
 511  
 512      public function set_material($object) {
 513          $this->material = $object;
 514      }
 515  
 516      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 517          $rubric = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::rubric);
 518          if (!empty($this->material)) {
 519              $this->material->generate($doc, $rubric, $namespace);
 520          }
 521      }
 522  }
 523  
 524  class cc_assesment_presentation_material_base extends cc_question_metadata_base {
 525      protected $flowmats = array();
 526  
 527      public function add_flow_mat($object) {
 528          $this->flowmats[] = $object;
 529      }
 530  
 531      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 532          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::presentation_material);
 533          if (!empty($this->flowmats)) {
 534              foreach ($this->flowmats as $flow_mat) {
 535                  $flow_mat->generate($doc, $node, $namespace);
 536              }
 537          }
 538      }
 539  }
 540  
 541  class cc_assesment_flow_mat_base extends cc_question_metadata_base {
 542  
 543      protected $mattag = null;
 544  
 545      protected function set_tag_value($object) {
 546          $this->mattag  = $object;
 547      }
 548  
 549      public function set_flow_mat(cc_assesment_flow_mat_base $object) {
 550          $this->set_tag_value($object);
 551      }
 552  
 553      public function set_material(cc_assesment_material $object) {
 554          $this->set_tag_value($object);
 555      }
 556  
 557      public function set_material_ref(cc_assesment_matref $object) {
 558          $this->set_tag_value($object);
 559      }
 560  
 561      public function __construct($value = null) {
 562          $this->set_setting(cc_qti_tags::t_class);
 563      }
 564  
 565      public function set_class($value) {
 566          $this->set_setting(cc_qti_tags::t_class, $value);
 567      }
 568  
 569      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 570          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::flow_mat);
 571          $this->generate_attributes($doc, $node, $namespace);
 572          if (!empty($this->mattag)) {
 573              $this->mattag->generate($doc, $node, $namespace);
 574          }
 575      }
 576  
 577  }
 578  
 579  class cc_assesment_section extends cc_question_metadata_base {
 580      /**
 581       * @var array
 582       */
 583      protected $items = array();
 584  
 585      public function __construct() {
 586          $this->set_setting(cc_qti_tags::ident, cc_helpers::uuidgen('I_'));
 587          $this->set_setting(cc_qti_tags::title);
 588          $this->set_setting_wns(cc_qti_tags::xml_lang, cc_xml_namespace::xml);
 589      }
 590  
 591      public function set_ident($value) {
 592          $this->set_setting(cc_qti_tags::ident, $value);
 593      }
 594  
 595      public function set_title($value) {
 596          $this->set_setting(cc_qti_tags::title, $value);
 597      }
 598  
 599      public function set_lang($value) {
 600          $this->set_setting_wns(cc_qti_tags::xml_lang, cc_xml_namespace::xml, $value);
 601      }
 602  
 603      public function add_item(cc_assesment_section_item $object) {
 604          $this->items[] = $object;
 605      }
 606  
 607      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 608          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::section);
 609          $this->generate_attributes($doc, $node, $namespace);
 610          if (!empty($this->items)) {
 611              foreach ($this->items as $item) {
 612                  $item->generate($doc, $node, $namespace);
 613              }
 614          }
 615      }
 616  }
 617  
 618  class cc_assesment_itemmetadata extends cc_question_metadata_base {
 619      public function add_metadata($object) {
 620          $this->metadata[] = $object;
 621      }
 622  
 623      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 624          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::itemmetadata);
 625          if (!empty($this->metadata)) {
 626              foreach ($this->metadata as $metaitem) {
 627                  $metaitem->generate($doc, $node, $namespace);
 628              }
 629          }
 630      }
 631  }
 632  
 633  class cc_assesment_decvartype extends cc_question_metadata_base {
 634  
 635      public function __construct() {
 636          $this->set_setting(cc_qti_tags::varname, cc_qti_values::SCORE);
 637          $this->set_setting(cc_qti_tags::vartype, cc_qti_values::Integer);
 638          $this->set_setting(cc_qti_tags::minvalue);
 639          $this->set_setting(cc_qti_tags::maxvalue);
 640      }
 641  
 642      public function set_vartype($value) {
 643          $this->set_setting(cc_qti_tags::vartype, $value);
 644      }
 645  
 646      public function set_limits($min = null, $max = null) {
 647          $this->set_setting(cc_qti_tags::minvalue, $min);
 648          $this->set_setting(cc_qti_tags::maxvalue, $max);
 649      }
 650  
 651      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 652          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::decvar);
 653          $this->generate_attributes($doc, $node, $namespace);
 654      }
 655  }
 656  
 657  
 658  class cc_assignment_conditionvar_othertype extends cc_question_metadata_base {
 659      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 660          $doc->append_new_element_ns($item, $namespace, cc_qti_tags::other);
 661      }
 662  }
 663  
 664  class cc_assignment_conditionvar_varequaltype extends cc_question_metadata_base {
 665      protected $tagname = null;
 666      protected $answerid = null;
 667  
 668      public function __construct($value = null) {
 669          if (is_null($value)) {
 670              throw new InvalidArgumentException('Must not pass null!');
 671          }
 672          $this->answerid = $value;
 673          $this->set_setting(cc_qti_tags::respident);
 674          $this->set_setting(cc_qti_tags::case_);//, cc_qti_values::No  );
 675          $this->tagname = cc_qti_tags::varequal;
 676      }
 677  
 678      public function set_respident($value) {
 679          $this->set_setting(cc_qti_tags::respident, $value);
 680      }
 681  
 682      public function enable_case($value = true) {
 683          $this->enable_setting_yesno(cc_qti_tags::case_, $value);
 684      }
 685  
 686      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 687          $node = $doc->append_new_element_ns($item, $namespace, $this->tagname, $this->answerid);
 688          $this->generate_attributes($doc, $node, $namespace);
 689      }
 690  }
 691  
 692  class cc_assignment_conditionvar_varsubstringtype extends cc_assignment_conditionvar_varequaltype {
 693      public function __construct($value) {
 694          parent::__construct($value);
 695          $this->tagname = cc_qti_tags::varsubstring;
 696      }
 697  }
 698  
 699  
 700  class cc_assignment_conditionvar_andtype extends cc_question_metadata_base {
 701      protected $nots = array();
 702      protected $varequals = array();
 703  
 704      public function set_not(cc_assignment_conditionvar_varequaltype $object) {
 705          $this->nots[] = $object;
 706      }
 707  
 708      public function set_varequal(cc_assignment_conditionvar_varequaltype $object) {
 709          $this->varequals[] = $object;
 710      }
 711  
 712      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 713          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::and_);
 714          if (!empty($this->nots)) {
 715              foreach ($this->nots as $notv) {
 716                  $not = $doc->append_new_element_ns($node, $namespace, cc_qti_tags::not_);
 717                  $notv->generate($doc, $not, $namespace);
 718              }
 719          }
 720  
 721          if (!empty($this->varequals)) {
 722              foreach ($this->varequals as $varequal) {
 723                  $varequal->generate($doc, $node, $namespace);
 724              }
 725          }
 726      }
 727  }
 728  
 729  class cc_assignment_conditionvar extends cc_question_metadata_base {
 730  
 731      /**
 732       * @var cc_assignment_conditionvar_andtype
 733       */
 734      protected $and = null;
 735      /**
 736       * @var cc_assignment_conditionvar_othertype
 737       */
 738      protected $other = null;
 739      /**
 740       * @var array
 741       */
 742      protected $varequal = array();
 743      /**
 744       * @var cc_assignment_conditionvar_varsubstringtype
 745       */
 746      protected $varsubstring = null;
 747  
 748      public function set_and(cc_assignment_conditionvar_andtype $object) {
 749          $this->and = $object;
 750      }
 751  
 752      public function set_other(cc_assignment_conditionvar_othertype $object) {
 753          $this->other = $object;
 754      }
 755  
 756      public function set_varequal(cc_assignment_conditionvar_varequaltype $object) {
 757          $this->varequal[] = $object;
 758      }
 759  
 760      public function set_varsubstring(cc_assignment_conditionvar_varsubstringtype $object) {
 761          $this->varsubstring = $object;
 762      }
 763  
 764      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 765          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::conditionvar);
 766  
 767          if (!empty($this->and)) {
 768              $this->and->generate($doc, $node, $namespace);
 769          }
 770  
 771          if (!empty($this->other)) {
 772              $this->other->generate($doc, $node, $namespace);
 773          }
 774  
 775          if (!empty($this->varequal)) {
 776              foreach ($this->varequal as $varequal) {
 777                  $varequal->generate($doc, $node, $namespace);
 778              }
 779          }
 780  
 781          if (!empty($this->varsubstring)) {
 782              $this->varsubstring->generate($doc, $node, $namespace);
 783          }
 784      }
 785  }
 786  
 787  class cc_assignment_displayfeedbacktype extends cc_question_metadata_base {
 788      public function __construct() {
 789          $this->set_setting(cc_qti_tags::feedbacktype);
 790          $this->set_setting(cc_qti_tags::linkrefid);
 791      }
 792  
 793      public function set_feedbacktype($value) {
 794          $this->set_setting(cc_qti_tags::feedbacktype, $value);
 795      }
 796  
 797      public function set_linkrefid($value) {
 798          $this->set_setting(cc_qti_tags::linkrefid, $value);
 799      }
 800  
 801      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 802          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::displayfeedback);
 803          $this->generate_attributes($doc, $node, $namespace);
 804      }
 805  }
 806  
 807  
 808  class cc_assignment_setvartype extends cc_question_metadata_base {
 809      /**
 810       * @var integer
 811       */
 812      protected $tagvalue = null;
 813  
 814      public function __construct($tagvalue = 100) {
 815          $this->set_setting(cc_qti_tags::varname, cc_qti_values::SCORE);
 816          $this->set_setting(cc_qti_tags::action , cc_qti_values::Set  );
 817          $this->tagvalue = $tagvalue;
 818      }
 819  
 820      public function set_varname($value) {
 821          $this->set_setting(cc_qti_tags::varname, $value);
 822      }
 823  
 824      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 825          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::setvar, $this->tagvalue);
 826          $this->generate_attributes($doc, $node, $namespace);
 827      }
 828  }
 829  
 830  class cc_assesment_respconditiontype extends cc_question_metadata_base {
 831      /**
 832       * @var cc_assignment_conditionvar
 833       */
 834      protected $conditionvar = null;
 835      protected $setvar = array();
 836      protected $displayfeedback = array();
 837  
 838      public function __construct() {
 839          $this->set_setting(cc_qti_tags::title);
 840          $this->set_setting(cc_qti_tags::continue_, cc_qti_values::No);
 841      }
 842  
 843      public function set_title($value) {
 844          $this->set_setting(cc_qti_tags::title, $value);
 845      }
 846  
 847      public function enable_continue($value = true) {
 848          $this->enable_setting_yesno(cc_qti_tags::continue_, $value);
 849      }
 850  
 851      public function set_conditionvar(cc_assignment_conditionvar $object) {
 852          $this->conditionvar = $object;
 853      }
 854  
 855      public function add_setvar(cc_assignment_setvartype $object) {
 856          $this->setvar[] = $object;
 857      }
 858  
 859      public function add_displayfeedback(cc_assignment_displayfeedbacktype $object) {
 860          $this->displayfeedback[] = $object;
 861      }
 862  
 863      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 864          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::respcondition);
 865          $this->generate_attributes($doc, $node, $namespace);
 866  
 867          if (!empty($this->conditionvar)) {
 868              $this->conditionvar->generate($doc, $node, $namespace);
 869          }
 870  
 871          if (!empty($this->setvar)) {
 872              foreach ($this->setvar as $setvar) {
 873                  $setvar->generate($doc, $node, $namespace);
 874              }
 875          }
 876  
 877          if (!empty($this->displayfeedback)) {
 878              foreach ($this->displayfeedback as $displayfeedback) {
 879                  $displayfeedback->generate($doc, $node, $namespace);
 880              }
 881          }
 882      }
 883  }
 884  
 885  
 886  class cc_assesment_resprocessingtype extends cc_question_metadata_base {
 887      /**
 888       * @var cc_assesment_decvartype
 889       */
 890      protected $decvar = null;
 891      /**
 892       * @var array
 893       */
 894      protected $respconditions = array();
 895  
 896      public function set_decvar(cc_assesment_decvartype $object) {
 897          $this->decvar = $object;
 898      }
 899  
 900      public function add_respcondition(cc_assesment_respconditiontype $object) {
 901          $this->respconditions[] = $object;
 902      }
 903  
 904      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 905          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::resprocessing);
 906          $outcomes = $doc->append_new_element_ns($node, $namespace, cc_qti_tags::outcomes);
 907          if (!empty($this->decvar)) {
 908              $this->decvar->generate($doc, $outcomes, $namespace);
 909          }
 910          if (!empty($this->respconditions)) {
 911              foreach ($this->respconditions as $rcond) {
 912                  $rcond->generate($doc, $node, $namespace);
 913              }
 914          }
 915      }
 916  }
 917  
 918  
 919  class cc_assesment_itemfeedback_shintmaterial_base extends cc_question_metadata_base {
 920      /**
 921       * @var string
 922       */
 923      protected $tagname = null;
 924      /**
 925       * @var array
 926       */
 927      protected $flow_mats = array();
 928      /**
 929       * @var array
 930       */
 931      protected $materials = array();
 932  
 933      /**
 934       * @param cc_assesment_flow_mattype $object
 935       */
 936      public function add_flow_mat(cc_assesment_flow_mattype $object) {
 937          $this->flow_mats[] = $object;
 938      }
 939  
 940      /**
 941       * @param cc_assesment_material $object
 942       */
 943      public function add_material(cc_assesment_material $object) {
 944          $this->materials[] = $object;
 945      }
 946  
 947      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 948          $node = $doc->append_new_element_ns($item, $namespace, $this->tagname);
 949  
 950          if (!empty($this->flow_mats)) {
 951              foreach ($this->flow_mats as $flow_mat) {
 952                  $flow_mat->generate($doc, $node, $namespace);
 953              }
 954          }
 955  
 956          if (!empty($this->materials)) {
 957              foreach ($this->materials as $material) {
 958                  $material->generate($doc, $node, $namespace);
 959              }
 960          }
 961      }
 962  }
 963  
 964  class cc_assesment_itemfeedback_hintmaterial extends cc_assesment_itemfeedback_shintmaterial_base {
 965      public function __construct() {
 966          $this->tagname = cc_qti_tags::hint;
 967      }
 968  }
 969  
 970  class cc_assesment_itemfeedback_solutionmaterial extends cc_assesment_itemfeedback_shintmaterial_base {
 971      public function __construct() {
 972          $this->tagname = cc_qti_tags::solutionmaterial;
 973      }
 974  }
 975  
 976  class cc_assesment_itemfeedback_shintype_base extends cc_question_metadata_base {
 977      /**
 978       * @var string
 979       */
 980      protected $tagname = null;
 981      /**
 982       * @var array
 983      */
 984      protected $items = array();
 985  
 986      public function __construct() {
 987          $this->set_setting(cc_qti_tags::feedbackstyle, cc_qti_values::Complete);
 988      }
 989  
 990      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
 991          $node = $doc->append_new_element_ns($item, $namespace, $this->tagname);
 992          $this->generate_attributes($doc, $node, $namespace);
 993  
 994          if (!empty($this->items)) {
 995              foreach ($this->items as $telement) {
 996                  $telement->generate($doc, $node, $namespace);
 997              }
 998          }
 999      }
1000  }
1001  
1002  class cc_assesment_itemfeedback_solutiontype extends cc_assesment_itemfeedback_shintype_base {
1003      public function __construct() {
1004          parent::__construct();
1005          $this->tagname = cc_qti_tags::solution;
1006      }
1007  
1008      /**
1009       * @param cc_assesment_itemfeedback_solutionmaterial $object
1010       */
1011      public function add_solutionmaterial(cc_assesment_itemfeedback_solutionmaterial $object) {
1012          $this->items[] = $object;
1013      }
1014  }
1015  
1016  class cc_assesment_itemfeedbac_hinttype extends cc_assesment_itemfeedback_shintype_base {
1017      public function __construct() {
1018          parent::__construct();
1019          $this->tagname = cc_qti_tags::hint;
1020      }
1021  
1022      /**
1023       * @param cc_assesment_itemfeedback_hintmaterial $object
1024       */
1025      public function add_hintmaterial(cc_assesment_itemfeedback_hintmaterial $object) {
1026          $this->items[] = $object;
1027      }
1028  }
1029  
1030  class cc_assesment_itemfeedbacktype extends cc_question_metadata_base {
1031      /**
1032       * @var cc_assesment_flow_mattype
1033       */
1034      protected $flow_mat = null;
1035      /**
1036       * @var cc_assesment_material
1037       */
1038      protected $material = null;
1039      /**
1040       * @var cc_assesment_itemfeedback_solutiontype
1041       */
1042      protected $solution = null;
1043      protected $hint = null;
1044  
1045      public function __construct() {
1046          $this->set_setting(cc_qti_tags::ident, cc_helpers::uuidgen('I_'));
1047          $this->set_setting(cc_qti_tags::title);
1048      }
1049  
1050      /**
1051       * @param string $value
1052       */
1053      public function set_ident($value) {
1054          $this->set_setting(cc_qti_tags::ident, $value);
1055      }
1056  
1057      /**
1058       * @param string $value
1059       */
1060      public function set_title($value) {
1061          $this->set_setting(cc_qti_tags::title, $value);
1062      }
1063  
1064      /**
1065       * @param cc_assesment_flow_mattype $object
1066       */
1067      public function set_flow_mat(cc_assesment_flow_mattype $object) {
1068          $this->flow_mat = $object;
1069      }
1070  
1071      /**
1072       * @param cc_assesment_material $object
1073       */
1074      public function set_material(cc_assesment_material $object) {
1075          $this->material = $object;
1076      }
1077  
1078      /**
1079       * @param cc_assesment_itemfeedback_solutiontype $object
1080       */
1081      public function set_solution(cc_assesment_itemfeedback_solutiontype $object) {
1082          $this->solution = $object;
1083      }
1084  
1085      public function set_hint($object) {
1086          $this->hint = $object;
1087      }
1088  
1089      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1090          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::itemfeedback);
1091          $this->generate_attributes($doc, $node, $namespace);
1092  
1093          if (!empty($this->flow_mat) && empty($this->material)) {
1094              $this->flow_mat->generate($doc, $node, $namespace);
1095          }
1096  
1097          if (!empty($this->material) && empty($this->flow_mat)) {
1098              $this->material->generate($doc, $node, $namespace);
1099          }
1100  
1101          if (!empty($this->solution)) {
1102              $this->solution->generate($doc, $node, $namespace);
1103          }
1104  
1105          if (!empty($this->itemfeedback)) {
1106              $this->itemfeedback->generate($doc, $node, $namespace);
1107          }
1108      }
1109  }
1110  
1111  class cc_assesment_section_item extends cc_assesment_section {
1112  
1113      /**
1114       * @var cc_assesment_itemmetadata
1115       */
1116      protected $itemmetadata = null;
1117      /**
1118       * @var cc_assesment_presentation
1119       */
1120      protected $presentation = null;
1121      protected $resprocessing = array();
1122      protected $itemfeedback = array();
1123  
1124      public function set_itemmetadata(cc_assesment_itemmetadata $object) {
1125          $this->itemmetadata = $object;
1126      }
1127  
1128      public function set_presentation(cc_assesment_presentation $object) {
1129          $this->presentation = $object;
1130      }
1131  
1132      public function add_resprocessing(cc_assesment_resprocessingtype $object) {
1133          $this->resprocessing[] = $object;
1134      }
1135  
1136      public function add_itemfeedback(cc_assesment_itemfeedbacktype $object) {
1137          $this->itemfeedback[] = $object;
1138      }
1139  
1140      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1141          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::item);
1142          $this->generate_attributes($doc, $node, $namespace);
1143  
1144          if (!empty($this->itemmetadata)) {
1145              $this->itemmetadata->generate($doc, $node, $namespace);
1146          }
1147  
1148          if (!empty($this->presentation)) {
1149              $this->presentation->generate($doc, $node, $namespace);
1150          }
1151  
1152          if (!empty($this->resprocessing)) {
1153              foreach ($this->resprocessing as $resprocessing) {
1154                  $resprocessing->generate($doc, $node, $namespace);
1155              }
1156          }
1157  
1158          if (!empty($this->itemfeedback)) {
1159              foreach ($this->itemfeedback as $itemfeedback) {
1160                  $itemfeedback->generate($doc, $node, $namespace);
1161              }
1162          }
1163      }
1164  }
1165  
1166  class cc_assesment_render_choicetype extends cc_question_metadata_base {
1167      /**
1168       * @var array
1169       */
1170      protected $materials = array();
1171  
1172      /**
1173       * @var array
1174       */
1175      protected $material_refs = array();
1176  
1177      /**
1178       * @var array
1179       */
1180      protected $response_labels = array();
1181      /**
1182       * @var array
1183       */
1184      protected $flow_labels = array();
1185  
1186      public function __construct() {
1187          $this->set_setting(cc_qti_tags::shuffle, cc_qti_values::No);
1188          $this->set_setting(cc_qti_tags::minnumber);
1189          $this->set_setting(cc_qti_tags::maxnumber);
1190      }
1191  
1192      public function add_material(cc_assesment_material $object) {
1193          $this->materials[] = $object;
1194      }
1195  
1196      public function add_material_ref(cc_assesment_response_matref $object) {
1197          $this->material_refs[] = $object;
1198      }
1199  
1200      public function add_response_label(cc_assesment_response_labeltype $object) {
1201          $this->response_labels[] = $object;
1202      }
1203  
1204      public function add_flow_label($object) {
1205          $this->flow_labels[] = $object;
1206      }
1207  
1208      public function enable_shuffle($value = true) {
1209          $this->enable_setting_yesno(cc_qti_tags::shuffle, $value);
1210      }
1211  
1212      public function set_limits($min = null, $max = null) {
1213          $this->set_setting(cc_qti_tags::minnumber, $min);
1214          $this->set_setting(cc_qti_tags::maxnumber, $max);
1215      }
1216  
1217      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1218          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::render_choice);
1219          $this->generate_attributes($doc, $node, $namespace);
1220  
1221          if (!empty($this->materials)) {
1222              foreach ($this->materials as $mattag) {
1223                  $mattag->generate($doc, $node, $namespace);
1224              }
1225          }
1226  
1227          if (!empty($this->material_refs)) {
1228              foreach ($this->material_refs as $matreftag) {
1229                  $matreftag->generate($doc, $node, $namespace);
1230              }
1231          }
1232  
1233          if (!empty($this->response_labels)) {
1234              foreach ($this->response_labels as $resplabtag) {
1235                  $resplabtag->generate($doc, $node, $namespace);
1236              }
1237          }
1238  
1239          if (!empty($this->flow_labels)) {
1240              foreach ($this->flow_labels as $flowlabtag) {
1241                  $flowlabtag->generate($doc, $node, $namespace);
1242              }
1243          }
1244      }
1245  
1246  }
1247  
1248  class cc_assesment_flow_mattype extends cc_question_metadata_base {
1249  
1250      /**
1251       * @var cc_assesment_material
1252       */
1253      protected $material = null;
1254      /**
1255       * @var cc_assesment_response_matref
1256       */
1257      protected $material_ref = null;
1258      /**
1259       * @var cc_assesment_flow_mattype
1260       */
1261      protected $flow_mat = null;
1262  
1263      public function __construct() {
1264          $this->set_setting(cc_qti_tags::t_class);
1265      }
1266  
1267      public function set_class($value) {
1268          $this->set_setting(cc_qti_tags::t_class, $value);
1269      }
1270  
1271      public function set_material(cc_assesment_material $object) {
1272          $this->material = $object;
1273      }
1274  
1275      public function set_material_ref(cc_assesment_response_matref $object) {
1276          $this->material_ref = $object;
1277      }
1278  
1279      public function set_flow_mat(cc_assesment_flow_mattype $object) {
1280          $this->flow_mat = $object;
1281      }
1282  
1283      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1284          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::flow_mat);
1285          $this->generate_attributes($doc, $node, $namespace);
1286  
1287          if (!empty($this->flow_mat)) {
1288              $this->flow_mat->generate($doc, $node, $namespace);
1289          }
1290  
1291          if (!empty($this->material)) {
1292              $this->material->generate($doc, $node, $namespace);
1293          }
1294  
1295          if (!empty($this->material_ref)) {
1296              $this->material_ref->generate($doc, $node, $namespace);
1297          }
1298      }
1299  }
1300  
1301  class cc_assesment_response_labeltype extends cc_question_metadata_base {
1302      /**
1303       * @var cc_assesment_material
1304       */
1305      protected $material = null;
1306  
1307      /**
1308       * @var cc_assesment_response_matref
1309       */
1310      protected $material_ref = null;
1311  
1312      /**
1313       * @var cc_assesment_flow_mattype
1314       */
1315      protected $flow_mat = null;
1316  
1317      public function __construct() {
1318          $this->set_setting(cc_qti_tags::ident, cc_helpers::uuidgen('I_'));
1319          $this->set_setting(cc_qti_tags::labelrefid);
1320          $this->set_setting(cc_qti_tags::rshuffle);
1321          $this->set_setting(cc_qti_tags::match_group);
1322          $this->set_setting(cc_qti_tags::match_max);
1323      }
1324  
1325      public function set_ident($value) {
1326          $this->set_setting(cc_qti_tags::ident, $value);
1327      }
1328  
1329      public function get_ident() {
1330          return $this->get_setting(cc_qti_tags::ident);
1331      }
1332  
1333      public function set_labelrefid($value) {
1334          $this->set_setting(cc_qti_tags::labelrefid, $value);
1335      }
1336  
1337      public function enable_rshuffle($value = true) {
1338          $this->enable_setting_yesno(cc_qti_tags::rshuffle, $value);
1339      }
1340  
1341      public function set_match_group($value) {
1342          $this->set_setting(cc_qti_tags::match_group, $value);
1343      }
1344  
1345      public function set_match_max($value) {
1346          $this->set_setting(cc_qti_tags::match_max, $value);
1347      }
1348  
1349      public function set_material(cc_assesment_material $object) {
1350          $this->material = $object;
1351      }
1352  
1353      public function set_material_ref(cc_assesment_response_matref $object) {
1354          $this->material_ref = $object;
1355      }
1356  
1357      public function set_flow_mat(cc_assesment_flow_mattype $object) {
1358          $this->flow_mat = $object;
1359      }
1360  
1361      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1362          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::response_label);
1363          $this->generate_attributes($doc, $node, $namespace);
1364  
1365          if (!empty($this->material)) {
1366              $this->material->generate($doc, $node, $namespace);
1367          }
1368  
1369          if (!empty($this->material_ref)) {
1370              $this->material_ref->generate($doc, $node, $namespace);
1371          }
1372  
1373          if (!empty($this->flow_mat)) {
1374              $this->flow_mat->generate($doc, $node, $namespace);
1375          }
1376      }
1377  }
1378  
1379  class cc_assesment_flow_labeltype extends cc_question_metadata_base {
1380      /**
1381       * @var cc_assesment_flow_labeltype
1382       */
1383      protected $flow_label = null;
1384      /**
1385       * @var cc_assesment_response_labeltype
1386       */
1387      protected $response_label = null;
1388  
1389      public function __construct() {
1390          $this->set_setting(cc_qti_tags::t_class);
1391      }
1392  
1393      public function set_class($value) {
1394          $this->set_setting(cc_qti_tags::t_class, $value);
1395      }
1396  
1397      public function set_flow_label(cc_assesment_flow_labeltype $object) {
1398          $this->flow_label = $object;
1399      }
1400  
1401      public function set_response_label(cc_assesment_response_labeltype $object) {
1402          $this->response_label = $object;
1403      }
1404  
1405      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1406          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::flow_label);
1407          $this->generate_attributes($doc, $node, $namespace);
1408  
1409          if (!empty($this->material)) {
1410              $this->material->generate($doc, $node, $namespace);
1411          }
1412  
1413          if (!empty($this->material_ref)) {
1414              $this->material_ref->generate($doc, $node, $namespace);
1415          }
1416  
1417          if (!empty($this->response_label)) {
1418              $this->response_label->generate($doc, $node, $namespace);
1419          }
1420  
1421          if (!empty($this->flow_label)) {
1422              $this->flow_label->generate($doc, $node, $namespace);
1423          }
1424      }
1425  
1426  }
1427  
1428  
1429  class cc_assesment_render_fibtype extends cc_question_metadata_base {
1430      /**
1431       * @var cc_assesment_material
1432       */
1433      protected $material = null;
1434  
1435      /**
1436       * @var cc_assesment_response_matref
1437       */
1438      protected $material_ref = null;
1439      /**
1440       * @var cc_assesment_response_labeltype
1441       */
1442      protected $response_label = null;
1443      /**
1444       *
1445       * Enter description here ...
1446       * @var unknown_type
1447       */
1448      protected $flow_label = null;
1449  
1450  
1451      public function __construct() {
1452          $this->set_setting(cc_qti_tags::encoding );
1453          $this->set_setting(cc_qti_tags::charset  );
1454          $this->set_setting(cc_qti_tags::rows     );
1455          $this->set_setting(cc_qti_tags::columns  );
1456          $this->set_setting(cc_qti_tags::maxchars );
1457          $this->set_setting(cc_qti_tags::minnumber);
1458          $this->set_setting(cc_qti_tags::maxnumber);
1459          $this->set_setting(cc_qti_tags::prompt, cc_qti_values::Box);
1460          $this->set_setting(cc_qti_tags::fibtype, cc_qti_values::String);
1461      }
1462  
1463      public function set_encoding($value) {
1464          $this->set_setting(cc_qti_tags::encoding, $value);
1465      }
1466      public function set_charset($value) {
1467          $this->set_setting(cc_qti_tags::charset, $value);
1468      }
1469  
1470      public function set_rows($value) {
1471          $this->set_setting(cc_qti_tags::rows, $value);
1472      }
1473  
1474      public function set_columns($value) {
1475          $this->set_setting(cc_qti_tags::columns, $value);
1476      }
1477  
1478      public function set_maxchars($value) {
1479          $this->set_setting(cc_qti_tags::columns, $value);
1480      }
1481  
1482      public function set_limits($min = null, $max = null) {
1483          $this->set_setting(cc_qti_tags::minnumber, $min);
1484          $this->set_setting(cc_qti_tags::maxnumber, $max);
1485      }
1486  
1487      public function set_prompt($value) {
1488          $this->set_setting(cc_qti_tags::prompt, $value);
1489      }
1490  
1491      public function set_fibtype($value) {
1492          $this->set_setting(cc_qti_tags::fibtype, $value);
1493      }
1494  
1495      public function set_material(cc_assesment_material $object) {
1496          $this->material = $object;
1497      }
1498  
1499      public function set_material_ref(cc_assesment_response_matref $object) {
1500          $this->material_ref = $object;
1501      }
1502  
1503      public function set_response_label(cc_assesment_response_labeltype $object) {
1504          $this->response_label = $object;
1505      }
1506  
1507      public function set_flow_label($object) {
1508          $this->flow_label = $object;
1509      }
1510  
1511      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1512          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::render_fib);
1513          $this->generate_attributes($doc, $node, $namespace);
1514  
1515          if (!empty($this->material) && empty($this->material_ref)) {
1516              $this->material->generate($doc, $node, $namespace);
1517          }
1518  
1519          if (!empty($this->material_ref) && empty($this->material)) {
1520              $this->material_ref->generate($doc, $node, $namespace);
1521          }
1522  
1523          if (!empty($this->response_label)) {
1524              $this->response_label->generate($doc, $node, $namespace);
1525          }
1526  
1527          if (!empty($this->flow_label)) {
1528              $this->flow_label->generate($doc, $node, $namespace);
1529          }
1530      }
1531  }
1532  
1533  class cc_response_lidtype extends cc_question_metadata_base {
1534      /**
1535       * @var string
1536       */
1537      protected $tagname = null;
1538      /**
1539       * @var cc_assesment_material
1540       */
1541      protected $material = null;
1542  
1543      /**
1544       * @var cc_assesment_response_matref
1545       */
1546      protected $material_ref = null;
1547  
1548      /**
1549       * @var cc_assesment_render_choicetype
1550       */
1551      protected $render_choice = null;
1552  
1553      /**
1554       * @var cc_assesment_render_fibtype
1555       */
1556      protected $render_fib = null;
1557  
1558      public function __construct() {
1559          $this->set_setting(cc_qti_tags::rcardinality, cc_qti_values::Single);
1560          $this->set_setting(cc_qti_tags::rtiming);
1561          $this->set_setting(cc_qti_tags::ident, cc_helpers::uuidgen('I_'));
1562          $this->tagname = cc_qti_tags::response_lid;
1563      }
1564  
1565      public function set_rcardinality($value) {
1566          $this->set_setting(cc_qti_tags::rcardinality, $value);
1567      }
1568  
1569      public function enable_rtiming($value = true) {
1570          $this->enable_setting_yesno(cc_qti_tags::rtiming, $value);
1571      }
1572  
1573      public function set_ident($value) {
1574          $this->set_setting(cc_qti_tags::ident, $value);
1575      }
1576  
1577      public function get_ident() {
1578          return $this->get_setting(cc_qti_tags::ident);
1579      }
1580  
1581      public function set_material_ref(cc_assesment_response_matref $object) {
1582          $this->material_ref = $object;
1583      }
1584  
1585      public function set_material(cc_assesment_material $object) {
1586          $this->material = $object;
1587      }
1588  
1589      public function set_render_choice(cc_assesment_render_choicetype $object) {
1590          $this->render_choice = $object;
1591      }
1592  
1593      public function set_render_fib(cc_assesment_render_fibtype $object) {
1594          $this->render_fib = $object;
1595      }
1596  
1597      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1598          $node = $doc->append_new_element_ns($item, $namespace, $this->tagname);
1599          $this->generate_attributes($doc, $node, $namespace);
1600  
1601          if (!empty($this->material) && empty($this->material_ref)) {
1602              $this->material->generate($doc, $node, $namespace);
1603          }
1604  
1605          if (!empty($this->material_ref) && empty($this->material)) {
1606              $this->material_ref->generate($doc, $node, $namespace);
1607          }
1608  
1609          if (!empty($this->render_choice) && empty($this->render_fib)) {
1610              $this->render_choice->generate($doc, $node, $namespace);
1611          }
1612  
1613          if (!empty($this->render_fib) && empty($this->render_choice)) {
1614              $this->render_fib->generate($doc, $node, $namespace);
1615          }
1616      }
1617  }
1618  
1619  class cc_assesment_response_strtype extends cc_response_lidtype {
1620      public function __construct() {
1621          $rtt = parent::__construct();
1622          $this->tagname = cc_qti_tags::response_str;
1623      }
1624  }
1625  
1626  class cc_assesment_flowtype extends cc_question_metadata_base {
1627      /**
1628       * @var cc_assesment_flowtype
1629       */
1630      protected $flow = null;
1631      /**
1632       * @var cc_assesment_material
1633       */
1634      protected $material = null;
1635      /**
1636       * @var cc_assesment_response_matref
1637       */
1638      protected $material_ref = null;
1639      /**
1640       * @var cc_response_lidtype
1641       */
1642      protected $response_lid = null;
1643      /**
1644       * @var cc_assesment_response_strtype
1645       */
1646      protected $response_str = null;
1647  
1648      public function __construct() {
1649          $this->set_setting(cc_qti_tags::t_class);
1650      }
1651  
1652      public function set_class($value) {
1653          $this->set_setting(cc_qti_tags::t_class, $value);
1654      }
1655  
1656      public function set_flow(cc_assesment_flowtype $object) {
1657          $this->flow = $object;
1658      }
1659  
1660      public function set_material(cc_assesment_material $object) {
1661          $this->material = $object;
1662      }
1663  
1664      public function set_material_ref(cc_assesment_response_matref $object) {
1665          $this->material_ref = $object;
1666      }
1667  
1668      public function set_response_lid(cc_response_lidtype $object) {
1669          $this->response_lid = $object;
1670      }
1671  
1672      public function set_response_str(cc_assesment_response_strtype $object) {
1673          $this->response_str = $object;
1674      }
1675  
1676      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1677          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::flow);
1678          $this->generate_attributes($doc, $node, $namespace);
1679  
1680          if (!empty($this->flow)) {
1681              $this->flow->generate($doc, $node, $namespace);
1682          }
1683  
1684          if (!empty($this->material)) {
1685              $this->material->generate($doc, $node, $namespace);
1686          }
1687  
1688          if (!empty($this->response_lid)) {
1689              $this->response_lid->generate($doc, $node, $namespace);
1690          }
1691  
1692          if (!empty($this->response_str)) {
1693              $this->response_str->generate($doc, $node, $namespace);
1694          }
1695      }
1696  }
1697  
1698  class cc_assesment_presentation extends cc_question_metadata_base {
1699      /**
1700       * @var cc_assesment_flowtype
1701       */
1702      protected $flow         = null;
1703      /**
1704       * @var cc_assesment_material
1705       */
1706      protected $material     = null;
1707      /**
1708       * @var cc_response_lidtype
1709       */
1710      protected $response_lid = null;
1711      /**
1712       * @var cc_assesment_response_strtype
1713       */
1714      protected $response_str = null;
1715  
1716      public function __construct() {
1717          $this->set_setting(cc_qti_tags::label);
1718          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml);
1719          $this->set_setting(cc_qti_tags::x0);
1720          $this->set_setting(cc_qti_tags::y0);
1721          $this->set_setting(cc_qti_tags::width);
1722          $this->set_setting(cc_qti_tags::height);
1723      }
1724  
1725      public function set_label($value) {
1726          $this->set_setting(cc_qti_tags::label, $value);
1727      }
1728  
1729      public function set_lang($value) {
1730          $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml, $value);
1731      }
1732  
1733      public function set_coor($x = null, $y = null) {
1734          $this->set_setting(cc_qti_tags::x0, $x);
1735          $this->set_setting(cc_qti_tags::y0, $y);
1736      }
1737  
1738      public function set_size($width = null, $height = null) {
1739          $this->set_setting(cc_qti_tags::width, $width);
1740          $this->set_setting(cc_qti_tags::height, $height);
1741      }
1742  
1743      public function set_flow(cc_assesment_flowtype $object) {
1744          $this->flow = $object;
1745      }
1746  
1747      public function set_material(cc_assesment_material $object) {
1748          $this->material = $object;
1749      }
1750  
1751      public function set_response_lid(cc_response_lidtype $object) {
1752          $this->response_lid = $object;
1753      }
1754  
1755      public function set_response_str(cc_assesment_response_strtype $object) {
1756          $this->response_str = $object;
1757      }
1758  
1759      public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
1760          $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::presentation);
1761          $this->generate_attributes($doc, $node, $namespace);
1762  
1763          if (!empty($this->flow)) {
1764              $this->flow->generate($doc, $node, $namespace);
1765          }
1766  
1767          if (!empty($this->material) && empty($this->flow)) {
1768              $this->material->generate($doc, $node, $namespace);
1769          }
1770  
1771          if (!empty($this->response_lid) && empty($this->flow)) {
1772              $this->response_lid->generate($doc, $node, $namespace);
1773          }
1774  
1775          if (!empty($this->response_str) && empty($this->flow)) {
1776              $this->response_str->generate($doc, $node, $namespace);
1777          }
1778      }
1779  }
1780  
1781  class assesment1_resurce_file extends general_cc_file {
1782      const deafultname = 'assesment.xml';
1783  
1784      protected $rootns   = 'xmlns';
1785      protected $rootname = cc_qti_tags::questestinterop;
1786      protected $ccnamespaces = array('xmlns' => 'http://www.imsglobal.org/xsd/ims_qtiasiv1p2',
1787                                      'xsi'   => 'http://www.w3.org/2001/XMLSchema-instance');
1788      protected $ccnsnames = array('xmlns' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_4/ims_qtiasiv1p2_localised.xsd');
1789  
1790      /**
1791       * @var string
1792       */
1793      protected $assessment_title = 'Untitled';
1794      /**
1795       * @var cc_assesment_metadata
1796       */
1797      protected $metadata = null;
1798      /**
1799       * @var cc_assesment_rubric_base
1800       */
1801      protected $rubric = null;
1802  
1803      /**
1804       * @var cc_assesment_presentation_material_base
1805       */
1806      protected $presentation_material = null;
1807  
1808      /**
1809       * @var cc_assesment_section
1810       */
1811      protected $section = null;
1812  
1813      public function set_metadata(cc_assesment_metadata $object) {
1814          $this->metadata = $object;
1815      }
1816  
1817      public function set_rubric(cc_assesment_rubric_base $object) {
1818          $this->rubric = $object;
1819      }
1820  
1821      public function set_presentation_material(cc_assesment_presentation_material_base $object) {
1822          $this->presentation_material = $object;
1823      }
1824  
1825      public function set_section(cc_assesment_section $object) {
1826          $this->section = $object;
1827      }
1828  
1829      public function set_title($value) {
1830          $this->assessment_title = self::safexml($value);
1831      }
1832  
1833      protected function on_save() {
1834          $rns = $this->ccnamespaces[$this->rootns];
1835          //root assesment element - required
1836          $assessment = $this->append_new_element_ns($this->root, $rns, cc_qti_tags::assessment);
1837          $this->append_new_attribute_ns($assessment, $rns, cc_qti_tags::ident, cc_helpers::uuidgen('QDB_'));
1838          $this->append_new_attribute_ns($assessment, $rns, cc_qti_tags::title, $this->assessment_title);
1839  
1840          //metadata - optional
1841          if (!empty($this->metadata)) {
1842              $this->metadata->generate($this, $assessment, $rns);
1843          }
1844  
1845          //rubric - optional
1846          if (!empty($this->rubric)) {
1847              $this->rubric->generate($this, $assessment, $rns);
1848          }
1849  
1850          //presentation_material - optional
1851          if (!empty($this->presentation_material)) {
1852              $this->presentation_material->generate($this, $assessment, $rns);
1853          }
1854  
1855          //section - required
1856          if (!empty($this->section)) {
1857              $this->section->generate($this, $assessment, $rns);
1858          }
1859  
1860          return true;
1861      }
1862  }
1863  
1864  
1865  class assesment11_resurce_file extends assesment1_resurce_file {
1866      protected $ccnsnames = array('xmlns' => 'http://www.imsglobal.org/profile/cc/ccv1p1/ccv1p1_qtiasiv1p2p1_v1p0.xsd');
1867  }
1868  
1869  abstract class cc_assesment_helper {
1870  
1871      public static $correct_fb = null;
1872      public static $incorrect_fb = null;
1873  
1874      public static function add_feedback($qitem, $content, $content_type, $ident) {
1875          if (empty($content)) {
1876              return false;
1877          }
1878          $qitemfeedback = new cc_assesment_itemfeedbacktype();
1879          $qitem->add_itemfeedback($qitemfeedback);
1880          if (!empty($ident)) {
1881              $qitemfeedback->set_ident($ident);
1882          }
1883          $qflowmat = new cc_assesment_flow_mattype();
1884          $qitemfeedback->set_flow_mat($qflowmat);
1885          $qmaterialfb = new cc_assesment_material();
1886          $qflowmat->set_material($qmaterialfb);
1887          $qmattext = new cc_assesment_mattext();
1888          $qmaterialfb->set_mattext($qmattext);
1889          $qmattext->set_content($content, $content_type);
1890          return true;
1891      }
1892  
1893      public static function add_answer($qresponse_choice, $content, $content_type) {
1894          $qresponse_label = new cc_assesment_response_labeltype();
1895          $qresponse_choice->add_response_label($qresponse_label);
1896          $qrespmaterial = new cc_assesment_material();
1897          $qresponse_label->set_material($qrespmaterial);
1898          $qrespmattext = new cc_assesment_mattext();
1899          $qrespmaterial->set_mattext($qrespmattext);
1900          $qrespmattext->set_content($content, $content_type);
1901          return $qresponse_label;
1902      }
1903  
1904      public static function add_response_condition($node, $title, $ident, $feedback_refid, $respident) {
1905          $qrespcondition = new cc_assesment_respconditiontype();
1906          $node->add_respcondition($qrespcondition);
1907          //define rest of the conditions
1908          $qconditionvar = new cc_assignment_conditionvar();
1909          $qrespcondition->set_conditionvar($qconditionvar);
1910          $qvarequal = new cc_assignment_conditionvar_varequaltype($ident);
1911          $qvarequal->enable_case();
1912          $qconditionvar->set_varequal($qvarequal);
1913          $qvarequal->set_respident($respident);
1914          $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
1915          $qrespcondition->add_displayfeedback($qdisplayfeedback);
1916          $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
1917          $qdisplayfeedback->set_linkrefid($feedback_refid);
1918      }
1919  
1920      public static function add_assesment_description($rt, $content, $contenttype) {
1921          if (empty($rt) || empty($content)) {
1922              return;
1923          }
1924          $activity_rubric = new cc_assesment_rubric_base();
1925          $rubric_material = new cc_assesment_material();
1926          $activity_rubric->set_material($rubric_material);
1927          $rubric_mattext = new cc_assesment_mattext();
1928          $rubric_material->set_label('Summary');
1929          $rubric_material->set_mattext($rubric_mattext);
1930          $rubric_mattext->set_content($content, $contenttype);
1931          $rt->set_rubric($activity_rubric);
1932      }
1933  
1934      public static function add_respcondition($node, $title, $feedback_refid, $grade_value = null, $continue = false ) {
1935          $qrespcondition = new cc_assesment_respconditiontype();
1936          $qrespcondition->set_title($title);
1937          $node->add_respcondition($qrespcondition);
1938          $qrespcondition->enable_continue($continue);
1939          //Add setvar if grade present
1940          if ($grade_value !== null) {
1941              $qsetvar = new cc_assignment_setvartype($grade_value);
1942              $qrespcondition->add_setvar($qsetvar);
1943          }
1944          //define the condition for success
1945          $qconditionvar = new cc_assignment_conditionvar();
1946          $qrespcondition->set_conditionvar($qconditionvar);
1947          $qother = new cc_assignment_conditionvar_othertype();
1948          $qconditionvar->set_other($qother);
1949          $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
1950          $qrespcondition->add_displayfeedback($qdisplayfeedback);
1951          $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
1952          $qdisplayfeedback->set_linkrefid($feedback_refid);
1953      }
1954  
1955      /**
1956       *
1957       * Enter description here ...
1958       * @param XMLGenericDocument $qdoc
1959       * @param unknown_type $manifest
1960       * @param cc_assesment_section $section
1961       * @param unknown_type $rootpath
1962       * @param unknown_type $contextid
1963       * @param unknown_type $outdir
1964       */
1965      public static function process_questions(&$qdoc, &$manifest, cc_assesment_section &$section, $rootpath, $contextid, $outdir) {
1966          $question_file = $rootpath . DIRECTORY_SEPARATOR . 'questions.xml';
1967          //load questions file
1968          $questions = new XMLGenericDocument();
1969          if (!$questions->load($question_file)) {
1970              return false;
1971          }
1972  
1973          pkg_resource_dependencies::instance()->reset();
1974          $questioncount = 0;
1975          $questionforexport = 0;
1976          $qids = $qdoc->nodeList('//question_instances//questionid');
1977          foreach ($qids as $qid) {
1978              /** @var DOMNode $qid */
1979              $value = $qid->nodeValue;
1980              if (intval($value) == 0) {
1981                  continue;
1982              }
1983              $question_node = $questions->node("//question_category/questions/question[@id='{$value}']");
1984              if (empty($question_node)) {
1985                  continue;
1986              }
1987              ++$questionforexport;
1988              //process question
1989              //question type
1990              $qtype = $questions->nodeValue('qtype', $question_node);
1991              $question_processor = null;
1992              switch ($qtype) {
1993                  case 'multichoice':
1994                      $single_correct_answer = (int)$questions->nodeValue('plugin_qtype_multichoice_question/multichoice/single', $question_node) > 0;
1995                      //TODO: Add checking for the nunmber of valid responses
1996                      //If question is marked as multi response but contains only one valid answer it
1997                      //should be handle as single response - classic multichoice
1998                      if ($single_correct_answer) {
1999                          $question_processor = new cc_assesment_question_multichoice($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2000                      } else {
2001                          $question_processor = new cc_assesment_question_multichoice_multiresponse($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2002                      }
2003                      $question_processor->generate();
2004                      ++$questioncount;
2005                  break;
2006                  case 'truefalse':
2007                      $question_processor = new cc_assesment_question_truefalse($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2008                      $question_processor->generate();
2009                      ++$questioncount;
2010                  break;
2011                  case 'essay':
2012                      $question_processor = new cc_assesment_question_essay($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2013                      $question_processor->generate();
2014                      ++$questioncount;
2015                  break;
2016                  case 'shortanswer':
2017                      //This is rather ambiguos since shortanswer supports partial pattern match
2018                      //In order to detect pattern match we need to scan for all the responses
2019                      //if at least one of the responses uses wildcards it should be treated as
2020                      //pattern match, otherwise it should be simple fill in the blank
2021                      if (self::has_matching_element($questions, $question_node)) {
2022                          //$question_processor = new cc_assesment_question_patternmatch($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2023                          $questionforexport--;
2024                      } else {
2025                          $question_processor = new cc_assesment_question_sfib($qdoc, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2026                      }
2027                      if (!empty($question_processor)) {
2028                          $question_processor->generate();
2029                          ++$questioncount;
2030                      }
2031                  break;
2032                  default:
2033                      ;
2034                  break;
2035              }
2036  
2037          }
2038  
2039          //return dependencies
2040          return ($questioncount == 0) || ($questioncount != $questionforexport)?
2041                 false: pkg_resource_dependencies::instance()->get_deps();
2042      }
2043  
2044      /**
2045       *
2046       * Checks if question has matching element
2047       * @param XMLGenericDocument $questions
2048       * @param object $question_node
2049       * @return bool
2050       */
2051      public static function has_matching_element(XMLGenericDocument $questions, $question_node) {
2052          $answers = $questions->nodeList('plugin_qtype_shortanswer_question//answertext', $question_node);
2053          $result = false;
2054          foreach ($answers as $answer) {
2055              $prepare = str_replace('\*', '\#', $answer->nodeValue);
2056              $result = (strpos($prepare, '*') !== false);
2057              if ($result) {
2058                  break;
2059              }
2060          }
2061          return $result;
2062      }
2063  
2064  }
2065  
2066  class cc_assesment_question_proc_base {
2067      /**
2068       * @var XMLGenericDocument
2069       */
2070      protected $quiz = null;
2071  
2072      /**
2073       * @var XMLGenericDocument
2074       */
2075      protected $questions = null;
2076  
2077      /**
2078      * @var cc_manifest
2079      */
2080      protected $manifest = null;
2081  
2082      /**
2083       * @var cc_assesment_section
2084       */
2085      protected $section = null;
2086  
2087      /**
2088       * @var DOMElement
2089       */
2090      protected $question_node = null;
2091  
2092      /**
2093       * @var string
2094       */
2095      protected $rootpath = null;
2096  
2097      /**
2098       * @var string
2099       */
2100      protected $contextid = null;
2101  
2102      /**
2103       * @var string
2104       */
2105      protected $outdir = null;
2106  
2107      /**
2108       * @var string
2109       */
2110      protected $qtype = null;
2111  
2112      /**
2113       * @var cc_question_metadata
2114       */
2115      protected $qmetadata = null;
2116  
2117      /**
2118       * @var cc_assesment_section_item
2119       */
2120      protected $qitem = null;
2121  
2122      /**
2123       * @var cc_assesment_presentation
2124       */
2125      protected $qpresentation = null;
2126  
2127      /**
2128       * @var cc_response_lidtype
2129       */
2130      protected $qresponse_lid = null;
2131  
2132      protected $qresprocessing = null;
2133  
2134      protected $correct_grade_value = null;
2135      protected $correct_answer_node_id = null;
2136      protected $correct_answer_ident = null;
2137  
2138      protected $total_grade_value = null;
2139  
2140      protected $answerlist = null;
2141  
2142      protected $general_feedback = null;
2143      protected $correct_feedbacks = array();
2144      protected $incorrect_feedbacks = array();
2145  
2146      /**
2147       * @param XMLGenericDocument $questions
2148       * @param cc_manifest $manifest
2149       * @param cc_assesment_section $section
2150       * @param DOMElement $question_node
2151       * @param string $rootpath
2152       * @param string $contextid
2153       * @param string $outdir
2154       */
2155      public function __construct(XMLGenericDocument &$quiz, XMLGenericDocument &$questions, cc_manifest &$manifest, cc_assesment_section &$section, &$question_node, $rootpath, $contextid, $outdir) {
2156          $this->quiz = $quiz;
2157          $this->questions = $questions;
2158          $this->manifest = $manifest;
2159          $this->section = $section;
2160          $this->question_node = $question_node;
2161          $this->rootpath = $rootpath;
2162          $this->contextid = $contextid;
2163          $this->outdir = $outdir;
2164  
2165          //
2166          $qitem = new cc_assesment_section_item();
2167          $this->section->add_item($qitem);
2168          $qitem->set_title($this->questions->nodeValue('name', $this->question_node));
2169          $this->qitem = $qitem;
2170      }
2171  
2172      public function on_generate_metadata() {
2173          if (empty($this->qmetadata)) {
2174              $this->qmetadata = new cc_question_metadata($this->qtype);
2175              //Get weighting value
2176              $weighting_value = (int)$this->questions->nodeValue('defaultmark', $this->question_node);
2177              if ($weighting_value > 1) {
2178                  $this->qmetadata->set_weighting($weighting_value);
2179              }
2180              //Get category
2181              $question_category = $this->questions->nodeValue('../../name', $this->question_node);
2182              if (!empty($question_category)) {
2183                  $this->qmetadata->set_category($question_category);
2184              }
2185              $rts = new cc_assesment_itemmetadata();
2186              $rts->add_metadata($this->qmetadata);
2187              $this->qitem->set_itemmetadata($rts);
2188          }
2189      }
2190  
2191      public function on_generate_presentation() {
2192          if (empty($this->qpresentation)) {
2193              $qpresentation = new cc_assesment_presentation();
2194              $this->qitem->set_presentation($qpresentation);
2195              //add question text
2196              $qmaterial = new cc_assesment_material();
2197              $qmattext = new cc_assesment_mattext();
2198              $question_text = $this->questions->nodeValue('questiontext', $this->question_node);
2199              $result = cc_helpers::process_linked_files( $question_text,
2200                                                          $this->manifest,
2201                                                          $this->rootpath,
2202                                                          $this->contextid,
2203                                                          $this->outdir);
2204              $qmattext->set_content($result[0], cc_qti_values::htmltype);
2205              $qmaterial->set_mattext($qmattext);
2206              $qpresentation->set_material($qmaterial);
2207              $this->qpresentation = $qpresentation;
2208              pkg_resource_dependencies::instance()->add($result[1]);
2209          }
2210      }
2211  
2212      public function on_generate_answers() {}
2213      public function on_generate_feedbacks() {
2214          $general_question_feedback = $this->questions->nodeValue('generalfeedback', $this->question_node);
2215          if (empty($general_question_feedback)) {
2216              return;
2217          }
2218          $name = 'general_fb';
2219          //Add question general feedback - the one that should be always displayed
2220          $result = cc_helpers::process_linked_files( $general_question_feedback,
2221                                                      $this->manifest,
2222                                                      $this->rootpath,
2223                                                      $this->contextid,
2224                                                      $this->outdir);
2225  
2226          cc_assesment_helper::add_feedback($this->qitem,
2227                                            $result[0],
2228                                            cc_qti_values::htmltype,
2229                                            $name);
2230          pkg_resource_dependencies::instance()->add($result[1]);
2231          $this->general_feedback = $name;
2232      }
2233  
2234      public function on_generate_response_processing() {
2235  
2236          $qresprocessing = new cc_assesment_resprocessingtype();
2237          $this->qitem->add_resprocessing($qresprocessing);
2238          $qdecvar = new cc_assesment_decvartype();
2239          $qresprocessing->set_decvar($qdecvar);
2240          //according to the Common Cartridge 1.1 Profile: Implementation document
2241          //this should always be set to 0, 100 in case of question type that is not essay
2242          $qdecvar->set_limits(0,100);
2243          $qdecvar->set_vartype(cc_qti_values::Decimal);
2244  
2245          $this->qresprocessing = $qresprocessing;
2246  
2247      }
2248  
2249      public function generate() {
2250          $this->on_generate_metadata();
2251  
2252          $this->on_generate_presentation();
2253  
2254          $this->on_generate_answers();
2255  
2256          $this->on_generate_feedbacks();
2257  
2258          $this->on_generate_response_processing();
2259      }
2260  
2261  }
2262  
2263  class cc_assesment_question_multichoice extends cc_assesment_question_proc_base {
2264      public function __construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir) {
2265          parent::__construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2266          $this->qtype = cc_qti_profiletype::multiple_choice;
2267  
2268          /**
2269           *
2270           * What is needed is a maximum grade value taken from the answer fraction
2271           * It is supposed to always be between 1 and 0 in decimal representation,
2272           * however that is not always the case so a change in test was needed
2273           * but since we support here one correct answer type
2274           * correct answer would always have to be 1
2275           */
2276          $correct_answer_node = $this->questions->node("plugin_qtype_multichoice_question/answers/answer[fraction > 0]", $this->question_node);
2277          if (empty($correct_answer_node)) {
2278              throw new RuntimeException('No correct answer!');
2279          }
2280          $this->correct_answer_node_id = $this->questions->nodeValue('@id', $correct_answer_node);
2281          $maximum_quiz_grade = (int)$this->quiz->nodeValue('/activity/quiz/grade');
2282          $this->total_grade_value = ($maximum_quiz_grade + 1).'.0000000';
2283      }
2284  
2285      public function on_generate_answers() {
2286          //add responses holder
2287          $qresponse_lid = new cc_response_lidtype();
2288          $this->qresponse_lid = $qresponse_lid;
2289          $this->qpresentation->set_response_lid($qresponse_lid);
2290          $qresponse_choice = new cc_assesment_render_choicetype();
2291          $qresponse_lid->set_render_choice($qresponse_choice);
2292          //Mark that question has only one correct answer -
2293          //which applies for multiple choice and yes/no questions
2294          $qresponse_lid->set_rcardinality(cc_qti_values::Single);
2295          //are we to shuffle the responses?
2296          $shuffle_answers = (int)$this->quiz->nodeValue('/activity/quiz/shuffleanswers') > 0;
2297          $qresponse_choice->enable_shuffle($shuffle_answers);
2298          $answerlist = array();
2299          $qa_responses = $this->questions->nodeList('plugin_qtype_multichoice_question/answers/answer', $this->question_node);
2300          foreach ($qa_responses as $node) {
2301              $answer_content = $this->questions->nodeValue('answertext', $node);
2302              $id = ((int)$this->questions->nodeValue('@id', $node) == $this->correct_answer_node_id);
2303              $result = cc_helpers::process_linked_files( $answer_content,
2304                                                          $this->manifest,
2305                                                          $this->rootpath,
2306                                                          $this->contextid,
2307                                                          $this->outdir);
2308              $qresponse_label = cc_assesment_helper::add_answer( $qresponse_choice,
2309                                                                  $result[0],
2310                                                                  cc_qti_values::htmltype);
2311              pkg_resource_dependencies::instance()->add($result[1]);
2312              $answer_ident = $qresponse_label->get_ident();
2313              $feedback_ident = $answer_ident.'_fb';
2314              if (empty($this->correct_answer_ident) && $id) {
2315                  $this->correct_answer_ident = $answer_ident;
2316              }
2317              //add answer specific feedbacks if not empty
2318              $content = $this->questions->nodeValue('feedback', $node);
2319              if (!empty($content)) {
2320                  $result = cc_helpers::process_linked_files( $content,
2321                                                              $this->manifest,
2322                                                              $this->rootpath,
2323                                                              $this->contextid,
2324                                                              $this->outdir);
2325  
2326  
2327                  cc_assesment_helper::add_feedback( $this->qitem,
2328                                                     $result[0],
2329                                                     cc_qti_values::htmltype,
2330                                                     $feedback_ident);
2331  
2332                  pkg_resource_dependencies::instance()->add($result[1]);
2333  
2334                  $answerlist[$answer_ident] = $feedback_ident;
2335              }
2336          }
2337  
2338          $this->answerlist = $answerlist;
2339  
2340      }
2341  
2342      public function on_generate_feedbacks() {
2343          parent::on_generate_feedbacks();
2344          //Question combined feedbacks
2345          $correct_question_fb = $this->questions->nodeValue('plugin_qtype_multichoice_question/multichoice/correctfeedback', $this->question_node);
2346          $incorrect_question_fb = $this->questions->nodeValue('plugin_qtype_multichoice_question/multichoice/incorrectfeedback', $this->question_node);
2347          $proc = array('correct_fb' => $correct_question_fb, 'general_incorrect_fb' => $incorrect_question_fb);
2348          foreach ($proc as $ident => $content) {
2349              if (empty($content)) {
2350                  continue;
2351              }
2352              $result = cc_helpers::process_linked_files( $content,
2353                                                          $this->manifest,
2354                                                          $this->rootpath,
2355                                                          $this->contextid,
2356                                                          $this->outdir);
2357  
2358              cc_assesment_helper::add_feedback( $this->qitem,
2359                                                 $result[0],
2360                                                 cc_qti_values::htmltype,
2361                                                 $ident);
2362  
2363              pkg_resource_dependencies::instance()->add($result[1]);
2364              if ($ident == 'correct_fb') {
2365                  $this->correct_feedbacks[] = $ident;
2366              } else {
2367                  $this->incorrect_feedbacks[] = $ident;
2368              }
2369          }
2370  
2371      }
2372  
2373      public function on_generate_response_processing() {
2374          parent::on_generate_response_processing();
2375  
2376          //respconditions
2377          /**
2378           * General unconditional feedback must be added as a first respcondition
2379           * without any condition and just displayfeedback (if exists)
2380           */
2381          if (!empty($this->general_feedback)) {
2382              $qrespcondition = new cc_assesment_respconditiontype();
2383              $qrespcondition->set_title('General feedback');
2384              $this->qresprocessing->add_respcondition($qrespcondition);
2385              $qrespcondition->enable_continue();
2386              //define the condition for success
2387              $qconditionvar = new cc_assignment_conditionvar();
2388              $qrespcondition->set_conditionvar($qconditionvar);
2389              $qother = new cc_assignment_conditionvar_othertype();
2390              $qconditionvar->set_other($qother);
2391              $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2392              $qrespcondition->add_displayfeedback($qdisplayfeedback);
2393              $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2394              $qdisplayfeedback->set_linkrefid('general_fb');
2395          }
2396  
2397          //success condition
2398          /**
2399           * For all question types outside of the Essay question, scoring is done in a
2400           * single <respcondition> with a continue flag set to No. The outcome is always
2401           * a variable named SCORE which value must be set to 100 in case of correct answer.
2402           * Partial scores (not 0 or 100) are not supported.
2403           */
2404          $qrespcondition = new cc_assesment_respconditiontype();
2405          $qrespcondition->set_title('Correct');
2406          $this->qresprocessing->add_respcondition($qrespcondition);
2407          $qrespcondition->enable_continue(false);
2408          $qsetvar = new cc_assignment_setvartype(100);
2409          $qrespcondition->add_setvar($qsetvar);
2410          //define the condition for success
2411          $qconditionvar = new cc_assignment_conditionvar();
2412          $qrespcondition->set_conditionvar($qconditionvar);
2413          $qvarequal = new cc_assignment_conditionvar_varequaltype($this->correct_answer_ident);
2414          $qconditionvar->set_varequal($qvarequal);
2415          $qvarequal->set_respident($this->qresponse_lid->get_ident());
2416  
2417          if (array_key_exists($this->correct_answer_ident, $this->answerlist)) {
2418              $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2419              $qrespcondition->add_displayfeedback($qdisplayfeedback);
2420              $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2421              $qdisplayfeedback->set_linkrefid($this->answerlist[$this->correct_answer_ident]);
2422          }
2423  
2424          foreach ($this->correct_feedbacks as $ident) {
2425              $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2426              $qrespcondition->add_displayfeedback($qdisplayfeedback);
2427              $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2428              $qdisplayfeedback->set_linkrefid($ident);
2429          }
2430  
2431          //rest of the conditions
2432          foreach ($this->answerlist as $ident => $refid) {
2433              if ($ident == $this->correct_answer_ident) {
2434                  continue;
2435              }
2436  
2437              $qrespcondition = new cc_assesment_respconditiontype();
2438              $this->qresprocessing->add_respcondition($qrespcondition);
2439              $qsetvar = new cc_assignment_setvartype(0);
2440              $qrespcondition->add_setvar($qsetvar);
2441              //define the condition for fail
2442              $qconditionvar = new cc_assignment_conditionvar();
2443              $qrespcondition->set_conditionvar($qconditionvar);
2444              $qvarequal = new cc_assignment_conditionvar_varequaltype($ident);
2445              $qconditionvar->set_varequal($qvarequal);
2446              $qvarequal->set_respident($this->qresponse_lid->get_ident());
2447  
2448              $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2449              $qrespcondition->add_displayfeedback($qdisplayfeedback);
2450              $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2451              $qdisplayfeedback->set_linkrefid($refid);
2452  
2453              foreach ($this->incorrect_feedbacks as $ident) {
2454                  $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2455                  $qrespcondition->add_displayfeedback($qdisplayfeedback);
2456                  $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2457                  $qdisplayfeedback->set_linkrefid($ident);
2458              }
2459          }
2460      }
2461  }
2462  
2463  class cc_assesment_question_multichoice_multiresponse extends cc_assesment_question_proc_base {
2464      /**
2465       * @var DOMNodeList
2466       */
2467      protected $correct_answers = null;
2468  
2469      public function __construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir) {
2470          parent::__construct($quiz, $questions, $manifest, $section, $question_node, $rootpath, $contextid, $outdir);
2471          $this->qtype = cc_qti_profiletype::multiple_response;
2472  
2473          $correct_answer_nodes = $this->questions->nodeList("plugin_qtype_multichoice_question/answers/answer[fraction > 0]", $this->question_node);
2474          if ($correct_answer_nodes->length == 0) {
2475              throw new RuntimeException('No correct answer!');
2476          }
2477          $this->correct_answers = $correct_answer_nodes;
2478          //$this->correct_answer_node_id = $this->questions->nodeValue('@id', $correct_answer_node);
2479          $maximum_quiz_grade = (int)$this->quiz->nodeValue('/activity/quiz/grade');
2480          $this->total_grade_value = ($maximum_quiz_grade + 1).'.0000000';
2481      }
2482  
2483      public function on_generate_answers() {
2484          //add responses holder
2485          $qresponse_lid = new cc_response_lidtype();
2486          $this->qresponse_lid = $qresponse_lid;
2487          $this->qpresentation->set_response_lid($qresponse_lid);
2488          $qresponse_choice = new cc_assesment_render_choicetype();
2489          $qresponse_lid->set_render_choice($qresponse_choice);
2490          //Mark that question has more than one correct answer
2491          $qresponse_lid->set_rcardinality(cc_qti_values::Multiple);
2492          //are we to shuffle the responses?
2493          $shuffle_answers = (int)$this->quiz->nodeValue('/activity/quiz/shuffleanswers') > 0;
2494          $qresponse_choice->enable_shuffle($shuffle_answers);
2495          $answerlist = array();
2496          $qa_responses = $this->questions->nodeList('plugin_qtype_multichoice_question/answers/answer', $this->question_node);
2497          foreach ($qa_responses as $node) {
2498              $answer_content = $this->questions->nodeValue('answertext', $node);
2499              $answer_grade_fraction = (float)$this->questions->nodeValue('fraction', $node);
2500              $result = cc_helpers::process_linked_files( $answer_content,
2501                                                          $this->manifest,
2502                                                          $this->rootpath,
2503                                                          $this->contextid,
2504                                                          $this->outdir);
2505              $qresponse_label = cc_assesment_helper::add_answer( $qresponse_choice,
2506                                                                  $result[0],
2507                                                                  cc_qti_values::htmltype);
2508              pkg_resource_dependencies::instance()->add($result[1]);
2509              $answer_ident = $qresponse_label->get_ident();
2510              $feedback_ident = $answer_ident.'_fb';
2511              //add answer specific feedbacks if not empty
2512              $content = $this->questions->nodeValue('feedback', $node);
2513              if (!empty($content)) {
2514                  $result = cc_helpers::process_linked_files( $content,
2515                                                              $this->manifest,
2516                                                              $this->rootpath,
2517                                                              $this->contextid,
2518                                                              $this->outdir);
2519  
2520  
2521                  cc_assesment_helper::add_feedback( $this->qitem,
2522                                                      $result[0],
2523                                                      cc_qti_values::htmltype,
2524                                                      $feedback_ident);
2525  
2526                  pkg_resource_dependencies::instance()->add($result[1]);
2527  
2528              }
2529              $answerlist[$answer_ident] = array($feedback_ident, ($answer_grade_fraction > 0));
2530          }
2531  
2532          $this->answerlist = $answerlist;
2533  
2534      }
2535  
2536      public function on_generate_feedbacks() {
2537          parent::on_generate_feedbacks();
2538          //Question combined feedbacks
2539          $correct_question_fb = $this->questions->nodeValue('plugin_qtype_multichoice_question/multichoice/correctfeedback', $this->question_node);
2540          $incorrect_question_fb = $this->questions->nodeValue('plugin_qtype_multichoice_question/multichoice/incorrectfeedback', $this->question_node);
2541          if (empty($correct_question_fb)) {
2542              //Hardcode some text for now
2543              $correct_question_fb = 'Well done!';
2544          }
2545          if (empty($incorrect_question_fb)) {
2546              //Hardcode some text for now
2547              $incorrect_question_fb = 'Better luck next time!';
2548          }
2549  
2550          $proc = array('correct_fb' => $correct_question_fb, 'incorrect_fb' => $incorrect_question_fb);
2551          foreach ($proc as $ident => $content) {
2552              if (empty($content)) {
2553                  continue;
2554              }
2555              $result = cc_helpers::process_linked_files( $content,
2556                                                          $this->manifest,
2557                                                          $this->rootpath,
2558                                                          $this->contextid,
2559                                                          $this->outdir);
2560  
2561              cc_assesment_helper::add_feedback( $this->qitem,
2562                                                  $result[0],
2563                                                  cc_qti_values::htmltype,
2564                                                  $ident);
2565  
2566              pkg_resource_dependencies::instance()->add($result[1]);
2567              if ($ident == 'correct_fb') {
2568                  $this->correct_feedbacks[$ident] = $ident;
2569              } else {
2570                  $this->incorrect_feedbacks[$ident] = $ident;
2571              }
2572          }
2573  
2574      }
2575  
2576      public function on_generate_response_processing() {
2577          parent::on_generate_response_processing();
2578  
2579          //respconditions
2580          /**
2581          * General unconditional feedback must be added as a first respcondition
2582          * without any condition and just displayfeedback (if exists)
2583          */
2584          cc_assesment_helper::add_respcondition( $this->qresprocessing,
2585                                                  'General feedback',
2586                                                  $this->general_feedback,
2587                                                  null,
2588                                                  true
2589                                                 );
2590  
2591          //success condition
2592          /**
2593          * For all question types outside of the Essay question, scoring is done in a
2594          * single <respcondition> with a continue flag set to No. The outcome is always
2595          * a variable named SCORE which value must be set to 100 in case of correct answer.
2596          * Partial scores (not 0 or 100) are not supported.
2597          */
2598          $qrespcondition = new cc_assesment_respconditiontype();
2599          $qrespcondition->set_title('Correct');
2600          $this->qresprocessing->add_respcondition($qrespcondition);
2601          $qrespcondition->enable_continue(false);
2602          $qsetvar = new cc_assignment_setvartype(100);
2603          $qrespcondition->add_setvar($qsetvar);
2604          //define the condition for success
2605          $qconditionvar = new cc_assignment_conditionvar();
2606          $qrespcondition->set_conditionvar($qconditionvar);
2607          //create root and condition
2608          $qandcondition = new cc_assignment_conditionvar_andtype();
2609          $qconditionvar->set_and($qandcondition);
2610          foreach ($this->answerlist as $ident => $refid) {
2611              $qvarequal = new cc_assignment_conditionvar_varequaltype($ident);
2612              $qvarequal->enable_case();
2613              if ($refid[1]) {
2614                  $qandcondition->set_varequal($qvarequal);
2615              } else {
2616                  $qandcondition->set_not($qvarequal);
2617              }
2618              $qvarequal->set_respident($this->qresponse_lid->get_ident());
2619          }
2620  
2621          $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2622          $qrespcondition->add_displayfeedback($qdisplayfeedback);
2623          $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2624          //TODO: this needs to be fixed
2625          reset($this->correct_feedbacks);
2626          $ident = key($this->correct_feedbacks);
2627          $qdisplayfeedback->set_linkrefid($ident);
2628  
2629  
2630          //rest of the conditions
2631          foreach ($this->answerlist as $ident => $refid) {
2632              cc_assesment_helper::add_response_condition( $this->qresprocessing,
2633                                                           'Incorrect feedback',
2634                                                           $refid[0],
2635                                                           $this->general_feedback,
2636                                                           $this->qresponse_lid->get_ident()
2637                                                         );
2638          }
2639  
2640          //Final element for incorrect feedback
2641          reset($this->incorrect_feedbacks);
2642          $ident = key($this->incorrect_feedbacks);
2643          cc_assesment_helper::add_respcondition( $this->qresprocessing,
2644                                                  'Incorrect feedback',
2645                                                  $ident,
2646                                                  0
2647                                                );
2648  
2649      }
2650  
2651  }