ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.SurveyImportParser.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2019 ILIAS open source, Extended GPL, see docs/LICENSE */
4
11{
12 public $path;
13 public $depth;
15 public $spl;
18 public $error_col;
19 public $error_msg;
20 public $has_error;
21 public $size;
22 public $elements;
24 public $texts;
25 public $text_size;
27 public $activetag;
28 public $material;
29 public $metadata;
30 public $responses;
31 public $variables;
33 public $matrix;
35 public $is_matrix;
38 public $in_survey;
39 public $survey;
42 public $questions;
45 public $textblock;
52
60 public function __construct($a_spl_id, $a_xml_file = '', $spl_exists = false, $a_mapping = null)
61 {
62 parent::__construct($a_xml_file);
63 $this->spl_id = $a_spl_id;
64 $this->has_error = false;
65 $this->characterbuffer = "";
66 $this->survey_status = 0;
67 $this->activetag = "";
68 $this->material = array();
69 $this->depth = array();
70 $this->path = array();
71 $this->metadata = array();
72 $this->responses = array();
73 $this->variables = array();
74 $this->response_id = "";
75 $this->matrix = array();
76 $this->is_matrix = false;
77 $this->adjectives = array();
78 $this->spl_exists = $spl_exists;
79 $this->survey = null;
80 $this->in_survey = false;
81 $this->anonymisation = 0;
82 $this->surveyaccess = "restricted";
83 $this->questions = array();
84 $this->original_question_id = "";
85 $this->constraints = array();
86 $this->textblock = "";
87 $this->textblocks = array();
88 $this->in_questionblock = false;
89 $this->questionblocks = array();
90 $this->questionblock = array();
91 $this->showQuestiontext = 1;
92 $this->questionblocktitle = "";
93 $this->mapping = $a_mapping;
94 }
95
100 public function setSurveyObject($a_svy)
101 {
102 $this->survey = $a_svy;
103 }
104
110 public function setHandlers($a_xml_parser)
111 {
112 xml_set_object($a_xml_parser, $this);
113 xml_set_element_handler($a_xml_parser, 'handlerBeginTag', 'handlerEndTag');
114 xml_set_character_data_handler($a_xml_parser, 'handlerCharacterData');
115 }
116
120 public function startParsing()
121 {
122 parent::startParsing();
123 }
124
130 public function parse($a_xml_parser, $a_fp = null)
131 {
132 switch ($this->getInputType()) {
133 case 'file':
134
135 while ($data = fread($a_fp, 4096)) {
136 $parseOk = xml_parse($a_xml_parser, $data, feof($a_fp));
137 }
138 break;
139
140 case 'string':
141 $parseOk = xml_parse($a_xml_parser, $this->getXMLContent());
142 break;
143 }
144 if (!$parseOk
145 && (xml_get_error_code($a_xml_parser) != XML_ERROR_NONE)) {
146 $this->error_code = xml_get_error_code($a_xml_parser);
147 $this->error_line = xml_get_current_line_number($a_xml_parser);
148 $this->error_col = xml_get_current_column_number($a_xml_parser);
149 $this->error_msg = xml_error_string($a_xml_parser);
150 $this->has_error = true;
151 return false;
152 }
153 return true;
154 }
155
156 public function getParent($a_xml_parser)
157 {
158 if ($this->depth[$a_xml_parser] > 0) {
159 return $this->path[$this->depth[$a_xml_parser] - 1];
160 } else {
161 return "";
162 }
163 }
164
168 public function handlerBeginTag($a_xml_parser, $a_name, $a_attribs)
169 {
170 $this->depth[$a_xml_parser]++;
171 $this->path[$this->depth[$a_xml_parser]] = strtolower($a_name);
172 $this->characterbuffer = "";
173 $this->activetag = $a_name;
174 $this->elements++;
175 $this->attributes += count($a_attribs);
176 switch ($a_name) {
177 case "questionblock":
178 $this->in_questionblock = true;
179 $this->questionblock = array();
180 $this->questionblocktitle = "";
181 $this->showQuestiontext = 1;
182 foreach ($a_attribs as $attrib => $value) {
183 switch ($attrib) {
184 case "showQuestiontext":
185 $this->showQuestiontext = $value;
186 break;
187 }
188 }
189 break;
190 case "surveyquestions":
191 foreach ($a_attribs as $attrib => $value) {
192 switch ($attrib) {
193 case "online":
194 if ($this->spl_id > 0) {
195 $spl = new ilObjSurveyQuestionPool($this->spl_id, false);
196 $spl->setOnline($value);
197 $spl->saveToDb();
198 }
199 break;
200 }
201 }
202 break;
203 case "survey":
204 $this->in_survey = true;
205 foreach ($a_attribs as $attrib => $value) {
206 switch ($attrib) {
207 case "title":
208 if (is_object($this->survey)) {
209 $this->survey->setTitle($value);
210 $this->survey->update(true);
211 }
212 break;
213 }
214 }
215 break;
216 case "anonymisation":
217 foreach ($a_attribs as $attrib => $value) {
218 switch ($attrib) {
219 case "enabled":
220 $this->anonymisation = $value;
221 break;
222 }
223 }
224 break;
225 case "access":
226 foreach ($a_attribs as $attrib => $value) {
227 switch ($attrib) {
228 case "type":
229 $this->surveyaccess = $value;
230 break;
231 }
232 }
233 break;
234 case "constraint":
235 array_push(
236 $this->constraints,
237 array(
238 "sourceref" => $a_attribs["sourceref"],
239 "destref" => $a_attribs["destref"],
240 "relation" => $a_attribs["relation"],
241 "value" => $a_attribs["value"],
242
243 // might be missing in old export files
244 "conjunction" => (int) $a_attribs["conjuction"]
245 )
246 );
247 break;
248 case "question":
249 // start with a new survey question
250 $type = $a_attribs["type"];
251 // patch due to changes in question types
252 switch ($type) {
253 case 'SurveyNominalQuestion':
254 $type = 'SurveyMultipleChoiceQuestion';
255 foreach ($a_attribs as $key => $value) {
256 switch ($key) {
257 case "subtype":
258 if ($value == 1) {
259 $type = 'SurveySingleChoiceQuestion';
260 } else {
261 $type = 'SurveyMultipleChoiceQuestion';
262 }
263 break;
264 }
265 }
266 break;
267 case 'SurveyOrdinalQuestion':
268 $type = 'SurveySingleChoiceQuestion';
269 break;
270 }
271 if (strlen($type)) {
273 $this->activequestion = new $type();
274
275 // if no pool is given, question will reference survey
276 $q_obj_id = $this->spl_id;
277 if ($this->spl_id < 0) {
278 $q_obj_id = $this->survey->getId();
279 }
280
281 $this->activequestion->setObjId($q_obj_id);
282 }
283 } else {
284 $this->activequestion = null;
285 }
286 $this->original_question_id = $a_attribs["id"];
287 if ($this->in_questionblock) {
288 array_push($this->questionblock, $this->original_question_id);
289 }
290 if (is_object($this->activequestion)) {
291 foreach ($a_attribs as $key => $value) {
292 switch ($key) {
293 case "title":
294 $this->activequestion->setTitle($value);
295 break;
296 case "subtype":
297 $this->activequestion->setSubtype($value);
298 break;
299 case "obligatory":
300 $this->activequestion->setObligatory($value);
301 break;
302 }
303 }
304 }
305 break;
306 case "material":
307 switch ($this->getParent($a_xml_parser)) {
308 case "question":
309 case "questiontext":
310 $this->material = array();
311 break;
312 }
313 array_push($this->material, array("text" => "", "image" => "", "label" => $a_attribs["label"]));
314 break;
315 case "matimage":
316 case "label":
317 if (array_key_exists("label", $a_attribs)) {
318 if (preg_match("/(il_([0-9]+)_mob_([0-9]+))/", $a_attribs["label"], $matches)) {
319 // import an mediaobject which was inserted using tiny mce
320 if (!is_array($_SESSION["import_mob_xhtml"])) {
321 $_SESSION["import_mob_xhtml"] = array();
322 }
323 array_push($_SESSION["import_mob_xhtml"], array("mob" => $a_attribs["label"], "uri" => $a_attribs["uri"], "type" => $a_attribs["type"], "id" => $a_attribs["id"]));
324 }
325 }
326 break;
327 case "metadata":
328 $this->metadata = array();
329 break;
330 case "metadatafield":
331 array_push($this->metadata, array("label" => "", "entry" => ""));
332 break;
333 case "matrix":
334 $this->is_matrix = true;
335 $this->matrix = array();
336 break;
337 case "matrixrow":
338 $this->material = array();
339 array_push($this->matrix, "");
340 $this->matrixrowattribs = array("id" => $a_attribs["id"], "label" => $a_attribs["label"], "other" => $a_attribs["other"]);
341 break;
342 case "responses":
343 $this->material = array();
344 $this->responses = array();
345 break;
346 case "variables":
347 $this->variables = array();
348 break;
349 case "response_single":
350 $this->material = array();
351 $this->responses[$a_attribs["id"]] = array("type" => "single", "id" => $a_attribs["id"], "label" => $a_attribs["label"], "other" => $a_attribs["other"], "neutral" => $a_attribs["neutral"], "scale" => $a_attribs["scale"]);
352 $this->response_id = $a_attribs["id"];
353 break;
354 case "response_multiple":
355 $this->material = array();
356 $this->responses[$a_attribs["id"]] = array("type" => "multiple", "id" => $a_attribs["id"], "label" => $a_attribs["label"], "other" => $a_attribs["other"], "neutral" => $a_attribs["neutral"], "scale" => $a_attribs["scale"]);
357 $this->response_id = $a_attribs["id"];
358 break;
359 case "response_text":
360 $this->material = array();
361 $this->responses[$a_attribs["id"]] = array("type" => "text", "id" => $a_attribs["id"], "columns" => $a_attribs["columns"], "maxlength" => $a_attribs["maxlength"], "rows" => $a_attribs["rows"], "label" => $a_attribs["label"]);
362 $this->response_id = $a_attribs["id"];
363 break;
364 case "response_num":
365 $this->material = array();
366 $this->responses[$a_attribs["id"]] = array("type" => "num", "id" => $a_attribs["id"], "format" => $a_attribs["format"], "max" => $a_attribs["max"], "min" => $a_attribs["min"], "size" => $a_attribs["size"], "label" => $a_attribs["label"]);
367 $this->response_id = $a_attribs["id"];
368 break;
369 case "response_time":
370 $this->material = array();
371 $this->responses[$a_attribs["id"]] = array("type" => "time", "id" => $a_attribs["id"], "format" => $a_attribs["format"], "max" => $a_attribs["max"], "min" => $a_attribs["min"], "label" => $a_attribs["label"]);
372 $this->response_id = $a_attribs["id"];
373 break;
374 case "bipolar_adjectives":
375 $this->adjectives = array();
376 break;
377 case "adjective":
378 array_push($this->adjectives, array("label" => $a_attribs["label"], "text" => ""));
379 break;
380 }
381 }
382
386 public function handlerCharacterData($a_xml_parser, $a_data)
387 {
388 $this->texts++;
389 $this->text_size += strlen($a_data);
390 $this->characterbuffer .= $a_data;
391 $a_data = $this->characterbuffer;
392 }
393
397 public function handlerEndTag($a_xml_parser, $a_name)
398 {
399 switch ($a_name) {
400 case "surveyobject":
401 if (is_object($this->survey)) {
402 $this->survey->setOfflineStatus(!$this->survey_status);
403 $this->survey->saveToDb();
404
405 // write question blocks
406 if (count($this->questionblocks)) {
407 foreach ($this->questionblocks as $data) {
408 $questionblock = $data["questions"];
409 $title = $data["title"];
410 $qblock = array();
411 foreach ($questionblock as $question_id) {
412 array_push($qblock, $this->questions[$question_id]);
413 }
414 $this->survey->createQuestionblock($title, $this->showQuestiontext, false, $qblock);
415 }
416 }
417
418 // #13878 - write constraints
419 if (count($this->constraints)) {
420 $relations = $this->survey->getAllRelations(true);
421 foreach ($this->constraints as $constraint) {
422 $constraint_id = $this->survey->addConstraint($this->questions[$constraint["destref"]], $relations[$constraint["relation"]]["id"], $constraint["value"], $constraint["conjunction"]);
423 $this->survey->addConstraintToQuestion($this->questions[$constraint["sourceref"]], $constraint_id);
424 }
425 }
426
427 // write textblocks
428 if (count($this->textblocks)) {
429 foreach ($this->textblocks as $original_id => $textblock) {
430 $this->survey->saveHeading($textblock, $this->questions[$original_id]);
431 }
432 }
433 }
434 break;
435 case "survey":
436 $this->in_survey = false;
437 if (is_object($this->survey)) {
438 if (strcmp($this->surveyaccess, "free") == 0) {
439 $this->survey->setAnonymize(2);
440 } else {
441 if ($this->anonymisation == 0) {
442 $this->survey->setAnonymize(0);
443 } else {
444 $this->survey->setAnonymize(1);
445 }
446 }
447 }
448 break;
449 case "startingtime":
450 if (preg_match("/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).*/", $this->characterbuffer, $matches)) {
451 if (is_object($this->survey)) {
452 $this->survey->setStartDate(sprintf("%04d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
453 }
454 }
455 break;
456 case "endingtime":
457 if (preg_match("/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).*/", $this->characterbuffer, $matches)) {
458 if (is_object($this->survey)) {
459 $this->survey->setEndDate(sprintf("%04d%02d%02d%02d%02d%02d", $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]));
460 }
461 }
462 break;
463 case "description":
464 if ($this->in_survey) {
465 if (is_object($this->survey)) {
466 $this->survey->setDescription($this->characterbuffer);
467 $this->survey->update(true);
468 }
469 } else {
470 if (is_object($this->activequestion)) {
471 $this->activequestion->setDescription($this->characterbuffer);
472 }
473 }
474 break;
475 case "question":
476 if (is_object($this->activequestion)) {
477 if (strlen($this->textblock)) {
479 }
480 $this->activequestion->saveToDb();
481 // duplicate the question for the survey (if pool is to be used)
482 if (is_object($this->survey) &&
483 $this->spl_id > 0) {
484 $question_id = $this->activequestion->duplicate(true, "", "", "", $this->survey->getId());
485 } else {
486 $question_id = $this->activequestion->getId();
487 }
488 if (is_object($this->survey)) { // #15452
489 $this->survey->addQuestion($question_id);
490 }
491 $this->questions[$this->original_question_id] = $question_id;
492 if ($this->mapping) {
493 $this->mapping->addMapping("Modules/Survey", "svy_q", $this->original_question_id, $question_id);
494 }
495 $this->activequestion = null;
496 }
497 $this->textblock = "";
498 break;
499 case "author":
500 if ($this->in_survey) {
501 if (is_object($this->survey)) {
502 $this->survey->setAuthor($this->characterbuffer);
503 }
504 } else {
505 if (is_object($this->activequestion)) {
506 $this->activequestion->setAuthor($this->characterbuffer);
507 }
508 }
509 break;
510 case "mattext":
511 $this->material[count($this->material) - 1]["text"] = $this->characterbuffer;
512 break;
513 case "matimage":
514 $this->material[count($this->material) - 1]["image"] = $this->characterbuffer;
515 break;
516 case "material":
517 if ($this->in_survey) {
518 if (strcmp($this->getParent($a_xml_parser), "objectives") == 0) {
519 if (strcmp($this->material[0]["label"], "introduction") == 0) {
520 if (is_object($this->survey)) {
521 $this->survey->setIntroduction($this->material[0]["text"]);
522 }
523 }
524 if (strcmp($this->material[0]["label"], "outro") == 0) {
525 if (is_object($this->survey)) {
526 $this->survey->setOutro($this->material[0]["text"]);
527 }
528 }
529 $this->material = array();
530 }
531 } else {
532 if (strcmp($this->getParent($a_xml_parser), "question") == 0) {
533 $this->activequestion->setMaterial($this->material[0]["text"], true, $this->material[0]["label"]);
534 }
535 }
536 break;
537 case "questiontext":
538 if (is_object($this->activequestion)) {
539 $questiontext = "";
540 foreach ($this->material as $matarray) {
541 $questiontext .= $matarray["text"];
542 }
543 $this->activequestion->setQuestiontext($questiontext);
544 }
545 $this->material = array();
546 break;
547 case "fieldlabel":
548 $this->metadata[count($this->metadata) - 1]["label"] = $this->characterbuffer;
549 break;
550 case "fieldentry":
551 $this->metadata[count($this->metadata) - 1]["entry"] = $this->characterbuffer;
552 break;
553 case "metadata":
554 if (strcmp($this->getParent($a_xml_parser), "question") == 0) {
555 if (is_object($this->activequestion)) {
556 $this->activequestion->importAdditionalMetadata($this->metadata);
557 }
558 }
559 if (strcmp($this->getParent($a_xml_parser), "survey") == 0) {
560 foreach ($this->metadata as $key => $value) {
561 switch ($value["label"]) {
562 case "SCORM":
563 if (strlen($value["entry"])) {
564 if (is_object($this->survey)) {
565 $md_sax_parser = new ilMDSaxParser();
566 $md_sax_parser->setXMLContent($value["entry"]);
567 $md_sax_parser->setMDObject($tmp = new ilMD($this->survey->getId(), 0, "svy"));
568 $md_sax_parser->enableMDParsing(true);
569 $md_sax_parser->startParsing();
570 $this->survey->MDUpdateListener("General");
571 }
572 }
573 break;
574 case "display_question_titles":
575 if ($value["entry"] == 1) {
576 $this->survey->showQuestionTitles();
577 } else {
578 $this->survey->hideQuestionTitles();
579 }
580 break;
581 case "status":
582 $this->survey_status = $value["entry"];
583 break;
584 case "evaluation_access":
585 $this->survey->setEvaluationAccess($value["entry"]);
586 break;
587 case "pool_usage":
588 $this->survey->setPoolUsage($value["entry"]);
589 break;
590 case "own_results_view":
591 $this->survey->setViewOwnResults($value["entry"]);
592 break;
593 case "own_results_mail":
594 $this->survey->setMailOwnResults($value["entry"]);
595 break;
596 case "confirmation_mail":
597 $this->survey->setMailConfirmation($value["entry"]);
598 break;
599 case "anon_user_list":
600 $this->survey->setAnonymousUserList($value["entry"]);
601 break;
602 case "mode":
603 $this->survey->setMode($value["entry"]);
604 break;
605 case "mode_360_self_eval":
606 $this->survey->set360SelfEvaluation($value["entry"]);
607 break;
608 case "mode_360_self_rate":
609 $this->survey->set360SelfRaters($value["entry"]);
610 break;
611 case "mode_360_self_appr":
612 $this->survey->set360SelfAppraisee($value["entry"]);
613 break;
614 case "mode_360_results":
615 $this->survey->set360Results($value["entry"]);
616 break;
617 case "mode_self_eval_results":
618 $this->survey->setSelfEvaluationResults($value["entry"]);
619 break;
620 case "mode_skill_service":
621 $this->survey->setSkillService($value["entry"]);
622 break;
623 }
624 }
625 }
626 if (!$this->spl_exists) {
627 if (strcmp($this->getParent($a_xml_parser), "surveyquestions") == 0) {
628 foreach ($this->metadata as $key => $value) {
629 if (strcmp($value["label"], "SCORM") == 0) {
630 if (strlen($value["entry"])) {
631 if ($this->spl_id > 0) {
632 $md_sax_parser = new ilMDSaxParser();
633 $md_sax_parser->setXMLContent($value["entry"]);
634 $md_sax_parser->setMDObject($tmp = new ilMD($this->spl_id, 0, "spl"));
635 $md_sax_parser->enableMDParsing(true);
636 $md_sax_parser->startParsing();
637 $spl = new ilObjSurveyQuestionPool($this->spl_id, false);
638 $spl->MDUpdateListener("General");
639 }
640 }
641 }
642 }
643 }
644 }
645 break;
646 case "responses":
647 if (is_object($this->activequestion)) {
648 $this->activequestion->importResponses($this->responses);
649 }
650 $this->is_matrix = false;
651 break;
652 case "variable":
653 array_push($this->variables, $this->characterbuffer);
654 break;
655 case "variables":
656 if (is_object($this->activequestion)) {
657 $this->activequestion->importVariables($this->variables);
658 }
659 break;
660 case "response_single":
661 case "response_multiple":
662 case "response_text":
663 case "response_num":
664 case "response_time":
665 $this->responses[$this->response_id]["material"] = $this->material;
666 break;
667 case "adjective":
668 $this->adjectives[count($this->adjectives) - 1]["text"] = $this->characterbuffer;
669 break;
670 case "bipolar_adjectives":
671 if (is_object($this->activequestion)) {
672 $this->activequestion->importAdjectives($this->adjectives);
673 }
674 break;
675 case "matrixrow":
676 $row = "";
677 foreach ($this->material as $material) {
678 $row .= $material["text"];
679 }
680 $this->matrix[count($this->matrix) - 1] = array('title' => $row, 'id' => $this->matrixrowattribs['id'], 'label' => $this->matrixrowattribs['label'], 'other' => $this->matrixrowattribs['other']);
681 break;
682 case "matrix":
683 if (is_object($this->activequestion)) {
684 $this->activequestion->importMatrix($this->matrix);
685 }
686 break;
687 case "textblock":
688 $this->textblock = $this->characterbuffer;
689 break;
690 case "questionblocktitle":
691 $this->questionblocktitle = $this->characterbuffer;
692 break;
693 case "questionblock":
694 $this->in_questionblock = false;
695 array_push($this->questionblocks, array("title" => $this->questionblocktitle, "questions" => $this->questionblock));
696 break;
697 }
698 $this->depth[$a_xml_parser]--;
699 }
700
701 public function getErrorCode()
702 {
703 return $this->error_code;
704 }
705
706 public function getErrorLine()
707 {
708 return $this->error_line;
709 }
710
711 public function getErrorColumn()
712 {
713 return $this->error_col;
714 }
715
716 public function getErrorMessage()
717 {
718 return $this->error_msg;
719 }
720
721 public function getFullError()
722 {
723 return "Error: " . $this->error_msg . " at line:" . $this->error_line . " column:" . $this->error_col;
724 }
725
726 public function getXMLSize()
727 {
728 return $this->size;
729 }
730
731 public function getXMLElements()
732 {
733 return $this->elements;
734 }
735
736 public function getXMLAttributes()
737 {
738 return $this->attributes;
739 }
740
741 public function getXMLTextSections()
742 {
743 return $this->texts;
744 }
745
746 public function getXMLTextSize()
747 {
748 return $this->text_size;
749 }
750
751 public function hasError()
752 {
753 return $this->has_error;
754 }
755}
$attrib
Regular expression to match HTML/XML attribute pairs within a tag.
Definition: Sanitizer.php:42
$_SESSION["AccountId"]
An exception for terminatinating execution or to throw for unit testing.
Survey Question Import Parser.
handlerBeginTag($a_xml_parser, $a_name, $a_attribs)
handler for begin of element
startParsing()
start the parser
parse($a_xml_parser, $a_fp=null)
parse xml file
setSurveyObject($a_svy)
Sets a reference to a survey object @access public.
handlerEndTag($a_xml_parser, $a_name)
handler for end of element
setHandlers($a_xml_parser)
set event handler should be overwritten by inherited class @access private
__construct($a_spl_id, $a_xml_file='', $spl_exists=false, $a_mapping=null)
Constructor.
handlerCharacterData($a_xml_parser, $a_data)
handler for character data
static _includeClass($question_type, $gui=0)
Include the php class file for a given question type.
Class ilObjSurveyQuestionPool.
Base class for sax-based expat parsing extended classes need to overwrite the method setHandlers and ...
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$type
$data
Definition: storeScorm.php:23