ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilQuestionPageParser.php
Go to the documentation of this file.
1<?php
2
20
28{
32 protected bool $in_properties;
36 protected bool $in_glossary_definition = false;
37 protected array $pg_mapping = [];
38 protected array $mobs_with_int_links = [];
39 protected bool $inside_code = false;
40 protected string $content_type = '';
41 public ilTree $tree;
42 public array $cnt = []; // counts open elements
43 public array $current_element = []; // store current element type
44 public ?ilObjLearningModule $learning_module = null; // current learning module
45 public ?ilPageObject $page_object = null; // current page object
47 public array $structure_objects = []; // array of current structure objects
49 public ?object $current_object = null; // at the time a LearningModule, PageObject or StructureObject
50 public ?ilLMTree $lm_tree = null;
51 public array $pg_into_tree = [];
52 public array $st_into_tree = [];
53 public array $container = [];
54 public bool $in_page_object = false; // are we currently within a PageObject? true/false
55 public bool $in_media_object = false;
56 public bool $in_file_item = false;
57 public bool $in_glossary = false;
58 public bool $in_map_area = false;
60 public ?ilObjFile $file_item = null;
61 public array $pages_to_parse = [];
62 public array $mob_mapping = [];
63 public array $file_item_mapping = [];
64 public ?ilMediaItem $media_item = null; // current media item
65 public string $loc_type = ''; // current location type
66 public ?ilMapArea $map_area = null; // current map area
67 public array $link_targets = []; // stores all objects by import id
68 public array $qst_mapping = [];
69 protected array $glossary_term_map = [];
70 protected ilLogger $log;
71 protected ?ilGlossaryTerm $glossary_term = null;
72 protected ?ilImportMapping $mapping = null;
73 protected string $cur_qid = '';
74 protected string $chr_data = '';
75 protected bool $in_media_item = false;
76
77 public function __construct(
78 private readonly ilObject $content_object,
79 string $xml_file,
80 private readonly string $importdir
81 ) {
82 global $DIC;
83 $lng = $DIC->language();
84 $tree = $DIC->repositoryTree();
85
86 $this->log = ilLoggerFactory::getLogger('lm');
87
89 $this->cnt = [];
90 $this->current_element = [];
91 $this->structure_objects = [];
92 $this->st_into_tree = [];
93 $this->pg_into_tree = [];
94 $this->pages_to_parse = [];
95 $this->mobs_with_int_links = [];
96 $this->mob_mapping = [];
97 $this->file_item_mapping = [];
98 $this->pg_mapping = [];
99 $this->link_targets = [];
100 $this->lng = $lng;
101 $this->tree = $tree;
102 $this->inside_code = false;
103 $this->qst_mapping = [];
104 $this->content_type = $this->content_object->getType();
105
106 if ($this->content_type !== 'tst' && $this->content_type !== 'qpl') {
107 $this->lm_tree = new ilLMTree($this->content_object->getId());
108 }
109 }
110
114 public function setHandlers($xml_parser): void
115 {
116 xml_set_element_handler($xml_parser, $this->handlerBeginTag(...), $this->handlerEndTag(...));
117 xml_set_character_data_handler($xml_parser, $this->handlerCharacterData(...));
118 }
119
120 public function setImportMapping(?ilImportMapping $mapping = null): void
121 {
122 $this->mapping = $mapping;
123 }
124
125 public function startParsing(): void
126 {
127 $this->log->debug('start');
128
129 parent::startParsing();
130 $this->storeTree();
131 $this->processPagesToParse();
132 $this->copyFileItems();
133 }
134
138 public function storeTree(): void
139 {
140 $ilLog = $this->log;
141
142 foreach ($this->st_into_tree as $st) {
143 $this->lm_tree->insertNode($st['id'], $st['parent']);
144 if (is_array($this->pg_into_tree[$st['id']])) {
145 foreach ($this->pg_into_tree[$st['id']] as $pg) {
146 $pg_id = 0;
147 switch ($pg['type']) {
148 case 'pg_alias':
149 if ($this->pg_mapping[$pg['id']] == '') {
150 $ilLog->write('LM Import: No PageObject for PageAlias ' .
151 $pg['id'] . ' found! (Please update export installation to ILIAS 3.3.0)');
152
153 // Jump two levels up. First level is switch
154 continue 2;
155 }
156 $pg_id = $this->pg_mapping[$pg['id']];
157 break;
158
159 case 'pg':
160 $pg_id = $pg['id'];
161 break;
162 }
163 if (!$this->lm_tree->isInTree($pg_id)) {
164 $this->lm_tree->insertNode($pg_id, $st['id']);
165 }
166 }
167 }
168 }
169 }
170
174 public function processPagesToParse(): void
175 {
176 // outgoin internal links
177 foreach ($this->pages_to_parse as $page_id) {
178 $page_arr = explode(':', $page_id);
179 $page_obj = null;
180 switch ($page_arr[0]) {
181 case 'lm':
182 switch ($this->content_object->getType()) {
183 case 'lm':
184 $page_obj = new ilLMPage($page_arr[1]);
185 break;
186
187 default:
188 die('Unknown content type ' . $this->content_object->getType());
189 }
190
191 break;
192
193 case 'term':
194 $page_obj = new ilGlossaryDefPage($page_arr[1]);
195 break;
196
197 case 'qpl':
198 $page_obj = new ilAssQuestionPage($page_arr[1]);
199 break;
200 }
201 $page_obj->buildDom();
202 $page_obj->resolveIntLinks();
203 $page_obj->resolveIIMMediaAliases($this->mob_mapping);
204 if ($this->content_type == 'lm') {
205 $page_obj->resolveQuestionReferences($this->qst_mapping);
206 }
207 $page_obj->update(false);
208
209 if ($page_arr[0] == 'term') {
210 $term = new ilGlossaryTerm($page_arr[1]);
211 $term->updateShortText();
212 }
213
214 unset($page_obj);
215 }
216
217 foreach ($this->mobs_with_int_links as $mob_id) {
219 }
220
221 $done = [];
222 foreach ($this->link_targets as $link_target) {
223 $parsed = $this->parseLinkTarget((string) $link_target);
224 if (!isset($parsed)) {
225 continue;
226 }
227 //echo "doin link target:".$link_target.":<br>";
229 $parsed['target_type'],
230 $parsed['target_id'],
231 $parsed['target_inst']
232 );
233 foreach ($sources as $key => $source) {
234 if (in_array($key, $done)) {
235 continue;
236 }
237 $type_arr = explode(':', $source['type']);
238
239 // content object pages
240 if ($type_arr[1] == 'pg') {
241 if (ilPageObject::_exists($type_arr[0], $source['id'])) {
242 $page_object = ilPageObjectFactory::getInstance($type_arr[0], $source['id']);
246 unset($page_object);
247 }
248 }
249
250 // eventually correct links in questions to learning modules
251 if ($type_arr[0] === 'qst') {
252 assQuestion::instantiateQuestion($source['id'])->resolveSuggestedSolutionLinks();
253 }
254 $done[$key] = $key;
255 }
256 }
257 }
258
262 private function copyFileItems(): void
263 {
264 foreach ($this->file_item_mapping as $origin_id => $file_id) {
265 if (empty($origin_id)) {
266 continue;
267 }
268 $obj_dir = $origin_id;
269 $source_dir = $this->importdir . DIRECTORY_SEPARATOR . 'objects' . DIRECTORY_SEPARATOR . $obj_dir;
270
271 $file_obj = new ilObjFile($file_id, false);
272 if (is_dir($source_dir)) {
273 $files = scandir($source_dir, SCANDIR_SORT_DESCENDING);
274 if ($files !== false && $files !== [] && is_file($source_dir . '/' . $files[0])) {
275 $file = fopen($source_dir . '/' . $files[0], 'rb');
276 $file_stream = Streams::ofResource($file);
277 $file_obj->appendStream($file_stream, $files[0]);
278 }
279 }
280 $file_obj->update();
281 }
282 }
283
288 public function setQuestionMapping(array $a_map): void
289 {
290 $this->qst_mapping = $a_map;
291 }
292
293 public function beginElement(string $a_name): void
294 {
295 if (!isset($this->status['$a_name'])) {
296 $this->cnt[$a_name] = 1;
297 } else {
298 $this->cnt[$a_name]++;
299 }
300 $this->current_element[count($this->current_element)] = $a_name;
301 }
302
303 public function endElement(string $a_name): void
304 {
305 $this->cnt[$a_name]--;
306 unset($this->current_element[count($this->current_element) - 1]);
307 }
308
309 public function getCurrentElement(): string
310 {
311 return ($this->current_element[count($this->current_element) - 1] ?? '');
312 }
313
314 public function getOpenCount(string $a_name): int
315 {
316 if (isset($this->cnt[$a_name])) {
317 return $this->cnt[$a_name];
318 }
319 return 0;
320 }
321
322 public function buildTag(
323 string $type,
324 string $name,
325 array $attr = []
326 ): string {
327 $tag = '<';
328
329 if ($type == 'end') {
330 $tag .= '/';
331 }
332
333 $tag .= $name;
334
335 if (is_array($attr)) {
336 foreach ($attr as $k => $v) {
337 $tag .= ' ' . $k . "='$v'";
338 }
339 }
340
341 $tag .= '>';
342
343 return $tag;
344 }
345
346 public function handlerBeginTag($a_xml_parser, string $a_name, array $a_attribs): void
347 {
348 switch ($a_name) {
349 case 'ContentObject':
350 $this->current_object = $this->content_object;
351 if ($a_attribs['Type'] == 'Glossary') {
352 $this->glossary_object = $this->content_object;
353 }
354 break;
355
356 case 'StructureObject':
358 $lm = $this->content_object;
359 $this->structure_objects[count($this->structure_objects)]
360 = new ilStructureObject($lm);
361 $this->current_object = $this->structure_objects[count($this->structure_objects) - 1];
362 $this->current_object->setLMId($this->content_object->getId());
363 // new meta data handling: we create the structure
364 // object already here, this should also create a
365 // md entry
366 $this->current_object->create(true);
367 break;
368
369 case 'PageObject':
370 $this->in_page_object = true;
371 $this->cur_qid = '';
372 if ($this->content_type !== 'tst' && $this->content_type !== 'qpl') {
374 $lm = $this->content_object;
375 $this->lm_page_object = new ilLMPageObject($lm);
376 $this->page_object = new ilLMPage();
377 $this->lm_page_object->setLMId($this->content_object->getId());
378 $this->lm_page_object->assignPageObject($this->page_object);
379 $this->current_object = $this->lm_page_object;
380 } else {
381 $this->page_object = new ilAssQuestionPage();
382 }
383 break;
384
385 case 'PageAlias':
386 throw new ilLMException('Page Alias not supported.');
387
388 case 'MediaObject':
389 case 'InteractiveImage':
390 if ($a_name == 'MediaObject') {
391 $this->in_media_object = true;
392 }
393 $this->media_object = new ilObjMediaObject();
394 $this->media_object->create(false, false);
395 break;
396
397 case 'MediaAlias':
398 $this->media_object->setAlias(true);
399 $this->media_object->setImportId($a_attribs['OriginId']);
400 $this->mob_mapping[$this->media_object->getImportId()] = $this->media_object->getId();
401 if (is_object($this->page_object)) {
402 $this->page_object->needsImportParsing(true);
403 }
404 break;
405
406 case 'MediaItem':
407 case 'MediaAliasItem':
408 $this->in_media_item = true;
409 $this->media_item = new ilMediaItem();
410 $this->media_item->setPurpose($a_attribs['Purpose']);
411 break;
412
413 case 'Layout':
414 if (is_object($this->media_object) && $this->in_media_object) {
415 $this->media_item->setWidth($a_attribs['Width'] ?? '');
416 $this->media_item->setHeight($a_attribs['Height'] ?? '');
417 $this->media_item->setHAlign($a_attribs['HorizontalAlign'] ?? '');
418 }
419 break;
420
421 case 'Parameter':
422 if (is_object($this->media_object) && $this->in_media_object) {
423 $this->media_item->setParameter($a_attribs['Name'], $a_attribs['Value']);
424 }
425 break;
426
427 case 'MapArea':
428 $this->in_map_area = true;
429 $this->map_area = new ilMapArea();
430 $this->map_area->setShape($a_attribs['Shape']);
431 $this->map_area->setCoords($a_attribs['Coords']);
432 $this->map_area->setHighlightMode($a_attribs['HighlightMode']);
433 $this->map_area->setHighlightClass($a_attribs['HighlightClass']);
434 break;
435
436 case 'Glossary':
437 $this->in_glossary = true;
438 if ($this->content_object->getType() != 'glo') {
439 $this->glossary_object = new ilObjGlossary();
440 $this->glossary_object->setTitle('');
441 $this->glossary_object->setDescription('');
442 $this->glossary_object->create(true);
443 $this->glossary_object->createReference();
444 $parent = $this->tree->getParentNodeData($this->content_object->getRefId());
445 $this->glossary_object->putInTree($parent['child']);
446 $this->glossary_object->setPermissions($parent['child']);
447 }
448 $this->current_object = $this->glossary_object;
449 break;
450
451 case 'GlossaryItem':
452 $this->glossary_term = new ilGlossaryTerm();
453 $this->glossary_term->setGlossaryId($this->glossary_object->getId());
454 $this->glossary_term->setLanguage($a_attribs['Language']);
455 $this->glossary_term->setImportId($a_attribs['Id']);
456 $parsed = $this->parseLinkTarget((string) $a_attribs['Id']);
457 if (isset($parsed)) {
458 $this->link_targets[$a_attribs["Id"]] = $a_attribs['Id'];
459 }
460
461 // no break
462 case 'Definition':
463 $this->in_glossary_definition = true;
464 $this->page_object = new ilGlossaryDefPage();
465 $this->page_object->setParentId($this->glossary_term->getGlossaryId());
466 $this->glossary_term->assignPageObject($this->page_object);
467 $this->current_object = $this->glossary_term;
468 // see bug #12465, we need to clear xml after creation, since it will be <PageObject></PageObject>
469 // otherwise, and appendXML calls will lead to '<PageObject></PageObject><PageObject>....</PageObject>'
470 $this->page_object->setXMLContent('');
471 break;
472
473 case 'FileItem':
474 $this->in_file_item = true;
475 $this->file_item = new ilObjFile();
476 $this->file_item->setTitle('dummy');
477 $this->file_item->setMode('filelist');
478 if (is_object($this->page_object)) {
479 $this->page_object->needsImportParsing(true);
480 }
481 break;
482
483 case 'Paragraph':
484 if ($a_attribs['Characteristic'] == 'Code') {
485 $this->inside_code = true;
486 }
487 break;
488
489 case 'Properties':
490 $this->in_properties = true;
491 break;
492
493 case 'Property':
494 if ($this->content_object->getType() == 'lm') {
495 switch ($a_attribs['Name']) {
496 case 'Layout':
497 $this->content_object->setLayout($a_attribs['Value']);
498 break;
499
500 case 'PageHeader':
501 $this->content_object->setPageHeader($a_attribs['Value']);
502 break;
503
504 case 'TOCMode':
505 $this->content_object->setTOCMode($a_attribs['Value']);
506 break;
507
508 case 'ActiveLMMenu':
509 $this->content_object->setActiveLMMenu(
510 ilUtil::yn2tf($a_attribs['Value'])
511 );
512 break;
513
514 case 'ActiveNumbering':
515 $this->content_object->setActiveNumbering(
516 ilUtil::yn2tf($a_attribs['Value'])
517 );
518 break;
519
520 case 'ActiveTOC':
521 $this->content_object->setActiveTOC(
522 ilUtil::yn2tf($a_attribs['Value'])
523 );
524 break;
525
526 case 'ActivePrintView':
527 $this->content_object->setActivePrintView(
528 ilUtil::yn2tf($a_attribs['Value'])
529 );
530 break;
531
532 case 'CleanFrames':
533 $this->content_object->setCleanFrames(
534 ilUtil::yn2tf($a_attribs['Value'])
535 );
536 break;
537
538 case 'PublicNotes':
539 $this->content_object->setPublicNotes(
540 ilUtil::yn2tf($a_attribs['Value'])
541 );
542 break;
543
544 case 'HistoryUserComments':
545 $this->content_object->setHistoryUserComments(
546 ilUtil::yn2tf($a_attribs['Value'])
547 );
548 break;
549
550 case 'Rating':
551 $this->content_object->setRating(
552 ilUtil::yn2tf($a_attribs['Value'])
553 );
554 break;
555
556 case 'RatingPages':
557 $this->content_object->setRatingPages(
558 ilUtil::yn2tf($a_attribs['Value'])
559 );
560 break;
561
562 case 'HeaderPage':
563 if ($a_attribs['Value'] != '') {
564 if ($this->pg_mapping[$a_attribs['Value']] > 0) {
565 $this->content_object->setHeaderPage(
566 $this->pg_mapping[$a_attribs['Value']]
567 );
568 }
569 }
570 break;
571
572 case 'FooterPage':
573 if ($a_attribs['Value'] != '') {
574 if ($this->pg_mapping[$a_attribs['Value']] > 0) {
575 $this->content_object->setFooterPage(
576 $this->pg_mapping[$a_attribs['Value']]
577 );
578 }
579 }
580 break;
581
582 case 'LayoutPerPage':
583 $this->content_object->setLayoutPerPage($a_attribs['Value']);
584 break;
585
586 case 'ProgressIcons':
587 $this->content_object->setProgressIcons($a_attribs['Value']);
588 break;
589
590 case 'StoreTries':
591 $this->content_object->setStoreTries($a_attribs['Value']);
592 break;
593
594 case 'RestrictForwardNavigation':
595 $this->content_object->setRestrictForwardNavigation($a_attribs['Value']);
596 break;
597
598 case 'DisableDefaultFeedback':
599 $this->content_object->setDisableDefaultFeedback($a_attribs['Value']);
600 break;
601 }
602 }
603 break;
604
605 // Identifier
606 case 'Identifier':
607 if ($this->in_file_item) {
608 if (!isset($this->file_item_mapping[$a_attribs['Entry']])
609 || $this->file_item_mapping[$a_attribs['Entry']] === '') {
610 $this->file_item->create();
611 $this->file_item->setImportId($a_attribs['Entry']);
612 $this->file_item_mapping[$a_attribs['Entry']] = $this->file_item->getId();
613 }
614 }
615 if ($this->in_media_object) {
616 $mob_id = $this->mob_mapping[$a_attribs['Entry']];
617
618 // within learning module import, usually a media object
619 // has already been created with a media alias tag
620 if ($mob_id > 0) {
621 $this->media_object = new ilObjMediaObject($mob_id);
622 } else { // in glossaries the media objects precede the definitions
623 // so we don't have an object already
624 $this->media_object = new ilObjMediaObject();
625 $this->media_object->create(false, false);
626 $this->mob_mapping[$a_attribs['Entry']]
627 = $this->media_object->getId();
628 }
629 $this->media_object->setImportId($a_attribs['Entry']);
630 }
631 break;
632
633 // Internal Link
634 case 'IntLink':
635 if (is_object($this->page_object)) {
636 $this->page_object->setContainsIntLink(true);
637 }
638 if ($this->in_map_area) {
639 $this->map_area->setLinkType(IL_INT_LINK);
640 $this->map_area->setTarget($a_attribs['Target']);
641 $this->map_area->setType($a_attribs['Type']);
642 $this->map_area->setTargetFrame($a_attribs['TargetFrame']);
643 if (is_object($this->media_object)) {
644 $this->media_object->setContainsIntLink(true);
645 }
646 }
647 break;
648
649 // External Link
650 case 'ExtLink':
651 if ($this->in_map_area) {
652 $this->map_area->setLinkType(IL_EXT_LINK);
653 $this->map_area->setHref($a_attribs['Href']);
654 $this->map_area->setExtTitle($a_attribs['Title']);
655 }
656 break;
657
658 // Question
659 case 'Question':
660 $this->cur_qid = $a_attribs['QRef'];
661 $this->page_object->setContainsQuestion(true);
662 break;
663
664 case 'Location':
665 $this->loc_type = $a_attribs['Type'];
666 break;
667 }
668 $this->beginElement($a_name);
669
670 // append content to page xml content
671 if (($this->in_page_object || $this->in_glossary_definition)
672 && !$this->in_media_object) {
673 if ($a_name == 'Definition') {
674 $app_name = 'PageObject';
675 $app_attribs = [];
676 } else {
677 $app_name = $a_name;
678 $app_attribs = $a_attribs;
679 }
680
681 // change identifier entry of file items to new local file id
682 if ($this->in_file_item && $app_name == 'Identifier') {
683 $app_attribs['Entry'] = 'il__file_' . $this->file_item_mapping[$a_attribs['Entry']];
684 }
685
686 $this->page_object->appendXMLContent($this->buildTag('start', $app_name, $app_attribs));
687 }
688 }
689
690 public function processMeta(): bool
691 {
692 // do not process second meta block in (ilias3) glossaries
693 // which comes right after the 'Glossary' tag
694 if ($this->content_object->getType() == 'glo' &&
695 $this->in_glossary && !$this->in_media_object
696 && !$this->in_glossary_definition) {
697 return false;
698 }
699
700 return true;
701 }
702
703
704 public function handlerEndTag($a_xml_parser, string $a_name): void
705 {
706 // append content to page xml content
707 if (($this->in_page_object || $this->in_glossary_definition)
708 && !$this->in_media_object) {
709 $app_name = ($a_name == 'Definition')
710 ? 'PageObject'
711 : $a_name;
712 $this->page_object->appendXMLContent($this->buildTag('end', $app_name));
713 }
714
715 switch ($a_name) {
716 case 'StructureObject':
717 unset($this->structure_objects[count($this->structure_objects) - 1]);
718 break;
719
720 case 'PageObject':
721 $this->in_page_object = false;
722 if ($this->content_type != 'tst' && $this->content_type != 'qpl') {
723 //if (!$this->lm_page_object->isAlias()) {
724 $this->page_object->updateFromXML();
725 $this->pg_mapping[$this->lm_page_object->getImportId()]
726 = $this->lm_page_object->getId();
727
728 if ($this->mapping instanceof ilImportMapping) {
729 $import_id_parsed = ilUtil::parseImportId($this->lm_page_object->getImportId());
730 if ($import_id_parsed['type'] == 'pg') {
731 $this->mapping->addMapping(
732 'components/ILIAS/LearningModule',
733 'pg',
734 $import_id_parsed['id'],
735 $this->lm_page_object->getId()
736 );
737 }
738 }
739
740 // collect pages with internal links
741 if ($this->page_object->containsIntLink()) {
742 $this->pages_to_parse['lm:' . $this->page_object->getId()] = 'lm:' . $this->page_object->getId();
743 }
744
745 // collect pages with mobs or files
746 if ($this->page_object->needsImportParsing()) {
747 $this->pages_to_parse['lm:' . $this->page_object->getId()] = 'lm:' . $this->page_object->getId();
748 }
749
750 // collect pages with questions
751 if ($this->page_object->getContainsQuestion()) {
752 $this->pages_to_parse['lm:' . $this->page_object->getId()] = 'lm:' . $this->page_object->getId();
753 }
754 //}
755 } else {
756 $xml = $this->page_object->getXMLContent();
757 if ($this->cur_qid != '') {
758 $ids = $this->qst_mapping[$this->cur_qid] ?? ['pool' => 0, 'test' => 0];
759 if ($ids['pool'] > 0) {
760 // question pool question
761 $page = new ilAssQuestionPage($ids['pool']);
762 $xmlcontent = str_replace(
763 $this->cur_qid,
764 'il__qst_' . $ids['pool'],
765 $xml
766 );
767 $page->setXMLContent($xmlcontent);
768 $page->updateFromXML();
769 if ($this->page_object->needsImportParsing()) {
770 $this->pages_to_parse['qpl:' . $page->getId()] = 'qpl:' . $page->getId();
771 }
772 unset($page);
773 }
774 if ($ids['test'] > 0) {
775 // test question
776 $page = new ilAssQuestionPage($ids['test']);
777 $xmlcontent = str_replace(
778 $this->cur_qid,
779 'il__qst_' . $ids['test'],
780 $xml
781 );
782 $page->setXMLContent($xmlcontent);
783 $page->updateFromXML();
784 if ($this->page_object->needsImportParsing()) {
785 $this->pages_to_parse['qpl:' . $page->getId()] = 'qpl:' . $page->getId();
786 }
787 unset($page);
788 }
789 }
790 }
791
792 // if we are within a structure object: put page in tree
793 $cnt = count($this->structure_objects);
794 if ($cnt > 0) {
795 $parent_id = $this->structure_objects[$cnt - 1]->getId();
796 $this->pg_into_tree[$parent_id][] = ['type' => 'pg', 'id' => $this->lm_page_object->getId()];
797 }
798
799 unset($this->page_object);
800 unset($this->lm_page_object);
801 unset($this->container[count($this->container) - 1]);
802 break;
803
804 case 'MediaObject':
805 case 'InteractiveImage':
806 if ($a_name == 'MediaObject') {
807 $this->in_media_object = false;
808 }
809
810 if (empty($this->mob_mapping[$this->media_object->getImportId()])) {
811 // create media object
812 // media items are saves for mobs outside of
813 // pages only
814 $this->media_object->create(false, false);
815
816 // collect mobs with internal links
817 if ($this->media_object->containsIntLink()) {
818 $this->mobs_with_int_links[] = $this->media_object->getId();
819 }
820
821 $this->mob_mapping[$this->media_object->getImportId()]
822 = $this->media_object->getId();
823 } else {
824 // get the id from mapping
825 $this->media_object->setId($this->mob_mapping[$this->media_object->getImportId()]);
826
827 // update 'real' (no alias) media object
828 // (note: we overwrite any data from the media object
829 // created by an MediaAlias, only the data of the real
830 // object is stored in db separately; data of the
831 // MediaAliases are within the page XML
832 if (!$this->media_object->isAlias()) {
833 // now the media items are saved within the db
834 $this->media_object->update();
835
836 // collect mobs with internal links
837 if ($this->media_object->containsIntLink()) {
838 $this->mobs_with_int_links[] = $this->media_object->getId();
839 }
840 }
841 }
842
843 // append media alias to page, if we are in a page
844 if ($this->in_page_object || $this->in_glossary_definition) {
845 if ($a_name != 'InteractiveImage') {
846 $this->page_object->appendXMLContent($this->media_object->getXML(IL_MODE_ALIAS));
847 }
848 }
849
850 break;
851
852 case 'MediaAliasItem':
853 $this->in_media_item = false;
854 $this->media_object->addMediaItem($this->media_item);
855 break;
856 case 'MediaItem':
857 $this->in_media_item = false;
858 $import_dir = $this->importdir . DIRECTORY_SEPARATOR . 'objects' . DIRECTORY_SEPARATOR . $this->media_object->getImportId();
859 if (!file_exists($import_dir)
860 || !is_dir($import_dir)) {
861 $this->media_object->addMediaItem($this->media_item);
862 break;
863 }
864
865 $dir_handle = opendir($import_dir);
866 while (($file = readdir($dir_handle)) !== false) {
867 if ($file !== $this->media_item->getLocation()) {
868 continue;
869 }
870
871 $this->media_object->addMediaItemFromLocalFile(
872 $this->media_item->getPurpose(),
873 $import_dir . DIRECTORY_SEPARATOR . $file,
874 $file
875 );
876 break;
877 }
878 closedir($dir_handle);
879 break;
880
881 case 'MapArea':
882 $this->in_map_area = false;
883 $this->media_item->addMapArea($this->map_area);
884 break;
885
886 case 'Properties':
887 $this->in_properties = false;
888 if ($this->content_object->getType() == 'lm') {
889 $this->content_object->update();
890 }
891 break;
892
893 case 'FileItem':
894 $this->in_file_item = false;
895 // only update new file items
896 if ($this->file_item->getImportId()) {
897 $this->file_item->update();
898 }
899 break;
900
901
902 case 'Table':
903 unset($this->container[count($this->container) - 1]);
904 break;
905
906 case 'Glossary':
907 $this->in_glossary = false;
908 break;
909
910 case 'GlossaryTerm':
911 $term = trim($this->chr_data);
912 $term = str_replace('&lt;', '<', $term);
913 $term = str_replace('&gt;', '>', $term);
914 $this->glossary_term->setTerm($term);
915 $this->glossary_term->create();
916 $iia = explode('_', $this->glossary_term->getImportId());
917 $this->glossary_term_map[(int) $iia[count($iia) - 1]] = $this->glossary_term->getId();
918 break;
919
920 case 'Paragraph':
921 $this->inside_code = false;
922 break;
923
924 case 'Definition':
925 $this->in_glossary_definition = false;
926 $this->page_object->updateFromXML();
927 $this->page_object->buildDom();
928 $this->glossary_term->setShortText($this->page_object->getFirstParagraphText());
929 $this->glossary_term->update();
930 if ($this->page_object->containsIntLink()) {
931 $this->pages_to_parse['term:' . $this->page_object->getId()] = 'term:' . $this->page_object->getId();
932 }
933 if ($this->page_object->needsImportParsing()) {
934 $this->pages_to_parse['term:' . $this->page_object->getId()] = 'term:' . $this->page_object->getId();
935 }
936 break;
937
938 case 'Format':
939 if ($this->in_media_item) {
940 $this->media_item->setFormat(trim($this->chr_data));
941 }
942 break;
943
944 case 'Title':
945 if ($this->in_media_object) {
946 $this->media_object->setTitle(trim($this->chr_data));
947 }
948 break;
949
950 case 'Description':
951 case 'Language':
952 break;
953
954 case 'Caption':
955 if ($this->in_media_object) {
956 $this->media_item->setCaption(trim($this->chr_data));
957 }
958 break;
959
960 case 'TextRepresentation':
961 if ($this->in_media_object) {
962 $this->media_item->setTextRepresentation(trim($this->chr_data));
963 }
964 break;
965
966 // Location
967 case 'Location':
968 // TODO: adapt for files in 'real' subdirectories
969 if ($this->in_media_item) {
970 $this->media_item->setLocationType($this->loc_type);
971 if ($this->loc_type == 'Reference') {
972 $this->media_item->setLocation(str_replace('&', '&amp;', trim($this->chr_data)));
973 } else {
974 $this->media_item->setLocation(trim($this->chr_data));
975 }
976 }
977 if ($this->in_file_item) {
978 // set file name from xml file
979 $this->file_item->setFileName(trim($this->chr_data));
980
981 // special handling for file names with special characters
982 // (e.g. '&gt;')
983 if ($this->file_item->getType() == 'file' &&
984 is_int(strpos($this->chr_data, '&')) &&
985 is_int(strpos($this->chr_data, ';'))) {
986 $source_dir = $this->importdir . DIRECTORY_SEPARATOR . 'objects' . DIRECTORY_SEPARATOR .
987 $this->file_item->getImportId();
988
989 // read 'physical' file name from directory
990 if ($dir = opendir($source_dir)) {
991 while (false !== ($file = readdir($dir))) {
992 if ($file != '.' && $file != '..') {
993 $this->file_item->setFileName($file);
994 }
995 }
996 closedir($dir);
997 }
998 }
999
1000 // set file item title
1001 $this->file_item->setTitle(trim($this->chr_data));
1002 }
1003 break;
1004 }
1005 $this->endElement($a_name);
1006 $this->chr_data = '';
1007 }
1008
1009 public function handlerCharacterData($a_xml_parser, string $a_data): void
1010 {
1011 // the parser converts '&gt;' to '>' and '&lt;' to '<'
1012 // in character data, but we don't want that, because it's the
1013 // way we mask user html in our content, so we convert back...
1014
1015 $a_data = str_replace('<', '&lt;', $a_data);
1016 $a_data = str_replace('>', '&gt;', $a_data);
1017
1018
1019 // DELETE WHITESPACES AND NEWLINES OF CHARACTER DATA
1020 $a_data = preg_replace('/\n/', '', $a_data);
1021 if (!$this->inside_code) {
1022 $a_data = preg_replace('/\t+/', '', $a_data);
1023 }
1024
1025 $this->chr_data .= $a_data;
1026
1027 if (!empty($a_data) || $a_data === '0') {
1028 // append all data to page, if we are within PageObject,
1029 // but not within MetaData or MediaObject
1030 if (($this->in_page_object || $this->in_glossary_definition)
1031 && !$this->in_media_object) {
1032 $this->page_object->appendXMLContent($a_data);
1033 }
1034
1035 switch ($this->getCurrentElement()) {
1036 case 'IntLink':
1037 case 'ExtLink':
1038 if ($this->in_map_area) {
1039 $this->map_area->appendTitle($a_data);
1040 }
1041 break;
1042 }
1043 }
1044 }
1045
1049 public function getGlossaryTermMap(): array
1050 {
1051 return $this->glossary_term_map;
1052 }
1053
1059 private function parseLinkTarget(string $identifier): ?array
1060 {
1061 $link_arr = explode('_', $identifier);
1062
1063 if (count($link_arr) !== 4
1064 || $link_arr[0] !== 'il'
1065 || !is_numeric($link_arr[1])
1066 || !is_numeric($link_arr[3])
1067 ) {
1068 return null;
1069 }
1070
1071 return [
1072 'target_inst' => (int) $link_arr[1],
1073 'target_type' => (string) $link_arr[2],
1074 'target_id' => (int) $link_arr[3]
1075 ];
1076 }
1077}
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
const IL_INT_LINK
const IL_EXT_LINK
const IL_MODE_ALIAS
static instantiateQuestion(int $question_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
write(string $message, $level=ilLogLevel::INFO, array $context=[])
write log message
Class ilMapArea.
Class ilMediaItem Media Item, component of a media object (file or reference)
static _resolveMapAreaLinks(int $a_mob_id)
resolve internal links of all media items of a media object
Class ilObjFile.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilObject Basic functions for all objects.
static getInstance(string $a_parent_type, int $a_id=0, int $a_old_nr=0, string $a_lang="-")
Get page object instance.
Class ilPageObject Handles PageObjects of ILIAS Learning Modules (see ILIAS DTD)
update(bool $a_validate=true, bool $a_no_history=false)
update complete page content in db (dom xml content is used)
resolveIntLinks(?array $a_link_map=null)
Resolves all internal link targets of the page, if targets are available (after import)
static _exists(string $a_parent_type, int $a_id, string $a_lang="", bool $a_no_cache=false)
Checks whether page exists.
buildDom(bool $a_force=false)
Legacy Content Object Parser.
ilObjLearningModule $learning_module
copyFileItems()
copy files of file items
processPagesToParse()
parse pages that contain files, mobs and/or internal links
startParsing()
stores xml data in array
__construct(private readonly ilObject $content_object, string $xml_file, private readonly string $importdir)
handlerCharacterData($a_xml_parser, string $a_data)
setImportMapping(?ilImportMapping $mapping=null)
storeTree()
insert StructureObjects and PageObjects into tree
handlerEndTag($a_xml_parser, string $a_name)
parseLinkTarget(string $identifier)
Parse a string the get the elements of a link target Return null if the string is not a link target.
buildTag(string $type, string $name, array $attr=[])
setQuestionMapping(array $a_map)
set question import ident to pool/test question id mapping
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ilLanguage $lng
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
static parseImportId(string $a_import_id)
Parse an ilias import id Typically of type il_[IL_INST_ID]_[OBJ_TYPE]_[OBJ_ID] returns array( 'orig' ...
static yn2tf(string $a_yn)
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26