Merge branch 'MDL-56498-master' of git://github.com/mickhawkins/moodle
[moodle.git] / backup / cc / cc_lib / cc_asssesment.php
blobbbc5650911bff032a6ffd1e16dce9c4722be95ec
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.
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
22 defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
24 require_once('cc_utils.php');
25 require_once('cc_general.php');
27 abstract class cc_xml_namespace {
28 const xml = 'http://www.w3.org/XML/1998/namespace';
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';
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';
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';
58 /**
60 * validates a profile value
61 * @param string $value
62 * @return boolean
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
72 return in_array($value, $verification_values);
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';
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';
190 class cc_question_metadata_base {
192 * @var array
194 protected $metadata = array();
197 * @param string $setting
198 * @param mixed $value
200 protected function set_setting($setting, $value = null) {
201 $this->metadata[$setting] = $value;
205 * @param string $setting
206 * @return mixed
208 protected function get_setting($setting) {
209 $result = null;
210 if (array_key_exists($setting, $this->metadata)) {
211 $result = $this->metadata[$setting];
213 return $result;
217 * @param string $setting
218 * @param string $namespace
219 * @param string $value
221 protected function set_setting_wns($setting, $namespace, $value = null) {
222 $this->metadata[$setting] = array($namespace => $value);
226 * @param string $setting
227 * @param boolean $value
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);
235 * @param XMLGenericDocument $doc
236 * @param DOMNode $item
237 * @param string $namespace
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);
256 * @param XMLGenericDocument $doc
257 * @param DOMNode $item
258 * @param string $namespace
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);
272 class cc_question_metadata extends cc_question_metadata_base {
274 public function set_category($value) {
275 $this->set_setting(cc_qti_metadata::cc_question_category, $value);
278 public function set_weighting($value) {
279 $this->set_setting(cc_qti_metadata::cc_weighting, $value);
282 public function enable_scoringpermitted($value = true) {
283 $this->enable_setting_yesno(cc_qti_metadata::qmd_scoringpermitted, $value);
286 public function enable_computerscored($value = true) {
287 $this->enable_setting_yesno(cc_qti_metadata::qmd_computerscored, $value);
292 * Constructs metadata
293 * @param string $profile
294 * @throws InvalidArgumentException
296 public function __construct($profile) {
297 if (!cc_qti_profiletype::valid($profile)) {
298 throw new InvalidArgumentException('Invalid profile type!');
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 );
309 class cc_assesment_metadata extends cc_question_metadata_base {
311 public function enable_hints($value = true) {
312 $this->enable_setting_yesno(cc_qti_metadata::qmd_hintspermitted, $value);
315 public function enable_solutions($value = true) {
316 $this->enable_setting_yesno(cc_qti_metadata::qmd_solutionspermitted, $value);
319 public function enable_latesubmissions($value = true) {
320 $this->enable_setting_yesno(cc_qti_metadata::cc_allow_late_submission, $value);
323 public function enable_feedback($value = true) {
324 $this->enable_setting_yesno(cc_qti_metadata::qmd_feedbackpermitted, $value);
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!');
333 $this->set_setting(cc_qti_metadata::qmd_timelimit, $value);
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');
342 $this->set_setting(cc_qti_metadata::cc_maxattempts, $value);
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 );
361 class cc_assesment_mattext extends cc_question_metadata_base {
362 protected $value = null;
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;
378 public function set_label($value) {
379 $this->set_setting(cc_qti_tags::label, $value);
382 public function set_uri($value) {
383 $this->set_setting(cc_qti_tags::uri, $value);
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);
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);
396 public function set_lang($lang = null) {
397 $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml, $lang);
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);
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);
412 class cc_assesment_matref {
413 protected $linkref = null;
415 public function __construct($linkref) {
416 $this->linkref = $linkref;
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);
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);
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);
438 abstract class cc_assesment_material_base extends cc_question_metadata_base {
440 * @var mixed
442 protected $mattag = null;
443 protected $tagname = null;
445 protected function set_tag_value($object) {
446 $this->mattag = $object;
449 public function set_mattext(cc_assesment_mattext $object) {
450 $this->set_tag_value($object);
453 public function set_matref(cc_assesment_matref $object) {
454 $this->set_tag_value($object);
457 public function set_matbreak(cc_assesment_matbreak $object) {
458 $this->set_tag_value($object);
461 public function set_lang($value) {
462 $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml, $value);
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);
471 return $material;
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;
482 class cc_assesment_material extends cc_assesment_material_base {
484 protected $altmaterial = null;
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;
492 public function set_label($value) {
493 $this->set_setting(cc_qti_tags::label, $value);
496 public function set_altmaterial(cc_assesment_altmaterial $object) {
497 $this->altmaterial = $object;
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);
508 class cc_assesment_rubric_base extends cc_question_metadata_base {
510 protected $material = null;
512 public function set_material($object) {
513 $this->material = $object;
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);
524 class cc_assesment_presentation_material_base extends cc_question_metadata_base {
525 protected $flowmats = array();
527 public function add_flow_mat($object) {
528 $this->flowmats[] = $object;
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);
541 class cc_assesment_flow_mat_base extends cc_question_metadata_base {
543 protected $mattag = null;
545 protected function set_tag_value($object) {
546 $this->mattag = $object;
549 public function set_flow_mat(cc_assesment_flow_mat_base $object) {
550 $this->set_tag_value($object);
553 public function set_material(cc_assesment_material $object) {
554 $this->set_tag_value($object);
557 public function set_material_ref(cc_assesment_matref $object) {
558 $this->set_tag_value($object);
561 public function __construct($value = null) {
562 $this->set_setting(cc_qti_tags::t_class);
565 public function set_class($value) {
566 $this->set_setting(cc_qti_tags::t_class, $value);
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);
579 class cc_assesment_section extends cc_question_metadata_base {
581 * @var array
583 protected $items = array();
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);
591 public function set_ident($value) {
592 $this->set_setting(cc_qti_tags::ident, $value);
595 public function set_title($value) {
596 $this->set_setting(cc_qti_tags::title, $value);
599 public function set_lang($value) {
600 $this->set_setting_wns(cc_qti_tags::xml_lang, cc_xml_namespace::xml, $value);
603 public function add_item(cc_assesment_section_item $object) {
604 $this->items[] = $object;
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);
618 class cc_assesment_itemmetadata extends cc_question_metadata_base {
619 public function add_metadata($object) {
620 $this->metadata[] = $object;
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);
633 class cc_assesment_decvartype extends cc_question_metadata_base {
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);
642 public function set_vartype($value) {
643 $this->set_setting(cc_qti_tags::vartype, $value);
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);
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);
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);
664 class cc_assignment_conditionvar_varequaltype extends cc_question_metadata_base {
665 protected $tagname = null;
666 protected $answerid = null;
668 public function __construct($value = null) {
669 if (is_null($value)) {
670 throw new InvalidArgumentException('Must not pass null!');
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;
678 public function set_respident($value) {
679 $this->set_setting(cc_qti_tags::respident, $value);
682 public function enable_case($value = true) {
683 $this->enable_setting_yesno(cc_qti_tags::case_, $value);
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);
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;
700 class cc_assignment_conditionvar_andtype extends cc_question_metadata_base {
701 protected $nots = array();
702 protected $varequals = array();
704 public function set_not(cc_assignment_conditionvar_varequaltype $object) {
705 $this->nots[] = $object;
708 public function set_varequal(cc_assignment_conditionvar_varequaltype $object) {
709 $this->varequals[] = $object;
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);
721 if (!empty($this->varequals)) {
722 foreach ($this->varequals as $varequal) {
723 $varequal->generate($doc, $node, $namespace);
729 class cc_assignment_conditionvar extends cc_question_metadata_base {
732 * @var cc_assignment_conditionvar_andtype
734 protected $and = null;
736 * @var cc_assignment_conditionvar_othertype
738 protected $other = null;
740 * @var array
742 protected $varequal = array();
744 * @var cc_assignment_conditionvar_varsubstringtype
746 protected $varsubstring = null;
748 public function set_and(cc_assignment_conditionvar_andtype $object) {
749 $this->and = $object;
752 public function set_other(cc_assignment_conditionvar_othertype $object) {
753 $this->other = $object;
756 public function set_varequal(cc_assignment_conditionvar_varequaltype $object) {
757 $this->varequal[] = $object;
760 public function set_varsubstring(cc_assignment_conditionvar_varsubstringtype $object) {
761 $this->varsubstring = $object;
764 public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
765 $node = $doc->append_new_element_ns($item, $namespace, cc_qti_tags::conditionvar);
767 if (!empty($this->and)) {
768 $this->and->generate($doc, $node, $namespace);
771 if (!empty($this->other)) {
772 $this->other->generate($doc, $node, $namespace);
775 if (!empty($this->varequal)) {
776 foreach ($this->varequal as $varequal) {
777 $varequal->generate($doc, $node, $namespace);
781 if (!empty($this->varsubstring)) {
782 $this->varsubstring->generate($doc, $node, $namespace);
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);
793 public function set_feedbacktype($value) {
794 $this->set_setting(cc_qti_tags::feedbacktype, $value);
797 public function set_linkrefid($value) {
798 $this->set_setting(cc_qti_tags::linkrefid, $value);
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);
808 class cc_assignment_setvartype extends cc_question_metadata_base {
810 * @var integer
812 protected $tagvalue = null;
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;
820 public function set_varname($value) {
821 $this->set_setting(cc_qti_tags::varname, $value);
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);
830 class cc_assesment_respconditiontype extends cc_question_metadata_base {
832 * @var cc_assignment_conditionvar
834 protected $conditionvar = null;
835 protected $setvar = array();
836 protected $displayfeedback = array();
838 public function __construct() {
839 $this->set_setting(cc_qti_tags::title);
840 $this->set_setting(cc_qti_tags::continue_, cc_qti_values::No);
843 public function set_title($value) {
844 $this->set_setting(cc_qti_tags::title, $value);
847 public function enable_continue($value = true) {
848 $this->enable_setting_yesno(cc_qti_tags::continue_, $value);
851 public function set_conditionvar(cc_assignment_conditionvar $object) {
852 $this->conditionvar = $object;
855 public function add_setvar(cc_assignment_setvartype $object) {
856 $this->setvar[] = $object;
859 public function add_displayfeedback(cc_assignment_displayfeedbacktype $object) {
860 $this->displayfeedback[] = $object;
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);
867 if (!empty($this->conditionvar)) {
868 $this->conditionvar->generate($doc, $node, $namespace);
871 if (!empty($this->setvar)) {
872 foreach ($this->setvar as $setvar) {
873 $setvar->generate($doc, $node, $namespace);
877 if (!empty($this->displayfeedback)) {
878 foreach ($this->displayfeedback as $displayfeedback) {
879 $displayfeedback->generate($doc, $node, $namespace);
886 class cc_assesment_resprocessingtype extends cc_question_metadata_base {
888 * @var cc_assesment_decvartype
890 protected $decvar = null;
892 * @var array
894 protected $respconditions = array();
896 public function set_decvar(cc_assesment_decvartype $object) {
897 $this->decvar = $object;
900 public function add_respcondition(cc_assesment_respconditiontype $object) {
901 $this->respconditions[] = $object;
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);
910 if (!empty($this->respconditions)) {
911 foreach ($this->respconditions as $rcond) {
912 $rcond->generate($doc, $node, $namespace);
919 class cc_assesment_itemfeedback_shintmaterial_base extends cc_question_metadata_base {
921 * @var string
923 protected $tagname = null;
925 * @var array
927 protected $flow_mats = array();
929 * @var array
931 protected $materials = array();
934 * @param cc_assesment_flow_mattype $object
936 public function add_flow_mat(cc_assesment_flow_mattype $object) {
937 $this->flow_mats[] = $object;
941 * @param cc_assesment_material $object
943 public function add_material(cc_assesment_material $object) {
944 $this->materials[] = $object;
947 public function generate(XMLGenericDocument &$doc, DOMNode &$item, $namespace) {
948 $node = $doc->append_new_element_ns($item, $namespace, $this->tagname);
950 if (!empty($this->flow_mats)) {
951 foreach ($this->flow_mats as $flow_mat) {
952 $flow_mat->generate($doc, $node, $namespace);
956 if (!empty($this->materials)) {
957 foreach ($this->materials as $material) {
958 $material->generate($doc, $node, $namespace);
964 class cc_assesment_itemfeedback_hintmaterial extends cc_assesment_itemfeedback_shintmaterial_base {
965 public function __construct() {
966 $this->tagname = cc_qti_tags::hint;
970 class cc_assesment_itemfeedback_solutionmaterial extends cc_assesment_itemfeedback_shintmaterial_base {
971 public function __construct() {
972 $this->tagname = cc_qti_tags::solutionmaterial;
976 class cc_assesment_itemfeedback_shintype_base extends cc_question_metadata_base {
978 * @var string
980 protected $tagname = null;
982 * @var array
984 protected $items = array();
986 public function __construct() {
987 $this->set_setting(cc_qti_tags::feedbackstyle, cc_qti_values::Complete);
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);
994 if (!empty($this->items)) {
995 foreach ($this->items as $telement) {
996 $telement->generate($doc, $node, $namespace);
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;
1009 * @param cc_assesment_itemfeedback_solutionmaterial $object
1011 public function add_solutionmaterial(cc_assesment_itemfeedback_solutionmaterial $object) {
1012 $this->items[] = $object;
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;
1023 * @param cc_assesment_itemfeedback_hintmaterial $object
1025 public function add_hintmaterial(cc_assesment_itemfeedback_hintmaterial $object) {
1026 $this->items[] = $object;
1030 class cc_assesment_itemfeedbacktype extends cc_question_metadata_base {
1032 * @var cc_assesment_flow_mattype
1034 protected $flow_mat = null;
1036 * @var cc_assesment_material
1038 protected $material = null;
1040 * @var cc_assesment_itemfeedback_solutiontype
1042 protected $solution = null;
1043 protected $hint = null;
1045 public function __construct() {
1046 $this->set_setting(cc_qti_tags::ident, cc_helpers::uuidgen('I_'));
1047 $this->set_setting(cc_qti_tags::title);
1051 * @param string $value
1053 public function set_ident($value) {
1054 $this->set_setting(cc_qti_tags::ident, $value);
1058 * @param string $value
1060 public function set_title($value) {
1061 $this->set_setting(cc_qti_tags::title, $value);
1065 * @param cc_assesment_flow_mattype $object
1067 public function set_flow_mat(cc_assesment_flow_mattype $object) {
1068 $this->flow_mat = $object;
1072 * @param cc_assesment_material $object
1074 public function set_material(cc_assesment_material $object) {
1075 $this->material = $object;
1079 * @param cc_assesment_itemfeedback_solutiontype $object
1081 public function set_solution(cc_assesment_itemfeedback_solutiontype $object) {
1082 $this->solution = $object;
1085 public function set_hint($object) {
1086 $this->hint = $object;
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);
1093 if (!empty($this->flow_mat) && empty($this->material)) {
1094 $this->flow_mat->generate($doc, $node, $namespace);
1097 if (!empty($this->material) && empty($this->flow_mat)) {
1098 $this->material->generate($doc, $node, $namespace);
1101 if (!empty($this->solution)) {
1102 $this->solution->generate($doc, $node, $namespace);
1105 if (!empty($this->itemfeedback)) {
1106 $this->itemfeedback->generate($doc, $node, $namespace);
1111 class cc_assesment_section_item extends cc_assesment_section {
1114 * @var cc_assesment_itemmetadata
1116 protected $itemmetadata = null;
1118 * @var cc_assesment_presentation
1120 protected $presentation = null;
1121 protected $resprocessing = array();
1122 protected $itemfeedback = array();
1124 public function set_itemmetadata(cc_assesment_itemmetadata $object) {
1125 $this->itemmetadata = $object;
1128 public function set_presentation(cc_assesment_presentation $object) {
1129 $this->presentation = $object;
1132 public function add_resprocessing(cc_assesment_resprocessingtype $object) {
1133 $this->resprocessing[] = $object;
1136 public function add_itemfeedback(cc_assesment_itemfeedbacktype $object) {
1137 $this->itemfeedback[] = $object;
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);
1144 if (!empty($this->itemmetadata)) {
1145 $this->itemmetadata->generate($doc, $node, $namespace);
1148 if (!empty($this->presentation)) {
1149 $this->presentation->generate($doc, $node, $namespace);
1152 if (!empty($this->resprocessing)) {
1153 foreach ($this->resprocessing as $resprocessing) {
1154 $resprocessing->generate($doc, $node, $namespace);
1158 if (!empty($this->itemfeedback)) {
1159 foreach ($this->itemfeedback as $itemfeedback) {
1160 $itemfeedback->generate($doc, $node, $namespace);
1166 class cc_assesment_render_choicetype extends cc_question_metadata_base {
1168 * @var array
1170 protected $materials = array();
1173 * @var array
1175 protected $material_refs = array();
1178 * @var array
1180 protected $response_labels = array();
1182 * @var array
1184 protected $flow_labels = array();
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);
1192 public function add_material(cc_assesment_material $object) {
1193 $this->materials[] = $object;
1196 public function add_material_ref(cc_assesment_response_matref $object) {
1197 $this->material_refs[] = $object;
1200 public function add_response_label(cc_assesment_response_labeltype $object) {
1201 $this->response_labels[] = $object;
1204 public function add_flow_label($object) {
1205 $this->flow_labels[] = $object;
1208 public function enable_shuffle($value = true) {
1209 $this->enable_setting_yesno(cc_qti_tags::shuffle, $value);
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);
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);
1221 if (!empty($this->materials)) {
1222 foreach ($this->materials as $mattag) {
1223 $mattag->generate($doc, $node, $namespace);
1227 if (!empty($this->material_refs)) {
1228 foreach ($this->material_refs as $matreftag) {
1229 $matreftag->generate($doc, $node, $namespace);
1233 if (!empty($this->response_labels)) {
1234 foreach ($this->response_labels as $resplabtag) {
1235 $resplabtag->generate($doc, $node, $namespace);
1239 if (!empty($this->flow_labels)) {
1240 foreach ($this->flow_labels as $flowlabtag) {
1241 $flowlabtag->generate($doc, $node, $namespace);
1248 class cc_assesment_flow_mattype extends cc_question_metadata_base {
1251 * @var cc_assesment_material
1253 protected $material = null;
1255 * @var cc_assesment_response_matref
1257 protected $material_ref = null;
1259 * @var cc_assesment_flow_mattype
1261 protected $flow_mat = null;
1263 public function __construct() {
1264 $this->set_setting(cc_qti_tags::t_class);
1267 public function set_class($value) {
1268 $this->set_setting(cc_qti_tags::t_class, $value);
1271 public function set_material(cc_assesment_material $object) {
1272 $this->material = $object;
1275 public function set_material_ref(cc_assesment_response_matref $object) {
1276 $this->material_ref = $object;
1279 public function set_flow_mat(cc_assesment_flow_mattype $object) {
1280 $this->flow_mat = $object;
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);
1287 if (!empty($this->flow_mat)) {
1288 $this->flow_mat->generate($doc, $node, $namespace);
1291 if (!empty($this->material)) {
1292 $this->material->generate($doc, $node, $namespace);
1295 if (!empty($this->material_ref)) {
1296 $this->material_ref->generate($doc, $node, $namespace);
1301 class cc_assesment_response_labeltype extends cc_question_metadata_base {
1303 * @var cc_assesment_material
1305 protected $material = null;
1308 * @var cc_assesment_response_matref
1310 protected $material_ref = null;
1313 * @var cc_assesment_flow_mattype
1315 protected $flow_mat = null;
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);
1325 public function set_ident($value) {
1326 $this->set_setting(cc_qti_tags::ident, $value);
1329 public function get_ident() {
1330 return $this->get_setting(cc_qti_tags::ident);
1333 public function set_labelrefid($value) {
1334 $this->set_setting(cc_qti_tags::labelrefid, $value);
1337 public function enable_rshuffle($value = true) {
1338 $this->enable_setting_yesno(cc_qti_tags::rshuffle, $value);
1341 public function set_match_group($value) {
1342 $this->set_setting(cc_qti_tags::match_group, $value);
1345 public function set_match_max($value) {
1346 $this->set_setting(cc_qti_tags::match_max, $value);
1349 public function set_material(cc_assesment_material $object) {
1350 $this->material = $object;
1353 public function set_material_ref(cc_assesment_response_matref $object) {
1354 $this->material_ref = $object;
1357 public function set_flow_mat(cc_assesment_flow_mattype $object) {
1358 $this->flow_mat = $object;
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);
1365 if (!empty($this->material)) {
1366 $this->material->generate($doc, $node, $namespace);
1369 if (!empty($this->material_ref)) {
1370 $this->material_ref->generate($doc, $node, $namespace);
1373 if (!empty($this->flow_mat)) {
1374 $this->flow_mat->generate($doc, $node, $namespace);
1379 class cc_assesment_flow_labeltype extends cc_question_metadata_base {
1381 * @var cc_assesment_flow_labeltype
1383 protected $flow_label = null;
1385 * @var cc_assesment_response_labeltype
1387 protected $response_label = null;
1389 public function __construct() {
1390 $this->set_setting(cc_qti_tags::t_class);
1393 public function set_class($value) {
1394 $this->set_setting(cc_qti_tags::t_class, $value);
1397 public function set_flow_label(cc_assesment_flow_labeltype $object) {
1398 $this->flow_label = $object;
1401 public function set_response_label(cc_assesment_response_labeltype $object) {
1402 $this->response_label = $object;
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);
1409 if (!empty($this->material)) {
1410 $this->material->generate($doc, $node, $namespace);
1413 if (!empty($this->material_ref)) {
1414 $this->material_ref->generate($doc, $node, $namespace);
1417 if (!empty($this->response_label)) {
1418 $this->response_label->generate($doc, $node, $namespace);
1421 if (!empty($this->flow_label)) {
1422 $this->flow_label->generate($doc, $node, $namespace);
1429 class cc_assesment_render_fibtype extends cc_question_metadata_base {
1431 * @var cc_assesment_material
1433 protected $material = null;
1436 * @var cc_assesment_response_matref
1438 protected $material_ref = null;
1440 * @var cc_assesment_response_labeltype
1442 protected $response_label = null;
1445 * Enter description here ...
1446 * @var unknown_type
1448 protected $flow_label = null;
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);
1463 public function set_encoding($value) {
1464 $this->set_setting(cc_qti_tags::encoding, $value);
1466 public function set_charset($value) {
1467 $this->set_setting(cc_qti_tags::charset, $value);
1470 public function set_rows($value) {
1471 $this->set_setting(cc_qti_tags::rows, $value);
1474 public function set_columns($value) {
1475 $this->set_setting(cc_qti_tags::columns, $value);
1478 public function set_maxchars($value) {
1479 $this->set_setting(cc_qti_tags::columns, $value);
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);
1487 public function set_prompt($value) {
1488 $this->set_setting(cc_qti_tags::prompt, $value);
1491 public function set_fibtype($value) {
1492 $this->set_setting(cc_qti_tags::fibtype, $value);
1495 public function set_material(cc_assesment_material $object) {
1496 $this->material = $object;
1499 public function set_material_ref(cc_assesment_response_matref $object) {
1500 $this->material_ref = $object;
1503 public function set_response_label(cc_assesment_response_labeltype $object) {
1504 $this->response_label = $object;
1507 public function set_flow_label($object) {
1508 $this->flow_label = $object;
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);
1515 if (!empty($this->material) && empty($this->material_ref)) {
1516 $this->material->generate($doc, $node, $namespace);
1519 if (!empty($this->material_ref) && empty($this->material)) {
1520 $this->material_ref->generate($doc, $node, $namespace);
1523 if (!empty($this->response_label)) {
1524 $this->response_label->generate($doc, $node, $namespace);
1527 if (!empty($this->flow_label)) {
1528 $this->flow_label->generate($doc, $node, $namespace);
1533 class cc_response_lidtype extends cc_question_metadata_base {
1535 * @var string
1537 protected $tagname = null;
1539 * @var cc_assesment_material
1541 protected $material = null;
1544 * @var cc_assesment_response_matref
1546 protected $material_ref = null;
1549 * @var cc_assesment_render_choicetype
1551 protected $render_choice = null;
1554 * @var cc_assesment_render_fibtype
1556 protected $render_fib = null;
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;
1565 public function set_rcardinality($value) {
1566 $this->set_setting(cc_qti_tags::rcardinality, $value);
1569 public function enable_rtiming($value = true) {
1570 $this->enable_setting_yesno(cc_qti_tags::rtiming, $value);
1573 public function set_ident($value) {
1574 $this->set_setting(cc_qti_tags::ident, $value);
1577 public function get_ident() {
1578 return $this->get_setting(cc_qti_tags::ident);
1581 public function set_material_ref(cc_assesment_response_matref $object) {
1582 $this->material_ref = $object;
1585 public function set_material(cc_assesment_material $object) {
1586 $this->material = $object;
1589 public function set_render_choice(cc_assesment_render_choicetype $object) {
1590 $this->render_choice = $object;
1593 public function set_render_fib(cc_assesment_render_fibtype $object) {
1594 $this->render_fib = $object;
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);
1601 if (!empty($this->material) && empty($this->material_ref)) {
1602 $this->material->generate($doc, $node, $namespace);
1605 if (!empty($this->material_ref) && empty($this->material)) {
1606 $this->material_ref->generate($doc, $node, $namespace);
1609 if (!empty($this->render_choice) && empty($this->render_fib)) {
1610 $this->render_choice->generate($doc, $node, $namespace);
1613 if (!empty($this->render_fib) && empty($this->render_choice)) {
1614 $this->render_fib->generate($doc, $node, $namespace);
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;
1626 class cc_assesment_flowtype extends cc_question_metadata_base {
1628 * @var cc_assesment_flowtype
1630 protected $flow = null;
1632 * @var cc_assesment_material
1634 protected $material = null;
1636 * @var cc_assesment_response_matref
1638 protected $material_ref = null;
1640 * @var cc_response_lidtype
1642 protected $response_lid = null;
1644 * @var cc_assesment_response_strtype
1646 protected $response_str = null;
1648 public function __construct() {
1649 $this->set_setting(cc_qti_tags::t_class);
1652 public function set_class($value) {
1653 $this->set_setting(cc_qti_tags::t_class, $value);
1656 public function set_flow(cc_assesment_flowtype $object) {
1657 $this->flow = $object;
1660 public function set_material(cc_assesment_material $object) {
1661 $this->material = $object;
1664 public function set_material_ref(cc_assesment_response_matref $object) {
1665 $this->material_ref = $object;
1668 public function set_response_lid(cc_response_lidtype $object) {
1669 $this->response_lid = $object;
1672 public function set_response_str(cc_assesment_response_strtype $object) {
1673 $this->response_str = $object;
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);
1680 if (!empty($this->flow)) {
1681 $this->flow->generate($doc, $node, $namespace);
1684 if (!empty($this->material)) {
1685 $this->material->generate($doc, $node, $namespace);
1688 if (!empty($this->response_lid)) {
1689 $this->response_lid->generate($doc, $node, $namespace);
1692 if (!empty($this->response_str)) {
1693 $this->response_str->generate($doc, $node, $namespace);
1698 class cc_assesment_presentation extends cc_question_metadata_base {
1700 * @var cc_assesment_flowtype
1702 protected $flow = null;
1704 * @var cc_assesment_material
1706 protected $material = null;
1708 * @var cc_response_lidtype
1710 protected $response_lid = null;
1712 * @var cc_assesment_response_strtype
1714 protected $response_str = null;
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);
1725 public function set_label($value) {
1726 $this->set_setting(cc_qti_tags::label, $value);
1729 public function set_lang($value) {
1730 $this->set_setting_wns(cc_qti_tags::xml_lang , cc_xml_namespace::xml, $value);
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);
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);
1743 public function set_flow(cc_assesment_flowtype $object) {
1744 $this->flow = $object;
1747 public function set_material(cc_assesment_material $object) {
1748 $this->material = $object;
1751 public function set_response_lid(cc_response_lidtype $object) {
1752 $this->response_lid = $object;
1755 public function set_response_str(cc_assesment_response_strtype $object) {
1756 $this->response_str = $object;
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);
1763 if (!empty($this->flow)) {
1764 $this->flow->generate($doc, $node, $namespace);
1767 if (!empty($this->material) && empty($this->flow)) {
1768 $this->material->generate($doc, $node, $namespace);
1771 if (!empty($this->response_lid) && empty($this->flow)) {
1772 $this->response_lid->generate($doc, $node, $namespace);
1775 if (!empty($this->response_str) && empty($this->flow)) {
1776 $this->response_str->generate($doc, $node, $namespace);
1781 class assesment1_resurce_file extends general_cc_file {
1782 const deafultname = 'assesment.xml';
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');
1791 * @var string
1793 protected $assessment_title = 'Untitled';
1795 * @var cc_assesment_metadata
1797 protected $metadata = null;
1799 * @var cc_assesment_rubric_base
1801 protected $rubric = null;
1804 * @var cc_assesment_presentation_material_base
1806 protected $presentation_material = null;
1809 * @var cc_assesment_section
1811 protected $section = null;
1813 public function set_metadata(cc_assesment_metadata $object) {
1814 $this->metadata = $object;
1817 public function set_rubric(cc_assesment_rubric_base $object) {
1818 $this->rubric = $object;
1821 public function set_presentation_material(cc_assesment_presentation_material_base $object) {
1822 $this->presentation_material = $object;
1825 public function set_section(cc_assesment_section $object) {
1826 $this->section = $object;
1829 public function set_title($value) {
1830 $this->assessment_title = self::safexml($value);
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);
1840 //metadata - optional
1841 if (!empty($this->metadata)) {
1842 $this->metadata->generate($this, $assessment, $rns);
1845 //rubric - optional
1846 if (!empty($this->rubric)) {
1847 $this->rubric->generate($this, $assessment, $rns);
1850 //presentation_material - optional
1851 if (!empty($this->presentation_material)) {
1852 $this->presentation_material->generate($this, $assessment, $rns);
1855 //section - required
1856 if (!empty($this->section)) {
1857 $this->section->generate($this, $assessment, $rns);
1860 return true;
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');
1869 abstract class cc_assesment_helper {
1871 public static $correct_fb = null;
1872 public static $incorrect_fb = null;
1874 public static function add_feedback($qitem, $content, $content_type, $ident) {
1875 if (empty($content)) {
1876 return false;
1878 $qitemfeedback = new cc_assesment_itemfeedbacktype();
1879 $qitem->add_itemfeedback($qitemfeedback);
1880 if (!empty($ident)) {
1881 $qitemfeedback->set_ident($ident);
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;
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;
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);
1920 public static function add_assesment_description($rt, $content, $contenttype) {
1921 if (empty($rt) || empty($content)) {
1922 return;
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);
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);
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);
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
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;
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;
1983 $question_node = $questions->node("//question_category/questions/question[@id='{$value}']");
1984 if (empty($question_node)) {
1985 continue;
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);
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);
2027 if (!empty($question_processor)) {
2028 $question_processor->generate();
2029 ++$questioncount;
2031 break;
2032 default:
2034 break;
2039 //return dependencies
2040 return ($questioncount == 0) || ($questioncount != $questionforexport)?
2041 false: pkg_resource_dependencies::instance()->get_deps();
2046 * Checks if question has matching element
2047 * @param XMLGenericDocument $questions
2048 * @param object $question_node
2049 * @return bool
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;
2061 return $result;
2066 class cc_assesment_question_proc_base {
2068 * @var XMLGenericDocument
2070 protected $quiz = null;
2073 * @var XMLGenericDocument
2075 protected $questions = null;
2078 * @var cc_manifest
2080 protected $manifest = null;
2083 * @var cc_assesment_section
2085 protected $section = null;
2088 * @var DOMElement
2090 protected $question_node = null;
2093 * @var string
2095 protected $rootpath = null;
2098 * @var string
2100 protected $contextid = null;
2103 * @var string
2105 protected $outdir = null;
2108 * @var string
2110 protected $qtype = null;
2113 * @var cc_question_metadata
2115 protected $qmetadata = null;
2118 * @var cc_assesment_section_item
2120 protected $qitem = null;
2123 * @var cc_assesment_presentation
2125 protected $qpresentation = null;
2128 * @var cc_response_lidtype
2130 protected $qresponse_lid = null;
2132 protected $qresprocessing = null;
2134 protected $correct_grade_value = null;
2135 protected $correct_answer_node_id = null;
2136 protected $correct_answer_ident = null;
2138 protected $total_grade_value = null;
2140 protected $answerlist = null;
2142 protected $general_feedback = null;
2143 protected $correct_feedbacks = array();
2144 protected $incorrect_feedbacks = array();
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
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;
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;
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);
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);
2185 $rts = new cc_assesment_itemmetadata();
2186 $rts->add_metadata($this->qmetadata);
2187 $this->qitem->set_itemmetadata($rts);
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]);
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;
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);
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;
2234 public function on_generate_response_processing() {
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);
2245 $this->qresprocessing = $qresprocessing;
2249 public function generate() {
2250 $this->on_generate_metadata();
2252 $this->on_generate_presentation();
2254 $this->on_generate_answers();
2256 $this->on_generate_feedbacks();
2258 $this->on_generate_response_processing();
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;
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
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!');
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';
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;
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);
2327 cc_assesment_helper::add_feedback( $this->qitem,
2328 $result[0],
2329 cc_qti_values::htmltype,
2330 $feedback_ident);
2332 pkg_resource_dependencies::instance()->add($result[1]);
2334 $answerlist[$answer_ident] = $feedback_ident;
2338 $this->answerlist = $answerlist;
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;
2352 $result = cc_helpers::process_linked_files( $content,
2353 $this->manifest,
2354 $this->rootpath,
2355 $this->contextid,
2356 $this->outdir);
2358 cc_assesment_helper::add_feedback( $this->qitem,
2359 $result[0],
2360 cc_qti_values::htmltype,
2361 $ident);
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;
2373 public function on_generate_response_processing() {
2374 parent::on_generate_response_processing();
2376 //respconditions
2378 * General unconditional feedback must be added as a first respcondition
2379 * without any condition and just displayfeedback (if exists)
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');
2397 //success condition
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.
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());
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]);
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);
2431 //rest of the conditions
2432 foreach ($this->answerlist as $ident => $refid) {
2433 if ($ident == $this->correct_answer_ident) {
2434 continue;
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());
2448 $qdisplayfeedback = new cc_assignment_displayfeedbacktype();
2449 $qrespcondition->add_displayfeedback($qdisplayfeedback);
2450 $qdisplayfeedback->set_feedbacktype(cc_qti_values::Response);
2451 $qdisplayfeedback->set_linkrefid($refid);
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);
2463 class cc_assesment_question_multichoice_multiresponse extends cc_assesment_question_proc_base {
2465 * @var DOMNodeList
2467 protected $correct_answers = null;
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;
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!');
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';
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);
2521 cc_assesment_helper::add_feedback( $this->qitem,
2522 $result[0],
2523 cc_qti_values::htmltype,
2524 $feedback_ident);
2526 pkg_resource_dependencies::instance()->add($result[1]);
2529 $answerlist[$answer_ident] = array($feedback_ident, ($answer_grade_fraction > 0));
2532 $this->answerlist = $answerlist;
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!';
2545 if (empty($incorrect_question_fb)) {
2546 //Hardcode some text for now
2547 $incorrect_question_fb = 'Better luck next time!';
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;
2555 $result = cc_helpers::process_linked_files( $content,
2556 $this->manifest,
2557 $this->rootpath,
2558 $this->contextid,
2559 $this->outdir);
2561 cc_assesment_helper::add_feedback( $this->qitem,
2562 $result[0],
2563 cc_qti_values::htmltype,
2564 $ident);
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;
2576 public function on_generate_response_processing() {
2577 parent::on_generate_response_processing();
2579 //respconditions
2581 * General unconditional feedback must be added as a first respcondition
2582 * without any condition and just displayfeedback (if exists)
2584 cc_assesment_helper::add_respcondition( $this->qresprocessing,
2585 'General feedback',
2586 $this->general_feedback,
2587 null,
2588 true
2591 //success condition
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.
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);
2618 $qvarequal->set_respident($this->qresponse_lid->get_ident());
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);
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()
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,