ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilObjContentObject.php
Go to the documentation of this file.
1 <?php
2 
24 {
25  protected \ILIAS\Notes\Service $notes;
26  protected array $q_ids = [];
27  protected array $mob_ids = [];
28  protected array $file_ids = [];
29  protected array $public_export_file = [];
30  protected int $header_page = 0;
31  protected int $footer_page = 0;
32  protected bool $user_comments = false;
33  protected bool $clean_frames = false;
34  protected bool $pub_notes = false;
35  protected bool $downloads_public_active = false;
36  protected bool $downloads_active = false;
37  protected bool $hide_header_footer_print = false;
38  protected bool $prevent_glossary_appendix_active = false;
39  protected bool $print_view_active = false;
40  protected bool $numbering = false;
41  protected bool $toc_active = false;
42  protected bool $lm_menu_active = false;
43  protected string $public_access_mode = '';
44  protected string $toc_mode = '';
45  protected bool $restrict_forw_nav = false;
46  protected bool $store_tries = false;
47  protected bool $progr_icons = false;
48  protected bool $disable_def_feedback = false;
49  protected bool $layout_per_page = false;
50  protected ilObjUser $user;
53  public string $layout = '';
54  public int $style_id = 0;
55  public string $pg_header = '';
56  public bool $online = false;
57  public bool $for_translation = false;
58  protected bool $rating = false;
59  protected bool $rating_pages = false;
60  public array $auto_glossaries = array();
61  private string $import_dir = '';
63  protected \ILIAS\Style\Content\DomainService $content_style_domain;
64  private \ilGlobalTemplateInterface $main_tpl;
65 
66  public function __construct(
67  int $a_id = 0,
68  bool $a_call_by_reference = true
69  ) {
70  global $DIC;
71  $this->main_tpl = $DIC->ui()->mainTemplate();
72 
73  $this->user = $DIC->user();
74  $this->db = $DIC->database();
75  $this->tree = $DIC->repositoryTree();
76  $this->lng = $DIC->language();
77  $this->error = $DIC["ilErr"];
78  if (isset($DIC["ilLocator"])) {
79  $this->locator = $DIC["ilLocator"];
80  }
81 
82  $this->notes = $DIC->notes();
83 
84  // this also calls read() method! (if $a_id is set)
85  parent::__construct($a_id, $a_call_by_reference);
86 
87  $this->log = ilLoggerFactory::getLogger('lm');
88 
90  $lm = $this;
91  $this->lm = $lm;
92 
93  $this->mob_ids = array();
94  $this->file_ids = array();
95  $this->q_ids = array();
96  $cs = $DIC->contentStyle();
97  $this->content_style_domain = $cs->domain();
98  }
99 
103  public function create(
104  bool $a_no_meta_data = false
105  ): int {
106  $id = parent::create();
107 
108  // meta data will be created by
109  // import parser
110  if (!$a_no_meta_data) {
111  $this->createMetaData();
112  }
113 
114  $this->createProperties();
115  $this->updateAutoGlossaries();
116  return $id;
117  }
118 
119  public function read(): void
120  {
121  $ilDB = $this->db;
122 
123  parent::read();
124 
125  $this->lm_tree = new ilLMTree($this->getId());
126 
127  $this->readProperties();
128 
129  // read auto glossaries
130  $set = $ilDB->query(
131  "SELECT * FROM lm_glossaries " .
132  " WHERE lm_id = " . $ilDB->quote($this->getId(), "integer")
133  );
134  $glos = array();
135  while ($rec = $ilDB->fetchAssoc($set)) {
136  $glos[] = $rec["glo_id"];
137  }
138  $this->setAutoGlossaries($glos);
139  }
140 
141  public function setLayoutPerPage(bool $a_val): void
142  {
143  $this->layout_per_page = $a_val;
144  }
145 
146  public function getLayoutPerPage(): bool
147  {
148  return $this->layout_per_page;
149  }
150 
154  public function setDisableDefaultFeedback(bool $a_val): void
155  {
156  $this->disable_def_feedback = $a_val;
157  }
158 
159  public function getDisableDefaultFeedback(): bool
160  {
162  }
163 
164  public function setProgressIcons(bool $a_val): void
165  {
166  $this->progr_icons = $a_val;
167  }
168 
169  public function getProgressIcons(): bool
170  {
171  return $this->progr_icons;
172  }
173 
174  public function setStoreTries(bool $a_val): void
175  {
176  $this->store_tries = $a_val;
177  }
178 
179  public function getStoreTries(): bool
180  {
181  return $this->store_tries;
182  }
183 
184  public function setRestrictForwardNavigation(bool $a_val): void
185  {
186  $this->restrict_forw_nav = $a_val;
187  }
188 
189  public function getRestrictForwardNavigation(): bool
190  {
192  }
193 
194  public function getTree(): ilLMTree
195  {
196  return $this->lm_tree;
197  }
198 
199  public function update(): bool
200  {
201  $this->updateMetaData();
202  parent::update();
203  $this->updateProperties();
204  $this->updateAutoGlossaries();
205  return true;
206  }
207 
208  public function updateAutoGlossaries(): void
209  {
210  $ilDB = $this->db;
211 
212  // update auto glossaries
213  $ilDB->manipulate(
214  "DELETE FROM lm_glossaries WHERE " .
215  " lm_id = " . $ilDB->quote($this->getId(), "integer")
216  );
217  foreach ($this->getAutoGlossaries() as $glo_id) {
218  $ilDB->manipulate("INSERT INTO lm_glossaries " .
219  "(lm_id, glo_id) VALUES (" .
220  $ilDB->quote($this->getId(), "integer") . "," .
221  $ilDB->quote($glo_id, "integer") .
222  ")");
223  }
224  }
225 
226 
230  public function import(): void
231  {
232  // nothing to do. just display the dialogue in Out
233  }
234 
235  public function createLMTree(): void
236  {
237  $this->lm_tree = new ilLMTree($this->getId(), false);
238  $this->lm_tree->addTree($this->getId(), 1);
239  }
240 
241  public function setAutoGlossaries(array $a_val): void
242  {
243  $this->auto_glossaries = array();
244  if (is_array($a_val)) {
245  foreach ($a_val as $v) {
246  $v = (int) $v;
247  if ($v > 0 && ilObject::_lookupType($v) == "glo" &&
248  !in_array($v, $this->auto_glossaries)) {
249  $this->auto_glossaries[] = $v;
250  }
251  }
252  }
253  }
254 
255  public function getAutoGlossaries(): array
256  {
257  return $this->auto_glossaries;
258  }
259 
260  public function removeAutoGlossary(int $a_glo_id): void
261  {
262  $glo_ids = array();
263  foreach ($this->getAutoGlossaries() as $g) {
264  if ($g != $a_glo_id) {
265  $glo_ids[] = $g;
266  }
267  }
268  $this->setAutoGlossaries($glo_ids);
269  }
270 
271  public function addFirstChapterAndPage(): void
272  {
273  $lng = $this->lng;
274 
275 
276  $root_id = $this->lm_tree->getRootId();
277 
278  // chapter
279  $chap = new ilStructureObject($this->lm);
280  $chap->setType("st");
281  $chap->setTitle($lng->txt("cont_new_chap"));
282  $chap->setLMId($this->getId());
283  $chap->create();
285 
286  // page
288  $lm = $this;
289  $page = new ilLMPageObject($lm);
290  $page->setType("pg");
291  $page->setTitle($lng->txt("cont_new_page"));
292  $page->setLMId($this->getId());
293  $page->create();
294  ilLMObject::putInTree($page, $chap->getId(), ilTree::POS_FIRST_NODE);
295  }
296 
300  public function setForTranslation(bool $a_val): void
301  {
302  $this->for_translation = $a_val;
303  }
304 
305  public function getForTranslation(): bool
306  {
307  return $this->for_translation;
308  }
309 
310  public function getLMTree(): ilLMTree
311  {
312  return $this->lm_tree;
313  }
314 
315 
321  public function createImportDirectory(): void
322  {
324 
325  $lm_data_dir = ilFileUtils::getDataDir() . "/lm_data";
326  if (!is_writable($lm_data_dir)) {
327  $ilErr->raiseError("Content object Data Directory (" . $lm_data_dir
328  . ") not writeable.", $ilErr->FATAL);
329  }
330 
331  // create learning module directory (data_dir/lm_data/lm_<id>)
332  $lm_dir = $lm_data_dir . "/lm_" . $this->getId();
333  ilFileUtils::makeDir($lm_dir);
334  if (!is_dir($lm_dir)) {
335  $ilErr->raiseError("Creation of Learning Module Directory failed.", $ilErr->FATAL);
336  }
337 
338  // create import subdirectory (data_dir/lm_data/lm_<id>/import)
339  $import_dir = $lm_dir . "/import";
340  ilFileUtils::makeDir($import_dir);
341  if (!is_dir($import_dir)) {
342  $ilErr->raiseError("Creation of Import Directory failed.", $ilErr->FATAL);
343  }
344  }
345 
346  public function getDataDirectory(): string
347  {
348  return ilFileUtils::getDataDir() . "/lm_data" .
349  "/lm_" . $this->getId();
350  }
351 
352  public function getImportDirectory(): string
353  {
354  if (strlen($this->import_dir)) {
355  return $this->import_dir;
356  }
357 
358  $import_dir = ilFileUtils::getDataDir() . "/lm_data" .
359  "/lm_" . $this->getId() . "/import";
360  if (is_dir($import_dir)) {
361  return $import_dir;
362  }
363  return "";
364  }
365 
366  public function setImportDirectory(string $a_import_dir): void
367  {
368  $this->import_dir = $a_import_dir;
369  }
370 
371 
377  public function createExportDirectory(
378  string $a_type = "xml"
379  ): void {
381 
382  $lm_data_dir = ilFileUtils::getDataDir() . "/lm_data";
383  // create learning module directory (data_dir/lm_data/lm_<id>)
384  $lm_dir = $lm_data_dir . "/lm_" . $this->getId();
386  if (!is_dir($lm_dir)) {
387  $ilErr->raiseError("Creation of Learning Module Directory failed.", $ilErr->FATAL);
388  }
389  // create Export subdirectory (data_dir/lm_data/lm_<id>/Export)
390  switch ($a_type) {
391  default: // = xml
392  if (substr($a_type, 0, 4) == "html") {
393  $export_dir = $lm_dir . "/export_" . $a_type;
394  } else {
395  $export_dir = $lm_dir . "/export";
396  }
397  break;
398  }
399  ilFileUtils::makeDir($export_dir);
400 
401  if (!is_dir($export_dir)) {
402  $ilErr->raiseError("Creation of Export Directory failed.", $ilErr->FATAL);
403  }
404  }
405 
406  public function getExportDirectory(
407  string $a_type = "xml"
408  ): string {
409  switch ($a_type) {
410  default: // = xml
411  if (substr($a_type, 0, 4) == "html") {
412  $export_dir = ilFileUtils::getDataDir() . "/lm_data" . "/lm_" . $this->getId() . "/export_" . $a_type;
413  } else {
414  $export_dir = ilFileUtils::getDataDir() . "/lm_data" . "/lm_" . $this->getId() . "/export";
415  }
416  break;
417  }
418  return $export_dir;
419  }
420 
421 
430  public function delete(): bool
431  {
432  $ilDB = $this->db;
433 
434  // always call parent delete function first!!
435  if (!parent::delete()) {
436  return false;
437  }
438 
439  // delete lm object data
441  $lm = $this;
443 
444  // delete meta data of content object
445  $this->deleteMetaData();
446 
447 
448  // delete learning module tree
449  $this->lm_tree->removeTree($this->lm_tree->getTreeId());
450 
451  // delete data directory
453 
454  // delete content object record
455  $q = "DELETE FROM content_object WHERE id = " .
456  $ilDB->quote($this->getId(), "integer");
457  $ilDB->manipulate($q);
458 
459  // delete lm menu entries
460  $q = "DELETE FROM lm_menu WHERE lm_id = " .
461  $ilDB->quote($this->getId(), "integer");
462  $ilDB->manipulate($q);
463 
464  // remove auto glossary entries
465  $ilDB->manipulate(
466  "DELETE FROM lm_glossaries WHERE " .
467  " lm_id = " . $ilDB->quote($this->getId(), "integer")
468  );
469 
470 
471  return true;
472  }
473 
474  public function getLayout(): string
475  {
476  return $this->layout;
477  }
478 
479  public function setLayout(string $a_layout): void
480  {
481  $this->layout = $a_layout;
482  }
483 
484  public static function writeHeaderPage(
485  int $a_lm_id,
486  int $a_page_id
487  ): void {
488  global $DIC;
489 
490  $ilDB = $DIC->database();
491 
492  $ilDB->manipulate(
493  "UPDATE content_object SET " .
494  " header_page = " . $ilDB->quote($a_page_id, "integer") .
495  " WHERE id = " . $ilDB->quote($a_lm_id, "integer")
496  );
497  }
498 
499  public static function writeFooterPage(
500  int $a_lm_id,
501  int $a_page_id
502  ): void {
503  global $DIC;
504 
505  $ilDB = $DIC->database();
506 
507  $ilDB->manipulate(
508  "UPDATE content_object SET " .
509  " footer_page = " . $ilDB->quote($a_page_id, "integer") .
510  " WHERE id = " . $ilDB->quote($a_lm_id, "integer")
511  );
512  }
513 
514 
518  public static function _moveLMStyles(
519  int $a_from_style,
520  int $a_to_style
521  ): void {
522  global $DIC;
523 
524  $ilDB = $DIC->database();
525 
526  if ($a_from_style < 0) { // change / delete all individual styles
527  $q = "SELECT stylesheet FROM content_object, style_data " .
528  " WHERE content_object.stylesheet = style_data.id " .
529  " AND style_data.standard = " . $ilDB->quote(0, "integer") .
530  " AND content_object.stylesheet > " . $ilDB->quote(0, "integer");
531  $style_set = $ilDB->query($q);
532  while ($style_rec = $ilDB->fetchAssoc($style_set)) {
533  // assign learning modules to new style
534  $q = "UPDATE content_object SET " .
535  " stylesheet = " . $ilDB->quote($a_to_style, "integer") .
536  " WHERE stylesheet = " . $ilDB->quote($style_rec["stylesheet"], "integer");
537  $ilDB->manipulate($q);
538 
539  // delete style
540  $style_obj = ilObjectFactory::getInstanceByObjId($style_rec["stylesheet"]);
541  $style_obj->delete();
542  }
543  } else {
544  $q = "UPDATE content_object SET " .
545  " stylesheet = " . $ilDB->quote($a_to_style, "integer") .
546  " WHERE stylesheet = " . $ilDB->quote($a_from_style, "integer");
547  $ilDB->manipulate($q);
548  }
549  }
550 
551  protected static function _lookup(
552  int $a_obj_id,
553  string $a_field
554  ): string {
555  global $DIC;
556 
557  $ilDB = $DIC->database();
558 
559  $q = "SELECT " . $a_field . " FROM content_object " .
560  " WHERE id = " . $ilDB->quote($a_obj_id, "integer");
561 
562  $res = $ilDB->query($q);
563  $rec = $ilDB->fetchAssoc($res);
564 
565  return $rec[$a_field];
566  }
567 
568  public static function _lookupRestrictForwardNavigation(
569  int $a_obj_id
570  ): string {
571  return self::_lookup($a_obj_id, "restrict_forw_nav");
572  }
573 
574  public static function _lookupStyleSheetId(int $a_cont_obj_id): int
575  {
576  global $DIC;
577 
578  $ilDB = $DIC->database();
579 
580  $q = "SELECT stylesheet FROM content_object " .
581  " WHERE id = " . $ilDB->quote($a_cont_obj_id, "integer");
582  $res = $ilDB->query($q);
583  $sheet = $ilDB->fetchAssoc($res);
584 
585  return (int) $sheet["stylesheet"];
586  }
587 
588  public static function _lookupContObjIdByStyleId(int $a_style_id): array
589  {
590  global $DIC;
591 
592  $ilDB = $DIC->database();
593 
594  $q = "SELECT id FROM content_object " .
595  " WHERE stylesheet = " . $ilDB->quote($a_style_id, "integer");
596  $res = $ilDB->query($q);
597  $obj_ids = array();
598  while ($cont = $ilDB->fetchAssoc($res)) {
599  $obj_ids[] = (int) $cont["id"];
600  }
601  return $obj_ids;
602  }
603 
604  public static function _lookupDisableDefaultFeedback(int $a_id): bool
605  {
606  global $DIC;
607 
608  $ilDB = $DIC->database();
609 
610  $q = "SELECT disable_def_feedback FROM content_object " .
611  " WHERE id = " . $ilDB->quote($a_id, "integer");
612  $res = $ilDB->query($q);
613  $rec = $ilDB->fetchAssoc($res);
614 
615  return (bool) ($rec["disable_def_feedback"] ?? false);
616  }
617 
618  public static function _lookupStoreTries(int $a_id): bool
619  {
620  global $DIC;
621 
622  $ilDB = $DIC->database();
623 
624  $q = "SELECT store_tries FROM content_object " .
625  " WHERE id = " . $ilDB->quote($a_id, "integer");
626  $res = $ilDB->query($q);
627  $rec = $ilDB->fetchAssoc($res);
628 
629  return (bool) ($rec["store_tries"] ?? false);
630  }
631 
632 
636  public static function _getNrOfAssignedLMs(int $a_style_id): int
637  {
638  global $DIC;
639 
640  $ilDB = $DIC->database();
641 
642  $q = "SELECT count(*) as cnt FROM content_object " .
643  " WHERE stylesheet = " . $ilDB->quote($a_style_id, "integer");
644  $cset = $ilDB->query($q);
645  $crow = $ilDB->fetchAssoc($cset);
646 
647  return (int) ($crow["cnt"] ?? 0);
648  }
649 
650 
654  public static function _getNrLMsIndividualStyles(): int
655  {
656  global $DIC;
657 
658  $ilDB = $DIC->database();
659 
660  // joining with style table (not perfectly nice)
661  $q = "SELECT count(*) as cnt FROM content_object, style_data " .
662  " WHERE stylesheet = style_data.id " .
663  " AND standard = " . $ilDB->quote(0, "integer");
664  $cset = $ilDB->query($q);
665  $crow = $ilDB->fetchAssoc($cset);
666 
667  return (int) $crow["cnt"];
668  }
669 
673  public static function _getNrLMsNoStyle(): int
674  {
675  global $DIC;
676 
677  $ilDB = $DIC->database();
678 
679  $q = "SELECT count(*) as cnt FROM content_object " .
680  " WHERE stylesheet = " . $ilDB->quote(0, "integer");
681  $cset = $ilDB->query($q);
682  $crow = $ilDB->fetchAssoc($cset);
683 
684  return (int) $crow["cnt"];
685  }
686 
690  public static function _deleteStyleAssignments(
691  int $a_style_id
692  ): void {
693  global $DIC;
694 
695  $ilDB = $DIC->database();
696 
697  $q = "UPDATE content_object SET " .
698  " stylesheet = " . $ilDB->quote(0, "integer") .
699  " WHERE stylesheet = " . $ilDB->quote($a_style_id, "integer");
700 
701  $ilDB->manipulate($q);
702  }
703 
707  public function getPageHeader(): string
708  {
709  return $this->pg_header;
710  }
711 
716  public function setPageHeader(
717  string $a_pg_header = ilLMObject::CHAPTER_TITLE
718  ): void {
719  $this->pg_header = $a_pg_header;
720  }
721 
725  public function getTOCMode(): string
726  {
727  return $this->toc_mode;
728  }
729 
733  public function getPublicAccessMode(): string
734  {
736  }
737 
742  public function setTOCMode(string $a_toc_mode = "chapters"): void
743  {
744  $this->toc_mode = $a_toc_mode;
745  }
746 
747  public function setActiveLMMenu(bool $a_act_lm_menu): void
748  {
749  $this->lm_menu_active = $a_act_lm_menu;
750  }
751 
752  public function isActiveLMMenu(): bool
753  {
754  return $this->lm_menu_active;
755  }
756 
757  public function setActiveTOC(bool $a_toc): void
758  {
759  $this->toc_active = $a_toc;
760  }
761 
762  public function isActiveTOC(): bool
763  {
764  return $this->toc_active;
765  }
766 
767  public function setActiveNumbering(bool $a_num): void
768  {
769  $this->numbering = $a_num;
770  }
771 
772  public function isActiveNumbering(): bool
773  {
774  return $this->numbering;
775  }
776 
777  public function setActivePrintView(bool $a_print): void
778  {
779  $this->print_view_active = $a_print;
780  }
781 
782  public function isActivePrintView(): bool
783  {
785  }
786 
787  public function setActivePreventGlossaryAppendix(bool $a_print): void
788  {
789  $this->prevent_glossary_appendix_active = $a_print;
790  }
791 
792  public function isActivePreventGlossaryAppendix(): bool
793  {
795  }
796 
800  public function setHideHeaderFooterPrint(bool $a_val): void
801  {
802  $this->hide_header_footer_print = $a_val;
803  }
804 
805  public function getHideHeaderFooterPrint(): bool
806  {
808  }
809 
810  public function setActiveDownloads(bool $a_down): void
811  {
812  $this->downloads_active = $a_down;
813  }
814 
815  public function isActiveDownloads(): bool
816  {
818  }
819 
820  public function setActiveDownloadsPublic(bool $a_down): void
821  {
822  $this->downloads_public_active = $a_down;
823  }
824 
825  public function isActiveDownloadsPublic(): bool
826  {
828  }
829 
830  public function setPublicNotes(bool $a_pub_notes): void
831  {
832  $this->pub_notes = $a_pub_notes;
833  }
834 
835  public function publicNotes(): bool
836  {
837  return $this->pub_notes;
838  }
839 
840  public function setCleanFrames(bool $a_clean): void
841  {
842  $this->clean_frames = $a_clean;
843  }
844 
845  public function cleanFrames(): bool
846  {
847  return $this->clean_frames;
848  }
849 
850  public function setHistoryUserComments(bool $a_comm): void
851  {
852  $this->user_comments = $a_comm;
853  }
854 
855  public function setPublicAccessMode(string $a_mode): void
856  {
857  $this->public_access_mode = $a_mode;
858  }
859 
860  public function isActiveHistoryUserComments(): bool
861  {
862  return $this->user_comments;
863  }
864 
865  public function setHeaderPage(int $a_pg): void
866  {
867  $this->header_page = $a_pg;
868  }
869 
870  public function getHeaderPage(): int
871  {
872  return $this->header_page;
873  }
874 
875  public function setFooterPage(int $a_pg): void
876  {
877  $this->footer_page = $a_pg;
878  }
879 
880  public function getFooterPage(): int
881  {
882  return $this->footer_page;
883  }
884 
885  public function readProperties(): void
886  {
887  $ilDB = $this->db;
888 
889  $q = "SELECT * FROM content_object WHERE id = " .
890  $ilDB->quote($this->getId(), "integer");
891  $lm_set = $ilDB->query($q);
892  $lm_rec = $ilDB->fetchAssoc($lm_set);
893  $this->setLayout((string) $lm_rec["default_layout"]);
894  $this->setPageHeader((string) $lm_rec["page_header"]);
895  $this->setTOCMode((string) $lm_rec["toc_mode"]);
896  $this->setActiveTOC(ilUtil::yn2tf($lm_rec["toc_active"]));
897  $this->setActiveNumbering(ilUtil::yn2tf($lm_rec["numbering"]));
898  $this->setActivePrintView(ilUtil::yn2tf($lm_rec["print_view_active"]));
899  $this->setActivePreventGlossaryAppendix(ilUtil::yn2tf($lm_rec["no_glo_appendix"]));
900  $this->setHideHeaderFooterPrint((bool) $lm_rec["hide_head_foot_print"]);
901  $this->setActiveDownloads(ilUtil::yn2tf($lm_rec["downloads_active"]));
902  $this->setActiveDownloadsPublic(ilUtil::yn2tf($lm_rec["downloads_public_active"]));
903  $this->setActiveLMMenu(ilUtil::yn2tf($lm_rec["lm_menu_active"]));
904  $this->setCleanFrames(ilUtil::yn2tf($lm_rec["clean_frames"]));
905  $this->setHeaderPage((int) $lm_rec["header_page"]);
906  $this->setFooterPage((int) $lm_rec["footer_page"]);
907  $this->setHistoryUserComments(ilUtil::yn2tf($lm_rec["hist_user_comments"]));
908  $this->setPublicAccessMode((string) $lm_rec["public_access_mode"]);
909  $this->setPublicExportFile("xml", (string) $lm_rec["public_xml_file"]);
910  $this->setPublicExportFile("html", (string) $lm_rec["public_html_file"]);
911  $this->setLayoutPerPage((bool) $lm_rec["layout_per_page"]);
912  $this->setRating((bool) $lm_rec["rating"]);
913  $this->setRatingPages((bool) $lm_rec["rating_pages"]);
914  $this->setDisableDefaultFeedback((bool) $lm_rec["disable_def_feedback"]);
915  $this->setProgressIcons((bool) $lm_rec["progr_icons"]);
916  $this->setStoreTries((bool) $lm_rec["store_tries"]);
917  $this->setRestrictForwardNavigation((bool) $lm_rec["restrict_forw_nav"]);
918 
919  // #14661
920  $this->setPublicNotes($this->notes->domain()->commentsActive($this->getId()));
921 
922  $this->setForTranslation((bool) $lm_rec["for_translation"]);
923  }
924 
925  public function updateProperties(): void
926  {
927  $ilDB = $this->db;
928 
929  // force clean_frames to be set, if layout per page is activated
930  if ($this->getLayoutPerPage()) {
931  $this->setCleanFrames(true);
932  }
933 
934  $q = "UPDATE content_object SET " .
935  " default_layout = " . $ilDB->quote($this->getLayout(), "text") . ", " .
936  " page_header = " . $ilDB->quote($this->getPageHeader(), "text") . "," .
937  " toc_mode = " . $ilDB->quote($this->getTOCMode(), "text") . "," .
938  " toc_active = " . $ilDB->quote(ilUtil::tf2yn($this->isActiveTOC()), "text") . "," .
939  " numbering = " . $ilDB->quote(ilUtil::tf2yn($this->isActiveNumbering()), "text") . "," .
940  " print_view_active = " . $ilDB->quote(ilUtil::tf2yn($this->isActivePrintView()), "text") . "," .
941  " no_glo_appendix = " . $ilDB->quote(ilUtil::tf2yn($this->isActivePreventGlossaryAppendix()), "text") . "," .
942  " hide_head_foot_print = " . $ilDB->quote($this->getHideHeaderFooterPrint(), "integer") . "," .
943  " downloads_active = " . $ilDB->quote(ilUtil::tf2yn($this->isActiveDownloads()), "text") . "," .
944  " downloads_public_active = " . $ilDB->quote(ilUtil::tf2yn($this->isActiveDownloadsPublic()), "text") . "," .
945  " clean_frames = " . $ilDB->quote(ilUtil::tf2yn($this->cleanFrames()), "text") . "," .
946  " hist_user_comments = " . $ilDB->quote(ilUtil::tf2yn($this->isActiveHistoryUserComments()), "text") . "," .
947  " public_access_mode = " . $ilDB->quote($this->getPublicAccessMode(), "text") . "," .
948  " public_xml_file = " . $ilDB->quote($this->getPublicExportFile("xml"), "text") . "," .
949  " public_html_file = " . $ilDB->quote($this->getPublicExportFile("html"), "text") . "," .
950  " header_page = " . $ilDB->quote($this->getHeaderPage(), "integer") . "," .
951  " footer_page = " . $ilDB->quote($this->getFooterPage(), "integer") . "," .
952  " lm_menu_active = " . $ilDB->quote(ilUtil::tf2yn($this->isActiveLMMenu()), "text") . ", " .
953  " layout_per_page = " . $ilDB->quote($this->getLayoutPerPage(), "integer") . ", " .
954  " rating = " . $ilDB->quote($this->hasRating(), "integer") . ", " .
955  " rating_pages = " . $ilDB->quote($this->hasRatingPages(), "integer") . ", " .
956  " disable_def_feedback = " . $ilDB->quote($this->getDisableDefaultFeedback(), "integer") . ", " .
957  " progr_icons = " . $ilDB->quote($this->getProgressIcons(), "integer") . ", " .
958  " store_tries = " . $ilDB->quote($this->getStoreTries(), "integer") . ", " .
959  " restrict_forw_nav = " . $ilDB->quote($this->getRestrictForwardNavigation(), "integer") . ", " .
960  " for_translation = " . $ilDB->quote((int) $this->getForTranslation(), "integer") . " " .
961  " WHERE id = " . $ilDB->quote($this->getId(), "integer");
962  $ilDB->manipulate($q);
963  // #14661
964  $this->notes->domain()->activateComments($this->getId(), $this->publicNotes());
965  }
966 
970  public function createProperties(): void
971  {
972  $ilDB = $this->db;
973 
974  $this->db->insert("content_object", [
975  "id" => ["integer", $this->getId()],
976  "page_header" => ["text", ilLMObject::PAGE_TITLE]
977  ]);
978 
979  // #14661
980  $this->notes->domain()->activateComments($this->getId());
981 
982  $this->readProperties(); // to get db default values
983  }
984 
985 
989  public static function getAvailableLayouts(): array
990  {
991  $dir = opendir("./Modules/LearningModule/layouts/lm");
992 
993  $layouts = array();
994 
995  while ($file = readdir($dir)) {
996  if ($file != "." && $file != ".." && $file != "CVS" && $file != ".svn") {
997  // directories
998  if (is_dir("./Modules/LearningModule/layouts/lm/" . $file)) {
999  $layouts[$file] = $file;
1000  }
1001  }
1002  }
1003  asort($layouts);
1004 
1005  // workaround: fix ordering
1006  $ret = array(
1007  'toc2win' => 'toc2win',
1008  'toc2windyn' => 'toc2windyn',
1009  '1window' => '1window',
1010  '2window' => '2window',
1011  '3window' => '3window',
1012  'presentation' => 'presentation',
1013  'fullscreen' => 'fullscreen'
1014  );
1015 
1016  foreach ($layouts as $l) {
1017  if (!in_array($l, $ret)) {
1018  $ret[$l] = $l;
1019  }
1020  }
1021 
1022  return $ret;
1023  }
1024 
1028  public static function _checkPreconditionsOfPage(
1029  int $cont_ref_id,
1030  int $cont_obj_id,
1031  int $page_id
1032  ): bool {
1033  $lm_tree = new ilTree($cont_obj_id);
1034  $lm_tree->setTableNames('lm_tree', 'lm_data');
1035  $lm_tree->setTreeTablePK("lm_id");
1036 
1037  if ($lm_tree->isInTree($page_id)) {
1038  $path = $lm_tree->getPathFull($page_id, $lm_tree->readRootId());
1039  foreach ($path as $node) {
1040  if ($node["type"] == "st") {
1041  if (!ilConditionHandler::_checkAllConditionsOfTarget($cont_ref_id, $node["child"], "st")) {
1042  return false;
1043  }
1044  }
1045  }
1046  }
1047 
1048  return true;
1049  }
1050 
1054  public static function _getMissingPreconditionsOfPage(
1055  int $cont_ref_id,
1056  int $cont_obj_id,
1057  int $page_id
1058  ): array {
1059  $lm_tree = new ilTree($cont_obj_id);
1060  $lm_tree->setTableNames('lm_tree', 'lm_data');
1061  $lm_tree->setTreeTablePK("lm_id");
1062 
1063  $conds = array();
1064  if ($lm_tree->isInTree($page_id)) {
1065  // get full path of page
1066  $path = $lm_tree->getPathFull($page_id, $lm_tree->readRootId());
1067  foreach ($path as $node) {
1068  if ($node["type"] == "st") {
1069  // get all preconditions of upper chapters
1070  $tconds = ilConditionHandler::_getPersistedConditionsOfTarget($cont_ref_id, $node["child"], "st");
1071  foreach ($tconds as $tcond) {
1072  // store all missing preconditions
1073  if (!ilConditionHandler::_checkCondition($tcond)) {
1074  $conds[] = $tcond;
1075  }
1076  }
1077  }
1078  }
1079  }
1080 
1081  return $conds;
1082  }
1083 
1087  public static function _getMissingPreconditionsTopChapter(
1088  int $cont_obj_ref_id,
1089  int $cont_obj_id,
1090  int $page_id
1091  ): int {
1092  $lm_tree = new ilTree($cont_obj_id);
1093  $lm_tree->setTableNames('lm_tree', 'lm_data');
1094  $lm_tree->setTreeTablePK("lm_id");
1095 
1096  if ($lm_tree->isInTree($page_id)) {
1097  // get full path of page
1098  $path = $lm_tree->getPathFull($page_id, $lm_tree->readRootId());
1099  foreach ($path as $node) {
1100  if ($node["type"] == "st") {
1101  // get all preconditions of upper chapters
1102  $tconds = ilConditionHandler::_getPersistedConditionsOfTarget($cont_obj_ref_id, $node["child"], "st");
1103  foreach ($tconds as $tcond) {
1104  // look for missing precondition
1105  if (!ilConditionHandler::_checkCondition($tcond)) {
1106  return (int) $node["child"];
1107  }
1108  }
1109  }
1110  }
1111  }
1112 
1113  return 0;
1114  }
1115 
1119  public static function hasSuccessorPage(
1120  int $a_cont_obj_id,
1121  int $a_page_id
1122  ): bool {
1123  $tree = new ilTree($a_cont_obj_id);
1124  $tree->setTableNames('lm_tree', 'lm_data');
1125  $tree->setTreeTablePK("lm_id");
1126  if ($tree->isInTree($a_page_id)) {
1127  $succ = $tree->fetchSuccessorNode($a_page_id, "pg");
1128  if ($succ > 0) {
1129  return true;
1130  }
1131  }
1132  return false;
1133  }
1134 
1138  public function checkTree(): void
1139  {
1140  $tree = new ilLMTree($this->getId());
1141  $tree->checkTree();
1143  }
1144 
1145  public function fixTree(): void
1146  {
1147  $ilDB = $this->db;
1148 
1149  $tree = $this->getLMTree();
1150 
1151  // check numbering, if errors, renumber
1152  // it is very important to keep this step before deleting subtrees
1153  // in the following steps
1154  $set = $ilDB->query(
1155  "SELECT DISTINCT l1.lm_id" .
1156  " FROM lm_tree l1" .
1157  " JOIN lm_tree l2 ON ( l1.child = l2.parent" .
1158  " AND l1.lm_id = l2.lm_id )" .
1159  " JOIN lm_data ON ( l1.child = lm_data.obj_id )" .
1160  " WHERE (l2.lft < l1.lft" .
1161  " OR l2.rgt > l1.rgt OR l2.lft > l1.rgt OR l2.rgt < l1.lft)" .
1162  " AND l1.lm_id = " . $ilDB->quote($this->getId(), "integer") .
1163  " ORDER BY lm_data.create_date DESC"
1164  );
1165  if ($rec = $ilDB->fetchAssoc($set)) {
1166  $tree->renumber();
1167  }
1168 
1169  // delete subtrees that have no lm_data records (changed due to #20637)
1170  $set = $ilDB->query("SELECT * FROM lm_tree WHERE lm_tree.lm_id = " . $ilDB->quote($this->getId(), "integer"));
1171  while ($node = $ilDB->fetchAssoc($set)) {
1172  $q = "SELECT * FROM lm_data WHERE obj_id = " .
1173  $ilDB->quote($node["child"], "integer");
1174  $obj_set = $ilDB->query($q);
1175  $obj_rec = $ilDB->fetchAssoc($obj_set);
1176  if (!$obj_rec) {
1177  $node_data = $tree->getNodeData($node["child"]);
1178  $node_data["child"] = $node["child"];
1179  $tree->deleteTree($node_data);
1180  }
1181  }
1182 
1183  // delete subtrees that have pages as parent
1184  $nodes = $tree->getSubTree($tree->getNodeData($tree->getRootId()));
1185  foreach ($nodes as $node) {
1186  $q = "SELECT * FROM lm_data WHERE obj_id = " .
1187  $ilDB->quote($node["parent"], "integer");
1188  $obj_set = $ilDB->query($q);
1189  $obj_rec = $ilDB->fetchAssoc($obj_set);
1190  if (($obj_rec["type"] ?? "") == "pg") {
1191  $node_data = $tree->getNodeData($node["child"]);
1192  if ($tree->isInTree($node["child"])) {
1193  $tree->deleteTree($node_data);
1194  }
1195  }
1196  }
1197 
1198  // check for multi-references pages or chapters
1199  // if errors -> create copies of them here
1200  $set = $ilDB->query("SELECT DISTINCT l1.lm_id" .
1201  " FROM lm_tree l1" .
1202  " JOIN lm_tree l2 ON ( l1.child = l2.child AND l1.lm_id <> l2.lm_id )" .
1203  " JOIN lm_data ON (l1.child = lm_data.obj_id)" .
1204  " WHERE l1.child <> 1" .
1205  " AND l1.lm_id <> lm_data.lm_id" .
1206  " AND l1.lm_id = " . $ilDB->quote($this->getId(), "integer"));
1207  if ($rec = $ilDB->fetchAssoc($set)) {
1208  $set = $ilDB->query("SELECT DISTINCT l1.child " .
1209  " FROM lm_tree l1" .
1210  " JOIN lm_tree l2 ON ( l1.child = l2.child AND l1.lm_id <> l2.lm_id )" .
1211  " JOIN lm_data ON (l1.child = lm_data.obj_id)" .
1212  " WHERE l1.child <> 1" .
1213  " AND l1.lm_id <> lm_data.lm_id" .
1214  " AND l1.lm_id = " . $ilDB->quote($this->getId(), "integer"));
1215  while ($rec = $ilDB->fetchAssoc($set)) {
1216  $cobj = ilLMObjectFactory::getInstance($this->lm, $rec["child"]);
1217 
1218  if (is_object($cobj)) {
1219  if ($cobj->getType() == "pg") {
1220  // make a copy of it
1221  $pg_copy = $cobj->copy($this->lm);
1222 
1223  // replace the child in the tree with the copy (id)
1224  $ilDB->manipulate(
1225  "UPDATE lm_tree SET " .
1226  " child = " . $ilDB->quote($pg_copy->getId(), "integer") .
1227  " WHERE child = " . $ilDB->quote($cobj->getId(), "integer") .
1228  " AND lm_id = " . $ilDB->quote($this->getId(), "integer")
1229  );
1230  } elseif ($cobj->getType() == "st") {
1231  // make a copy of it
1232  $st_copy = $cobj->copy($this->lm);
1233 
1234  // replace the child in the tree with the copy (id)
1235  $ilDB->manipulate(
1236  "UPDATE lm_tree SET " .
1237  " child = " . $ilDB->quote($st_copy->getId(), "integer") .
1238  " WHERE child = " . $ilDB->quote($cobj->getId(), "integer") .
1239  " AND lm_id = " . $ilDB->quote($this->getId(), "integer")
1240  );
1241 
1242  // make all childs refer to the copy now
1243  $ilDB->manipulate(
1244  "UPDATE lm_tree SET " .
1245  " parent = " . $ilDB->quote($st_copy->getId(), "integer") .
1246  " WHERE parent = " . $ilDB->quote($cobj->getId(), "integer") .
1247  " AND lm_id = " . $ilDB->quote($this->getId(), "integer")
1248  );
1249  }
1250  }
1251  }
1252  }
1253 
1254  // missing copage entries
1255  $set = $ilDB->queryF(
1256  "SELECT * FROM lm_data " .
1257  " WHERE lm_id = %s AND type = %s",
1258  array("integer", "text"),
1259  array($this->getId(), "pg")
1260  );
1261  while ($rec = $ilDB->fetchAssoc($set)) {
1262  if (!ilPageObject::_exists("lm", $rec["obj_id"], "-")) {
1263  $lm_page = new ilLMPage();
1264  $lm_page->setId($rec["obj_id"]);
1265  $lm_page->setParentId($this->getId());
1266  $lm_page->create(false);
1267  }
1268  }
1269  }
1270 
1274  public function checkStructure(): array
1275  {
1276  $issues = [];
1277  $ilDB = $this->db;
1278 
1279  $tree = $this->getLMTree();
1280 
1281  // check numbering, if errors, renumber
1282  // it is very important to keep this step before deleting subtrees
1283  // in the following steps
1284  $set = $ilDB->query(
1285  "SELECT l1.child, l1.lft l1lft, l1.rgt l1rgt, l2.parent, l2.lft l2lft, l2.rgt l2rgt" .
1286  " FROM lm_tree l1" .
1287  " JOIN lm_tree l2 ON ( l1.child = l2.parent" .
1288  " AND l1.lm_id = l2.lm_id )" .
1289  " JOIN lm_data ON ( l1.child = lm_data.obj_id )" .
1290  " WHERE (l2.lft < l1.lft" .
1291  " OR l2.rgt > l1.rgt OR l2.lft > l1.rgt OR l2.rgt < l1.lft)" .
1292  " AND l1.lm_id = " . $ilDB->quote($this->getId(), "integer") .
1293  " ORDER BY lm_data.create_date DESC"
1294  );
1295  while ($rec = $ilDB->fetchAssoc($set)) {
1296  $issues[] = "Tree numbering: " . print_r($rec, true);
1297  }
1298 
1299  // delete subtrees that have no lm_data records (changed due to #20637)
1300  $set = $ilDB->query("SELECT * FROM lm_tree WHERE lm_tree.lm_id = " . $ilDB->quote($this->getId(), "integer"));
1301  while ($node = $ilDB->fetchAssoc($set)) {
1302  $q = "SELECT * FROM lm_data WHERE obj_id = " .
1303  $ilDB->quote($node["child"], "integer");
1304  $obj_set = $ilDB->query($q);
1305  $obj_rec = $ilDB->fetchAssoc($obj_set);
1306  if (!$obj_rec) {
1307  $issues[] = "Tree entry without data entry: " . print_r($node, true);
1308  }
1309  }
1310 
1311  // delete subtrees that have pages as parent
1312  $nodes = $tree->getSubTree($tree->getNodeData($tree->getRootId()));
1313  foreach ($nodes as $node) {
1314  $q = "SELECT * FROM lm_data WHERE obj_id = " .
1315  $ilDB->quote($node["parent"], "integer");
1316  $obj_set = $ilDB->query($q);
1317  $obj_rec = $ilDB->fetchAssoc($obj_set);
1318  if (($obj_rec["type"] ?? "") == "pg") {
1319  $node_data = $tree->getNodeData($node["child"]);
1320  if ($tree->isInTree($node["child"])) {
1321  $issues[] = "Subtree with page parent: " . print_r($node_data, true);
1322  }
1323  }
1324  }
1325 
1326  // check for multi-references pages or chapters
1327  // if errors -> create copies of them here
1328  $set = $ilDB->query("SELECT DISTINCT l1.lm_id" .
1329  " FROM lm_tree l1" .
1330  " JOIN lm_tree l2 ON ( l1.child = l2.child AND l1.lm_id <> l2.lm_id )" .
1331  " JOIN lm_data ON (l1.child = lm_data.obj_id)" .
1332  " WHERE l1.child <> 1" .
1333  " AND l1.lm_id <> lm_data.lm_id" .
1334  " AND l1.lm_id = " . $ilDB->quote($this->getId(), "integer"));
1335  if ($rec = $ilDB->fetchAssoc($set)) {
1336  $set = $ilDB->query("SELECT DISTINCT l1.child " .
1337  " FROM lm_tree l1" .
1338  " JOIN lm_tree l2 ON ( l1.child = l2.child AND l1.lm_id <> l2.lm_id )" .
1339  " JOIN lm_data ON (l1.child = lm_data.obj_id)" .
1340  " WHERE l1.child <> 1" .
1341  " AND l1.lm_id <> lm_data.lm_id" .
1342  " AND l1.lm_id = " . $ilDB->quote($this->getId(), "integer"));
1343  while ($rec = $ilDB->fetchAssoc($set)) {
1344  $set3 = $ilDB->queryF(
1345  "SELECT * FROM lm_tree " .
1346  " WHERE child = %s ",
1347  array("integer"),
1348  array($rec["child"])
1349  );
1350  while ($rec3 = $ilDB->fetchAssoc($set3)) {
1351  $issues[] = "Multi-reference item: " . print_r($rec3, true);
1352  }
1353  }
1354  }
1355 
1356  // missing copage entries
1357  $set = $ilDB->queryF(
1358  "SELECT * FROM lm_data " .
1359  " WHERE lm_id = %s AND type = %s",
1360  array("integer", "text"),
1361  array($this->getId(), "pg")
1362  );
1363  while ($rec = $ilDB->fetchAssoc($set)) {
1364  if (!ilPageObject::_exists("lm", $rec["obj_id"], "-")) {
1365  $issues[] = "Missing COPage: " . print_r($rec, true);
1366  }
1367  }
1368 
1369 
1370  return $issues;
1371  }
1372 
1373  public function exportXML(
1374  ilXmlWriter $a_xml_writer,
1375  int $a_inst,
1376  string $a_target_dir,
1377  ilLog $expLog
1378  ): void {
1379  $attrs = array();
1380  switch ($this->getType()) {
1381  case "lm":
1382  $attrs["Type"] = "LearningModule";
1383  break;
1384  }
1385  $a_xml_writer->xmlStartTag("ContentObject", $attrs);
1386 
1387  // MetaData
1388  $this->exportXMLMetaData($a_xml_writer);
1389 
1390  // StructureObjects
1391  //echo "ContObj:".$a_inst.":<br>";
1392  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Structure Objects");
1393  $this->exportXMLStructureObjects($a_xml_writer, $a_inst, $expLog);
1394  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Structure Objects");
1395 
1396  // PageObjects
1397  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Page Objects");
1398  $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
1399  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Page Objects");
1400 
1401  // MediaObjects
1402  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Media Objects");
1403  $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
1404  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Media Objects");
1405 
1406  // FileItems
1407  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export File Items");
1408  $this->exportFileItems($a_target_dir, $expLog);
1409  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export File Items");
1410 
1411  // Questions
1412  if (count($this->q_ids) > 0) {
1413  $qti_file = fopen($a_target_dir . "/qti.xml", "w");
1414  $pool = new ilObjQuestionPool();
1415  fwrite($qti_file, $pool->questionsToXML($this->q_ids));
1416  fclose($qti_file);
1417  }
1418 
1419  // To do: implement version selection/detection
1420  // Properties
1421  $expLog->write(date("[y-m-d H:i:s] ") . "Start Export Properties");
1422  $this->exportXMLProperties($a_xml_writer, $expLog);
1423  $expLog->write(date("[y-m-d H:i:s] ") . "Finished Export Properties");
1424 
1425  $a_xml_writer->xmlEndTag("ContentObject");
1426  }
1427 
1428  public function exportXMLMetaData(
1429  ilXmlWriter $a_xml_writer
1430  ): void {
1431  $md2xml = new ilMD2XML($this->getId(), 0, $this->getType());
1432  $md2xml->setExportMode(true);
1433  $md2xml->startExport();
1434  $a_xml_writer->appendXML($md2xml->getXML());
1435  }
1436 
1437  public function exportXMLStructureObjects(
1438  ilXmlWriter $a_xml_writer,
1439  int $a_inst,
1440  ilLog $expLog
1441  ): void {
1442  $childs = $this->lm_tree->getChilds($this->lm_tree->getRootId());
1443  foreach ($childs as $child) {
1444  if ($child["type"] != "st") {
1445  continue;
1446  }
1447 
1448  $structure_obj = new ilStructureObject($this->lm, $child["obj_id"]);
1449  $structure_obj->exportXML($a_xml_writer, $a_inst, $expLog);
1450  unset($structure_obj);
1451  }
1452  }
1453 
1454  public function exportXMLPageObjects(
1455  ilXmlWriter $a_xml_writer,
1456  int $a_inst,
1457  ilLog $expLog
1458  ): void {
1459  $pages = ilLMPageObject::getPageList($this->getId());
1460  foreach ($pages as $page) {
1461  if (ilLMPage::_exists($this->getType(), $page["obj_id"])) {
1462  $expLog->write(date("[y-m-d H:i:s] ") . "Page Object " . $page["obj_id"]);
1463 
1464  // export xml to writer object
1465  $page_obj = new ilLMPageObject($this->lm, $page["obj_id"]);
1466  $page_obj->exportXML($a_xml_writer, "normal", $a_inst);
1467 
1468  // collect media objects
1469  $mob_ids = $page_obj->getMediaObjectIds();
1470  foreach ($mob_ids as $mob_id) {
1471  $this->mob_ids[$mob_id] = $mob_id;
1472  }
1473 
1474  // collect all file items
1475  $file_ids = $page_obj->getFileItemIds();
1476  foreach ($file_ids as $file_id) {
1477  $this->file_ids[$file_id] = $file_id;
1478  }
1479 
1480  // collect all questions
1481  $q_ids = $page_obj->getQuestionIds();
1482  foreach ($q_ids as $q_id) {
1483  $this->q_ids[$q_id] = $q_id;
1484  }
1485 
1486  unset($page_obj);
1487  }
1488  }
1489  }
1490 
1491  public function exportXMLMediaObjects(
1492  ilXmlWriter $a_xml_writer,
1493  int $a_inst,
1494  string $a_target_dir,
1495  ilLog $expLog
1496  ): void {
1497  $linked_mobs = array();
1498 
1499  // mobs directly embedded into pages
1500  foreach ($this->mob_ids as $mob_id) {
1501  if ($mob_id > 0 && ilObject::_lookupType($mob_id) == "mob") {
1502  $expLog->write(date("[y-m-d H:i:s] ") . "Media Object " . $mob_id);
1503  $media_obj = new ilObjMediaObject($mob_id);
1504  $media_obj->exportXML($a_xml_writer, $a_inst);
1505  $media_obj->exportFiles($a_target_dir);
1506 
1507  $lmobs = $media_obj->getLinkedMediaObjects($this->mob_ids);
1508  $linked_mobs = array_merge($linked_mobs, $lmobs);
1509 
1510  unset($media_obj);
1511  }
1512  }
1513 
1514  // linked mobs (in map areas)
1515  foreach ($linked_mobs as $mob_id) {
1516  if ($mob_id > 0) {
1517  $expLog->write(date("[y-m-d H:i:s] ") . "Media Object " . $mob_id);
1518  $media_obj = new ilObjMediaObject($mob_id);
1519  $media_obj->exportXML($a_xml_writer, $a_inst);
1520  $media_obj->exportFiles($a_target_dir);
1521  unset($media_obj);
1522  }
1523  }
1524  }
1525 
1526  public function exportFileItems(
1527  string $a_target_dir,
1528  ilLog $expLog
1529  ): void {
1530  foreach ($this->file_ids as $file_id) {
1531  $expLog->write(date("[y-m-d H:i:s] ") . "File Item " . $file_id);
1532  $file_obj = new ilObjFile($file_id, false);
1533  $file_obj->export($a_target_dir);
1534  unset($file_obj);
1535  }
1536  }
1537 
1538  public function exportXMLProperties(
1539  ilXmlWriter $a_xml_writer,
1540  ilLog $expLog
1541  ): void {
1542  $attrs = array();
1543  $a_xml_writer->xmlStartTag("Properties", $attrs);
1544 
1545  // Layout
1546  $attrs = array("Name" => "Layout", "Value" => $this->getLayout());
1547  $a_xml_writer->xmlElement("Property", $attrs);
1548 
1549  // Page Header
1550  $attrs = array("Name" => "PageHeader", "Value" => $this->getPageHeader());
1551  $a_xml_writer->xmlElement("Property", $attrs);
1552 
1553  // TOC Mode
1554  $attrs = array("Name" => "TOCMode", "Value" => $this->getTOCMode());
1555  $a_xml_writer->xmlElement("Property", $attrs);
1556 
1557  // LM Menu Activation
1558  $attrs = array("Name" => "ActiveLMMenu", "Value" =>
1559  ilUtil::tf2yn($this->isActiveLMMenu()));
1560  $a_xml_writer->xmlElement("Property", $attrs);
1561 
1562  // Numbering Activation
1563  $attrs = array("Name" => "ActiveNumbering", "Value" =>
1564  ilUtil::tf2yn($this->isActiveNumbering()));
1565  $a_xml_writer->xmlElement("Property", $attrs);
1566 
1567  // Table of contents button activation
1568  $attrs = array("Name" => "ActiveTOC", "Value" =>
1569  ilUtil::tf2yn($this->isActiveTOC()));
1570  $a_xml_writer->xmlElement("Property", $attrs);
1571 
1572  // Print view button activation
1573  $attrs = array("Name" => "ActivePrintView", "Value" =>
1574  ilUtil::tf2yn($this->isActivePrintView()));
1575  $a_xml_writer->xmlElement("Property", $attrs);
1576 
1577  // Note that download button is not saved, because
1578  // download files do not exist after import
1579 
1580  // Clean frames
1581  $attrs = array("Name" => "CleanFrames", "Value" =>
1582  ilUtil::tf2yn($this->cleanFrames()));
1583  $a_xml_writer->xmlElement("Property", $attrs);
1584 
1585  // Public notes activation
1586  $attrs = array("Name" => "PublicNotes", "Value" =>
1587  ilUtil::tf2yn($this->publicNotes()));
1588  $a_xml_writer->xmlElement("Property", $attrs);
1589 
1590  // History comments for authors activation
1591  $attrs = array("Name" => "HistoryUserComments", "Value" =>
1593  $a_xml_writer->xmlElement("Property", $attrs);
1594 
1595  // Rating
1596  $attrs = array("Name" => "Rating", "Value" =>
1597  ilUtil::tf2yn($this->hasRating()));
1598  $a_xml_writer->xmlElement("Property", $attrs);
1599  $attrs = array("Name" => "RatingPages", "Value" =>
1600  ilUtil::tf2yn($this->hasRatingPages()));
1601  $a_xml_writer->xmlElement("Property", $attrs);
1602 
1603  // Header Page
1604  if ($this->getHeaderPage() > 0) {
1605  $attrs = array("Name" => "HeaderPage", "Value" =>
1606  "il_" . IL_INST_ID . "_pg_" . $this->getHeaderPage());
1607  $a_xml_writer->xmlElement("Property", $attrs);
1608  }
1609 
1610  // Footer Page
1611  if ($this->getFooterPage() > 0) {
1612  $attrs = array("Name" => "FooterPage", "Value" =>
1613  "il_" . IL_INST_ID . "_pg_" . $this->getFooterPage());
1614  $a_xml_writer->xmlElement("Property", $attrs);
1615  }
1616 
1617  // layout per page
1618  $attrs = array("Name" => "LayoutPerPage", "Value" =>
1619  $this->getLayoutPerPage());
1620  $a_xml_writer->xmlElement("Property", $attrs);
1621 
1622  // progress icons
1623  $attrs = array("Name" => "ProgressIcons", "Value" =>
1624  $this->getProgressIcons());
1625  $a_xml_writer->xmlElement("Property", $attrs);
1626 
1627  // store tries
1628  $attrs = array("Name" => "StoreTries", "Value" =>
1629  $this->getStoreTries());
1630  $a_xml_writer->xmlElement("Property", $attrs);
1631 
1632  // restrict forward navigation
1633  $attrs = array("Name" => "RestrictForwardNavigation", "Value" =>
1634  $this->getRestrictForwardNavigation());
1635  $a_xml_writer->xmlElement("Property", $attrs);
1636 
1637  // disable default feedback
1638  $attrs = array("Name" => "DisableDefaultFeedback", "Value" =>
1639  $this->getDisableDefaultFeedback());
1640  $a_xml_writer->xmlElement("Property", $attrs);
1641 
1642  $a_xml_writer->xmlEndTag("Properties");
1643  }
1644 
1645  public function getExportFiles(): array
1646  {
1647  $file = array();
1648 
1649  $types = array("xml", "html");
1650 
1651  foreach ($types as $type) {
1652  $dir = $this->getExportDirectory($type);
1653  // quit if import dir not available
1654  if (!is_dir($dir) or
1655  !is_writeable($dir)) {
1656  continue;
1657  }
1658 
1659  // open directory
1660  $cdir = dir($dir);
1661 
1662  // initialize array
1663 
1664  // get files and save the in the array
1665  while ($entry = $cdir->read()) {
1666  if ($entry != "." and
1667  $entry != ".." and
1668  substr($entry, -4) == ".zip" and
1669  preg_match("~^[0-9]{10}_{2}[0-9]+_{2}(lm_)*[0-9]+\.zip\$~", $entry)) {
1670  $file[$entry . $type] = array("type" => $type, "file" => $entry,
1671  "size" => filesize($dir . "/" . $entry));
1672  }
1673  }
1674 
1675  // close import directory
1676  $cdir->close();
1677  }
1678 
1679  // sort files
1680  ksort($file);
1681  return $file;
1682  }
1683 
1687  public function setPublicExportFile(
1688  string $a_type,
1689  string $a_file
1690  ): void {
1691  $this->public_export_file[$a_type] = $a_file;
1692  }
1693 
1694  public function getPublicExportFile(string $a_type): string
1695  {
1696  return $this->public_export_file[$a_type] ?? "";
1697  }
1698 
1699  public function getOfflineFiles(
1700  string $dir
1701  ): array {
1702  // quit if offline dir not available
1703  if (!is_dir($dir) or
1704  !is_writeable($dir)) {
1705  return array();
1706  }
1707 
1708  // open directory
1709  $dir = dir($dir);
1710 
1711  // initialize array
1712  $file = array();
1713 
1714  // get files and save the in the array
1715  while ($entry = $dir->read()) {
1716  if ($entry != "." and
1717  $entry != ".." and
1718  substr($entry, -4) == ".pdf" and
1719  preg_match("~^[0-9]{10}_{2}[0-9]+_{2}(lm_)*[0-9]+\.pdf\$~", $entry)) {
1720  $file[] = $entry;
1721  }
1722  }
1723 
1724  // close import directory
1725  $dir->close();
1726 
1727  // sort files
1728  sort($file);
1729  return $file;
1730  }
1731 
1732  public function executeDragDrop(
1733  int $source_id,
1734  int $target_id,
1735  bool $first_child,
1736  bool $as_subitem = false,
1737  string $movecopy = "move"
1738  ): void {
1739  if ($source_id === $target_id) {
1740  return;
1741  }
1742  $lmtree = new ilTree($this->getId());
1743  $lmtree->setTableNames('lm_tree', 'lm_data');
1744  $lmtree->setTreeTablePK("lm_id");
1745  //echo "-".$source_id."-".$target_id."-".$first_child."-".$as_subitem."-";
1746  $source_obj = ilLMObjectFactory::getInstance($this->lm, $source_id, true);
1747  $source_obj->setLMId($this->getId());
1748 
1749  if (!$first_child) {
1750  $target_obj = ilLMObjectFactory::getInstance($this->lm, $target_id, true);
1751  $target_obj->setLMId($this->getId());
1752  $target_parent = $lmtree->getParentId($target_id);
1753  }
1754 
1755  // handle pages
1756  if ($source_obj->getType() == "pg") {
1757  //echo "1";
1758  if ($lmtree->isInTree($source_obj->getId())) {
1759  $node_data = $lmtree->getNodeData($source_obj->getId());
1760 
1761  // cut on move
1762  if ($movecopy == "move") {
1763  $parent_id = $lmtree->getParentId($source_obj->getId());
1764  $lmtree->deleteTree($node_data);
1765 
1766  // write history entry
1768  $source_obj->getId(),
1769  "cut",
1770  array(ilLMObject::_lookupTitle($parent_id), $parent_id),
1771  $this->getType() . ":pg"
1772  );
1774  $parent_id,
1775  "cut_page",
1776  array(ilLMObject::_lookupTitle($source_obj->getId()), $source_obj->getId()),
1777  $this->getType() . ":st"
1778  );
1779  } else {
1780  // copy page
1781  $new_page = $source_obj->copy($this->lm);
1782  $source_id = $new_page->getId();
1783  $source_obj = $new_page;
1784  }
1785 
1786  // paste page
1787  if (!$lmtree->isInTree($source_obj->getId())) {
1788  if ($first_child) { // as first child
1789  $target_pos = ilTree::POS_FIRST_NODE;
1790  $parent = $target_id;
1791  } elseif ($as_subitem) { // as last child
1792  $parent = $target_id;
1793  $target_pos = ilTree::POS_FIRST_NODE;
1794  $pg_childs = $lmtree->getChildsByType($parent, "pg");
1795  if (count($pg_childs) != 0) {
1796  $target_pos = $pg_childs[count($pg_childs) - 1]["obj_id"];
1797  }
1798  } else { // at position
1799  $target_pos = $target_id;
1800  $parent = $target_parent;
1801  }
1802 
1803  // insert page into tree
1804  $lmtree->insertNode(
1805  $source_obj->getId(),
1806  $parent,
1807  $target_pos
1808  );
1809 
1810  // write history entry
1811  if ($movecopy == "move") {
1812  // write history comments
1814  $source_obj->getId(),
1815  "paste",
1816  array(ilLMObject::_lookupTitle($parent), $parent),
1817  $this->getType() . ":pg"
1818  );
1820  $parent,
1821  "paste_page",
1822  array(ilLMObject::_lookupTitle($source_obj->getId()), $source_obj->getId()),
1823  $this->getType() . ":st"
1824  );
1825  }
1826  }
1827  }
1828  }
1829 
1830  // handle chapters
1831  if ($source_obj->getType() == "st") {
1832  //echo "2";
1833  $source_node = $lmtree->getNodeData($source_id);
1834  $subnodes = $lmtree->getSubTree($source_node);
1835 
1836  // check, if target is within subtree
1837  foreach ($subnodes as $subnode) {
1838  if ($subnode["obj_id"] == $target_id) {
1839  return;
1840  }
1841  }
1842 
1843  $target_pos = $target_id;
1844 
1845  if ($first_child) { // as first subchapter
1846  $target_pos = ilTree::POS_FIRST_NODE;
1847  $target_parent = $target_id;
1848 
1849  $pg_childs = $lmtree->getChildsByType($target_parent, "pg");
1850  if (count($pg_childs) != 0) {
1851  $target_pos = $pg_childs[count($pg_childs) - 1]["obj_id"];
1852  }
1853  } elseif ($as_subitem) { // as last subchapter
1854  $target_parent = $target_id;
1855  $target_pos = ilTree::POS_FIRST_NODE;
1856  $childs = $lmtree->getChilds($target_parent);
1857  if (count($childs) != 0) {
1858  $target_pos = $childs[count($childs) - 1]["obj_id"];
1859  }
1860  }
1861 
1862  // delete source tree
1863  if ($movecopy == "move") {
1864  $lmtree->deleteTree($source_node);
1865  } else {
1866  // copy chapter (incl. subcontents)
1867  throw new ilException("ilObjContentObject: Not implemented");
1868  //$new_chapter = $source_obj->copy($lmtree, $target_parent, $target_pos);
1869  }
1870 
1871  if (!$lmtree->isInTree($source_id)) {
1872  $lmtree->insertNode($source_id, $target_parent, $target_pos);
1873 
1874  // insert moved tree
1875  foreach ($subnodes as $node) {
1876  if ($node["obj_id"] != $source_id) {
1877  $lmtree->insertNode($node["obj_id"], $node["parent"]);
1878  }
1879  }
1880  }
1881 
1882  // check the tree
1883  $this->checkTree();
1884  }
1885 
1886  $this->checkTree();
1887  }
1888 
1892  public function validatePages(): string
1893  {
1894  $mess = "";
1895 
1896  $pages = ilLMPageObject::getPageList($this->getId());
1897  foreach ($pages as $page) {
1898  if (ilLMPage::_exists($this->getType(), $page["obj_id"])) {
1899  $cpage = new ilLMPage($page["obj_id"]);
1900  $cpage->buildDom();
1901  $error = $cpage->validateDom();
1902 
1903  if ($error != "") {
1904  $this->lng->loadLanguageModule("content");
1905  $this->main_tpl->setOnScreenMessage('info', $this->lng->txt("cont_import_validation_errors"));
1906  $title = ilLMObject::_lookupTitle($page["obj_id"]);
1907  $page_obj = new ilLMPageObject($this->lm, $page["obj_id"]);
1908  $mess .= $this->lng->txt("obj_pg") . ": " . $title;
1909  $mess .= '<div class="small">';
1910  foreach ($error as $e) {
1911  $err_mess = implode(" - ", $e);
1912  if (!is_int(strpos($err_mess, ":0:"))) {
1913  $mess .= htmlentities($err_mess) . "<br />";
1914  }
1915  }
1916  $mess .= '</div>';
1917  $mess .= "<br />";
1918  }
1919  }
1920  }
1921 
1922  return $mess;
1923  }
1924 
1925  public function cloneObject(int $target_id, int $copy_id = 0, bool $omit_tree = false): ?ilObject
1926  {
1928  $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
1929  $this->cloneMetaData($new_obj);
1930  //$new_obj->createProperties();
1931 
1932  //copy online status if object is not the root copy object
1933  $cp_options = ilCopyWizardOptions::_getInstance($copy_id);
1934 
1935  if (!$cp_options->isRootNode($this->getRefId())) {
1936  $new_obj->setOfflineStatus($this->getOfflineStatus());
1937  }
1938 
1939  // $new_obj->setTitle($this->getTitle());
1940  $new_obj->setDescription($this->getDescription());
1941  $new_obj->setLayoutPerPage($this->getLayoutPerPage());
1942  $new_obj->setLayout($this->getLayout());
1943  $new_obj->setTOCMode($this->getTOCMode());
1944  $new_obj->setActiveLMMenu($this->isActiveLMMenu());
1945  $new_obj->setActiveTOC($this->isActiveTOC());
1946  $new_obj->setActiveNumbering($this->isActiveNumbering());
1947  $new_obj->setActivePrintView($this->isActivePrintView());
1948  $new_obj->setActivePreventGlossaryAppendix($this->isActivePreventGlossaryAppendix());
1949  $new_obj->setActiveDownloads($this->isActiveDownloads());
1950  $new_obj->setActiveDownloadsPublic($this->isActiveDownloadsPublic());
1951  $new_obj->setPublicNotes($this->publicNotes());
1952  $new_obj->setCleanFrames($this->cleanFrames());
1953  $new_obj->setHistoryUserComments($this->isActiveHistoryUserComments());
1954  $new_obj->setPublicAccessMode($this->getPublicAccessMode());
1955  $new_obj->setPageHeader($this->getPageHeader());
1956  $new_obj->setRating($this->hasRating());
1957  $new_obj->setRatingPages($this->hasRatingPages());
1958  $new_obj->setDisableDefaultFeedback($this->getDisableDefaultFeedback());
1959  $new_obj->setProgressIcons($this->getProgressIcons());
1960  $new_obj->setStoreTries($this->getStoreTries());
1961  $new_obj->setRestrictForwardNavigation($this->getRestrictForwardNavigation());
1962  $new_obj->setAutoGlossaries($this->getAutoGlossaries());
1963 
1964  $new_obj->update();
1965 
1966  $new_obj->createLMTree();
1967 
1968  // copy style
1969  $style = $this->content_style_domain->styleForObjId($this->getId());
1970  $style->cloneTo($new_obj->getId());
1971 
1972  $new_obj->update();
1973 
1974  // copy content
1975  $copied_nodes = $this->copyAllPagesAndChapters($new_obj, $copy_id);
1976 
1977  // page header and footer
1978  if ($this->getHeaderPage() > 0 && ($new_page_header = ($copied_nodes[$this->getHeaderPage()] ?? null)) > 0) {
1979  $new_obj->setHeaderPage($new_page_header);
1980  }
1981  if ($this->getFooterPage() > 0 && ($new_page_footer = ($copied_nodes[$this->getFooterPage()] ?? null)) > 0) {
1982  $new_obj->setFooterPage($new_page_footer);
1983  }
1984  $new_obj->update();
1985 
1986  // Copy learning progress settings
1987  $obj_settings = new ilLPObjSettings($this->getId());
1988  $obj_settings->cloneSettings($new_obj->getId());
1989  unset($obj_settings);
1990 
1991  // copy (page) multilang settings
1992  $ot = ilObjectTranslation::getInstance($this->getId());
1993  $ot->copy($new_obj->getId());
1994 
1995  // copy lm menu
1996  $menu = new ilLMMenuEditor();
1997  $menu->setObjId($this->getId());
1998  $new_menu = new ilLMMenuEditor();
1999  $new_menu->setObjId($new_obj->getId());
2000  foreach ($menu->getMenuEntries() as $entry) {
2001  /*'id' => $row->id,
2002  'title' => $row->title,
2003  'link' => $row->target,
2004  'type' => $row->link_type,
2005  'ref_id' => $row->link_ref_id,
2006  'active'*/
2007 
2008  $new_menu->setTarget($entry["link"] ?? "");
2009  $new_menu->setTitle($entry["title"] ?? "");
2010  $new_menu->setLinkType($entry["type"] ?? "");
2011  $new_menu->setLinkRefId($entry["ref_id"] ?? 0);
2012  $new_menu->create();
2013  ilLMMenuEditor::writeActive($new_menu->getEntryId(), $entry["active"] == "y");
2014  }
2015 
2016 
2017  return $new_obj;
2018  }
2019 
2020  public function copyAllPagesAndChapters(
2021  ilObjLearningModule $a_target_obj,
2022  int $a_copy_id = 0
2023  ): array {
2024  $parent_id = $a_target_obj->lm_tree->readRootId();
2025  $time = null;
2026 
2027  // get all chapters of root lm
2028  $chapters = $this->lm_tree->getChildsByType($this->lm_tree->readRootId(), "st");
2029  $copied_nodes = array();
2030  //$time = time();
2031  foreach ($chapters as $chap) {
2032  $cid = ilLMObject::pasteTree(
2033  $a_target_obj,
2034  $chap["child"],
2035  $parent_id,
2037  (string) $time,
2038  $copied_nodes,
2039  true,
2040  $this->lm
2041  );
2042  $target = $cid;
2043  }
2044 
2045  // copy free pages
2046  $pages = ilLMPageObject::getPageList($this->getId());
2047  foreach ($pages as $p) {
2048  if (!$this->lm_tree->isInTree($p["obj_id"])) {
2049  $item = new ilLMPageObject($this->lm, $p["obj_id"]);
2050  $target_item = $item->copy($a_target_obj);
2051  $copied_nodes[$item->getId()] = $target_item->getId();
2052  }
2053  }
2054 
2055  // Add mapping for pages and chapters
2056  $options = ilCopyWizardOptions::_getInstance($a_copy_id);
2057  foreach ($copied_nodes as $old_id => $new_id) {
2058  $options->appendMapping(
2059  $this->getRefId() . '_' . $old_id,
2060  $a_target_obj->getRefId() . '_' . $new_id
2061  );
2062  }
2063 
2064  ilLMObject::updateInternalLinks($copied_nodes);
2065 
2066  $a_target_obj->checkTree();
2067 
2068  return $copied_nodes;
2069  }
2070 
2071  public static function lookupAutoGlossaries(
2072  int $a_lm_id
2073  ): array {
2074  global $DIC;
2075 
2076  $ilDB = $DIC->database();
2077 
2078  // read auto glossaries
2079  $set = $ilDB->query(
2080  "SELECT * FROM lm_glossaries " .
2081  " WHERE lm_id = " . $ilDB->quote($a_lm_id, "integer")
2082  );
2083  $glos = array();
2084  while ($rec = $ilDB->fetchAssoc($set)) {
2085  $glos[] = $rec["glo_id"];
2086  }
2087  return $glos;
2088  }
2089 
2090  public function autoLinkGlossaryTerms(
2091  int $a_glo_ref_id
2092  ): void {
2093  // get terms
2094  $terms = ilGlossaryTerm::getTermList([$a_glo_ref_id]);
2095 
2096  // each get page: get content
2097  $pages = ilLMPage::getAllPages($this->getType(), $this->getId());
2098 
2099  // determine terms that occur in the page
2100  $found_pages = array();
2101  foreach ($pages as $p) {
2102  $pg = new ilLMPage($p["id"]);
2103  $c = $pg->getXMLContent();
2104  foreach ($terms as $t) {
2105  if (is_int(stripos($c, $t["term"]))) {
2106  $found_pages[$p["id"]]["terms"][] = $t;
2107  if (!is_object($found_pages[$p["id"]]["page"] ?? null)) {
2108  $found_pages[$p["id"]]["page"] = $pg;
2109  }
2110  }
2111  }
2112  reset($terms);
2113  }
2114 
2115  // ilPCParagraph autoLinkGlossariesPage with page and terms
2116  foreach ($found_pages as $id => $fp) {
2117  ilPCParagraph::autoLinkGlossariesPage($fp["page"], $fp["terms"]);
2118  }
2119  }
2120 
2121 
2125 
2130  public static function isOnlineHelpModule(
2131  int $a_id,
2132  bool $a_as_obj_id = false
2133  ): bool {
2134  if (!$a_as_obj_id && $a_id > 0 && $a_id === (int) OH_REF_ID) {
2135  return true;
2136  }
2137  if ($a_as_obj_id && $a_id > 0 && $a_id === ilObject::_lookupObjId((int) OH_REF_ID)) {
2138  return true;
2139  }
2140  return false;
2141  }
2142 
2143  public function setRating(bool $a_value): void
2144  {
2145  $this->rating = $a_value;
2146  }
2147 
2148  public function hasRating(): bool
2149  {
2150  return $this->rating;
2151  }
2152 
2153  public function setRatingPages(bool $a_value): void
2154  {
2155  $this->rating_pages = $a_value;
2156  }
2157 
2158  public function hasRatingPages(): bool
2159  {
2160  return $this->rating_pages;
2161  }
2162 
2163 
2164  protected function doMDUpdateListener(
2165  string $a_element
2166  ): void {
2167  switch ($a_element) {
2168  case 'Educational':
2169  $obj_lp = ilObjectLP::getInstance($this->getId());
2170  if (in_array(
2171  $obj_lp->getCurrentMode(),
2173  )) {
2175  }
2176  break;
2177 
2178  case 'General':
2179 
2180  // Update Title and description
2181  $md = new ilMD($this->getId(), 0, $this->getType());
2182  if (!is_object($md_gen = $md->getGeneral())) {
2183  return;
2184  }
2185 
2186  $ot = ilObjectTranslation::getInstance($this->getId());
2187  if ($ot->getContentActivated()) {
2188  $ot->setDefaultTitle($md_gen->getTitle());
2189 
2190  foreach ($md_gen->getDescriptionIds() as $id) {
2191  $md_des = $md_gen->getDescription($id);
2192  $ot->setDefaultDescription($md_des->getDescription());
2193  break;
2194  }
2195  $ot->save();
2196  }
2197  break;
2198  }
2199  }
2200 
2206  public function getPublicExportFiles(): array
2207  {
2208  $dirs = array("xml");
2209  $export_files = array();
2210 
2211  $ot = ilObjectTranslation::getInstance($this->getId());
2212  if ($ot->getContentActivated()) {
2213  $langs = $ot->getLanguages();
2214  foreach ($langs as $l => $ldata) {
2215  $dirs[] = "html_" . $l;
2216  }
2217  $dirs[] = "html_all";
2218  } else {
2219  $dirs[] = "html";
2220  }
2221 
2222  foreach ($dirs as $dir) {
2223  $type = explode("_", $dir);
2224  $type = $type[0];
2225  if ($this->getPublicExportFile($type) != "") {
2226  if (is_file($this->getExportDirectory($dir) . "/" .
2227  $this->getPublicExportFile($type))) {
2228  $size = filesize($this->getExportDirectory($dir) . "/" .
2229  $this->getPublicExportFile($type));
2230  $export_files[] = array("type" => $type,
2231  "dir_type" => $dir,
2232  "file" => $this->getPublicExportFile($type),
2233  "size" => $size);
2234  }
2235  }
2236  }
2237 
2238  return $export_files;
2239  }
2240 
2241  public function isInfoEnabled(): bool
2242  {
2244  }
2245 }
static updateInternalLinks(array $a_copied_nodes, string $a_parent_type="lm")
Update internal links, after multiple pages have been copied.
string $title
setActiveLMMenu(bool $a_act_lm_menu)
static _getNrOfAssignedLMs(int $a_style_id)
gets the number of learning modules assigned to a content style
executeDragDrop(int $source_id, int $target_id, bool $first_child, bool $as_subitem=false, string $movecopy="move")
static _getMissingPreconditionsOfPage(int $cont_ref_id, int $cont_obj_id, int $page_id)
gets all missing preconditions of page
$res
Definition: ltiservices.php:69
string $type
fetchSuccessorNode(int $a_node_id, string $a_type="")
get node data of successor node
static _getNrLMsNoStyle()
get number of learning modules assigned no style
getNodeData(int $a_node_id, ?int $a_tree_pk=null)
get all information of a node.
static _lookupDisableDefaultFeedback(int $a_id)
setActiveDownloadsPublic(bool $a_down)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
insert(string $table_name, array $values)
const IL_INST_ID
Definition: constants.php:40
static getLogger(string $a_component_id)
Get component logger.
static writeFooterPage(int $a_lm_id, int $a_page_id)
checkStructure()
Check tree (this has been copied from fixTree due to a bug fixing, should be reorganised) ...
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
exportXMLMediaObjects(ilXmlWriter $a_xml_writer, int $a_inst, string $a_target_dir, ilLog $expLog)
validatePages()
Validate all pages.
static _createEntry(int $a_obj_id, string $a_action, array $a_info_params=[], string $a_obj_type="", string $a_user_comment="", bool $a_update_last=false)
Creates a new history entry for an object.
static writeActive(int $entry_id, bool $active)
static autoLinkGlossariesPage(ilPageObject $a_page, array $a_terms)
Auto link glossary of whole page.
checkTreeChilds(bool $a_no_zero_child=true)
check, if all childs of tree nodes exist in object table
static _lookupRestrictForwardNavigation(int $a_obj_id)
static _deleteAllObjectData(ilObjLearningModule $a_cobj)
delete all objects of content object (digi book / learning module)
static getInstance(ilObjLearningModule $a_content_obj, int $a_id=0, bool $a_halt=true)
ilTree $tree
isInTree(?int $a_node_id)
get all information of a node.
static getAvailableLayouts()
get all available lm layouts
static _lookupContObjIdByStyleId(int $a_style_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupStoreTries(int $a_id)
createExportDirectory(string $a_type="xml")
creates data directory for export files (data_dir/lm_data/lm_<id>/export, depending on data directory...
setTreeTablePK(string $a_column_name)
set column containing primary key in tree table
static writeHeaderPage(int $a_lm_id, int $a_page_id)
deleteTree(array $a_node)
delete node and the whole subtree under this node
appendXML(string $a_str)
append xml string to document
setImportDirectory(string $a_import_dir)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: class.ilLog.php:30
static tf2yn(bool $a_tf)
static getTermList(array $a_glo_ref_id, string $searchterm="", string $a_first_letter="", string $a_def="", int $a_tax_node=0, bool $a_add_amet_fields=false, array $a_amet_filter=null, bool $a_include_references=false)
Get all terms for given set of glossary ids.
exportXMLMetaData(ilXmlWriter $a_xml_writer)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static hasSuccessorPage(int $a_cont_obj_id, int $a_page_id)
checks if page has a successor page
setPageHeader(string $a_pg_header=ilLMObject::CHAPTER_TITLE)
set page header mode
getPublicAccessMode()
get public access mode ("complete" | "selected")
setForTranslation(bool $a_val)
Set for translation (lm has been imported for translation purposes)
getPathFull(int $a_endnode_id, int $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
static putInTree(ilLMObject $a_obj, int $a_parent_id=0, int $a_target_node_id=0)
put this object into content object tree
$ilErr
Definition: raiseError.php:17
$path
Definition: ltiservices.php:32
ilGlobalTemplateInterface $main_tpl
static _lookupObjId(int $ref_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
xmlEndTag(string $tag)
Writes an endtag.
setRestrictForwardNavigation(bool $a_val)
static _lookupTitle(int $a_obj_id)
global $DIC
Definition: feed.php:28
create(bool $a_no_meta_data=false)
create content object
const POS_FIRST_NODE
setTableNames(string $a_table_tree, string $a_table_obj_data, string $a_table_obj_reference="")
set table names The primary key of the table containing your object_data must be &#39;obj_id&#39; You may use...
cloneMetaData(ilObject $target_obj)
Copy meta data.
__construct(VocabulariesInterface $vocabularies)
static _checkCondition(array $condition, int $a_usr_id=0)
checks wether a single condition is fulfilled every trigger object type must implement a static metho...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getPageHeader()
get page header mode (ilLMOBject::CHAPTER_TITLE | ilLMOBject::PAGE_TITLE | ilLMOBject::NO_HEADER) ...
doMDUpdateListener(string $a_element)
static _checkPreconditionsOfPage(int $cont_ref_id, int $cont_obj_id, int $page_id)
checks whether the preconditions of a page are fulfilled or not
getExportDirectory(string $a_type="xml")
static _exists(string $a_parent_type, int $a_id, string $a_lang="", bool $a_no_cache=false)
Checks whether page exists.
setTOCMode(string $a_toc_mode="chapters")
set toc mode
checkTree()
check consistence of tree all left & right values are checked if they are exists only once ...
static _lookupStyleSheetId(int $a_cont_obj_id)
ilLanguage $lng
getPublicExportFiles()
Get public export files.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
ilDBInterface $db
setPublicExportFile(string $a_type, string $a_file)
specify public export file for type
getTOCMode()
get toc mode ("chapters" | "pages")
renumber(int $node_id=1, int $i=1)
Wrapper for renumber.
static getInstance(int $obj_id)
Class ilObjFile.
static _moveLMStyles(int $a_from_style, int $a_to_style)
move learning modules from one style to another
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
exportFileItems(string $a_target_dir, ilLog $expLog)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getDataDir()
get data directory (outside webspace)
static _deleteStyleAssignments(int $a_style_id)
delete all style references to style
setPublicNotes(bool $a_pub_notes)
setActivePreventGlossaryAppendix(bool $a_print)
createImportDirectory()
creates data directory for import files (data_dir/lm_data/lm_<id>/import, depending on data directory...
static lookupAutoGlossaries(int $a_lm_id)
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
const POS_LAST_NODE
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$lm_set
static _checkAllConditionsOfTarget(int $a_target_ref_id, int $a_target_id, string $a_target_type="", int $a_usr_id=0)
checks wether all conditions of a target object are fulfilled
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ILIAS Style Content DomainService $content_style_domain
static getPageList(int $lm_id)
ilErrorHandling $error
autoLinkGlossaryTerms(int $a_glo_ref_id)
static _getNrLMsIndividualStyles()
get number of learning modules with individual styles
exportXMLStructureObjects(ilXmlWriter $a_xml_writer, int $a_inst, ilLog $expLog)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$q
Definition: shib_logout.php:21
setDisableDefaultFeedback(bool $a_val)
Set disable default feedback for questions.
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
copyAllPagesAndChapters(ilObjLearningModule $a_target_obj, int $a_copy_id=0)
static yn2tf(string $a_yn)
static _getInstance(int $a_copy_id)
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
write(string $a_msg, $a_log_level=null)
logging
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
exportXML(ilXmlWriter $a_xml_writer, int $a_inst, string $a_target_dir, ilLog $expLog)
getSubTree(array $a_node, bool $a_with_data=true, array $a_type=[])
get all nodes in the subtree under specified node
static _lookupType(int $id, bool $reference=false)
setHideHeaderFooterPrint(bool $a_val)
Set hide header footer in print mode.
exportXMLProperties(ilXmlWriter $a_xml_writer, ilLog $expLog)
static getInstance(int $obj_id)
createProperties()
create new properties record
static _lookup(int $a_obj_id, string $a_field)
static _getMissingPreconditionsTopChapter(int $cont_obj_ref_id, int $cont_obj_id, int $page_id)
get top chapter of page for that any precondition is missing
ILIAS Notes Service $notes
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
exportXMLPageObjects(ilXmlWriter $a_xml_writer, int $a_inst, ilLog $expLog)
static _getPersistedConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id, string $a_target_type="")
get all persisted conditions of target object
static isOnlineHelpModule(int $a_id, bool $a_as_obj_id=false)
Is module an online module.
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
setPublicAccessMode(string $a_mode)
static getAllPages(string $a_parent_type, int $a_parent_id, string $a_lang="-")
Get all pages for parent object.