ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilObject.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
27use ILIAS\Data\Factory as DataFactory;
28
38{
39 public const TITLE_LENGTH = 255; // title column max length in db
40 public const DESC_LENGTH = 128; // (short) description column max length in db
41 public const LONG_DESC_LENGTH = 4000; // long description column max length in db
42 public const TABLE_OBJECT_DATA = "object_data";
43 private const DATABASE_DATE_FORMAT = 'Y-m-d H:i:s';
44
46
47 protected ilLogger $obj_log;
48 protected ?ILIAS $ilias;
50 protected ilDBInterface $db;
51 protected ?ilLogger $log;
53 protected ilTree $tree;
57 protected ilObjUser $user;
58 protected ilLanguage $lng;
59 protected LOMServices $lom_services;
61 private TranslationsRepository $translations_repository;
62
63 protected bool $call_by_reference;
66 protected bool $add_dots = true;
67 protected ?int $ref_id = null;
68 protected string $type = "";
69 protected string $title = "";
70 protected string $desc = "";
71 protected string $long_desc = "";
72 protected int $owner = 0;
73 protected string $create_date = "";
74 protected string $last_update = "";
75 protected string $import_id = "";
76 protected bool $register = false; // registering required for object? set to true to implement a subscription interface
77
78 private bool $process_auto_reating = false;
79
80
84 public array $objectList;
85
86
87 // BEGIN WebDAV: WebDAV needs to access the untranslated title of an object
88 public string $untranslatedTitle;
89 // END WebDAV: WebDAV needs to access the untranslated title of an object
90
95 public function __construct(
96 protected int $id = 0,
97 protected bool $referenced = true
98 ) {
100 global $DIC;
101
102 $this->ilias = $DIC["ilias"];
103 $this->obj_definition = $DIC["objDefinition"];
104 $this->db = $DIC["ilDB"];
105 $this->log = $DIC["ilLog"];
106 $this->obj_log = ilLoggerFactory::getLogger("obj");
107 $this->error = $DIC["ilErr"];
108 $this->tree = $DIC["tree"];
109 $this->app_event_handler = $DIC["ilAppEventHandler"];
110 $this->lom_services = $DIC->learningObjectMetadata();
111 $object_dic = LocalDIC::dic();
112 $this->properties_aggregator = $object_dic['properties.aggregator'];
113 $this->translations_repository = $object_dic['properties.translations.repository'];
114
115 $this->call_by_reference = $this->referenced;
116
117 if (isset($DIC["lng"])) {
118 $this->lng = $DIC["lng"];
119 }
120
121 if (isset($DIC["ilUser"])) {
122 $this->user = $DIC["ilUser"];
123 }
124
125 if (isset($DIC["rbacadmin"])) {
126 $this->rbac_admin = $DIC["rbacadmin"];
127 }
128
129 if (isset($DIC["rbacreview"])) {
130 $this->rbac_review = $DIC["rbacreview"];
131 }
132
133 if ($id == 0) {
134 $this->referenced = false; // newly created objects are never referenced
135 } // they will get referenced if createReference() is called
136
137 if ($this->referenced) {
138 $this->ref_id = $id;
139 } else {
140 $this->id = $id;
141 }
142 // read object data
143 if ($id != 0) {
144 $this->read();
145 }
146 }
147
149 {
150 if ($this->object_properties === null) {
151 $this->object_properties = $this->properties_aggregator->getFor($this->id, $this->type);
152 }
154 }
155
159 public function flushObjectProperties(): void
160 {
161 $this->object_properties = null;
162 }
163
167 final public function withReferences(): bool
168 {
169 // both vars could differ. this method should always return true if one of them is true without changing their status
170 return ($this->call_by_reference) ? true : $this->referenced;
171 }
172
177 public function processAutoRating(): void
178 {
179 $this->process_auto_reating = true;
180 }
181
182 public function read(): void
183 {
184 global $DIC;
185 try {
186 $ilUser = $DIC["ilUser"];
187 } catch (InvalidArgumentException $e) {
188 }
189
190 if ($this->referenced) {
191 if (!isset($this->ref_id)) {
192 $message = "ilObject::read(): No ref_id given! (" . $this->type . ")";
193 $this->error->raiseError($message, $this->error->WARNING);
194 }
195
196 // read object data
197 $sql =
198 "SELECT od.obj_id, od.type, od.title, od.description, od.owner, od.create_date," . PHP_EOL
199 . "od.last_update, od.import_id, ore.ref_id, ore.obj_id, ore.deleted, ore.deleted_by" . PHP_EOL
200 . "FROM " . self::TABLE_OBJECT_DATA . " od" . PHP_EOL
201 . "JOIN object_reference ore ON od.obj_id = ore.obj_id" . PHP_EOL
202 . "WHERE ore.ref_id = " . $this->db->quote($this->ref_id, "integer") . PHP_EOL
203 ;
204
205 $result = $this->db->query($sql);
206
207 // check number of records
208 if ($this->db->numRows($result) === 0) {
209 $message = sprintf(
210 "ilObject::read(): Object with ref_id %s not found! (%s)",
211 $this->ref_id,
212 $this->type
213 );
214 $this->error->raiseError($message, $this->error->WARNING);
215 }
216 } else {
217 if (!isset($this->id)) {
218 $message = sprintf("ilObject::read(): No obj_id given! (%s)", $this->type);
219 $this->error->raiseError($message, $this->error->WARNING);
220 }
221
222 $sql =
223 "SELECT obj_id, type, title, description, owner, create_date, last_update, import_id, offline" . PHP_EOL
224 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
225 . "WHERE obj_id = " . $this->db->quote($this->id, "integer") . PHP_EOL
226 ;
227 $result = $this->db->query($sql);
228
229 if ($this->db->numRows($result) === 0) {
230 $message = sprintf("ilObject::read(): Object with obj_id: %s (%s) not found!", $this->id, $this->type);
232 }
233 }
234 $obj = $this->db->fetchAssoc($result);
235
236 $this->id = (int) $obj["obj_id"];
237
238 // check type match (the "xxx" type is used for the unit test)
239 if ($this->type != $obj["type"] && $obj["type"] != "xxx") {
240 $message = sprintf(
241 "ilObject::read(): Type mismatch. Object with obj_id: %s was instantiated by type '%s'. DB type is: %s",
242 $this->id,
243 $this->type,
244 $obj["type"]
245 );
246
247 $this->log->write($message);
249 }
250
251 $this->type = (string) $obj["type"];
252 $this->title = (string) $obj["title"];
253 // BEGIN WebDAV: WebDAV needs to access the untranslated title of an object
254 $this->untranslatedTitle = (string) $obj["title"];
255 // END WebDAV: WebDAV needs to access the untranslated title of an object
256
257 $this->desc = (string) $obj["description"];
258 $this->owner = (int) $obj["owner"];
259 $this->create_date = (string) $obj["create_date"];
260 $this->last_update = (string) $obj["last_update"];
261 $this->import_id = (string) $obj["import_id"];
262
263 if ($this->obj_definition->isRBACObject($this->getType())) {
264 $sql =
265 "SELECT obj_id, description" . PHP_EOL
266 . "FROM object_description" . PHP_EOL
267 . "WHERE obj_id = " . $this->db->quote($this->id, 'integer') . PHP_EOL
268 ;
269
270 $res = $this->db->query($sql);
271
272 $this->long_desc = '';
273 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
274 if (($row->description ?? '') !== '') {
275 $this->setDescription($row->description);
276 }
277 }
278 }
279
280 // multilingual support system objects (sys) & categories (db)
281 $translation_type = $this->obj_definition->getTranslationType($this->type);
282
283 if ($translation_type == "sys") {
284 $this->title = $this->lng->txt("obj_" . $this->type);
285 $this->setDescription($this->lng->txt("obj_" . $this->type . "_desc"));
286 } elseif ($translation_type == "db") {
287 $sql =
288 "SELECT title, description" . PHP_EOL
289 . "FROM object_translation" . PHP_EOL
290 . "WHERE obj_id = " . $this->db->quote($this->id, 'integer') . PHP_EOL
291 . "AND lang_code = " . $this->db->quote($ilUser->getCurrentLanguage(), 'text') . PHP_EOL
292 ;
293 $r = $this->db->query($sql);
294 $row = $r->fetchRow(ilDBConstants::FETCHMODE_OBJECT);
295 if ($row) {
296 $this->title = (string) $row->title;
297 $this->setDescription((string) $row->description);
298 }
299 }
300
301 $this->object_properties = null;
302 }
303
304 public function getId(): int
305 {
306 return $this->id;
307 }
308
309 public function setId(int $id): void
310 {
311 $this->id = $id;
312 }
313
314 final public function setRefId(int $ref_id): void
315 {
316 $this->ref_id = $ref_id;
317 $this->referenced = true;
318 }
319
320 final public function getRefId(): int
321 {
322 return $this->ref_id ?? 0;
323 }
324
325 public function getType(): string
326 {
327 return $this->type;
328 }
329
330 final public function setType(string $type): void
331 {
332 $this->type = $type;
333 }
334
340 public function getPresentationTitle(): string
341 {
342 return $this->getTitle();
343 }
344
345 public function getTitle(): string
346 {
347 return $this->title;
348 }
349
354 final public function getUntranslatedTitle(): string
355 {
357 }
358
359 final public function setTitle(string $title): void
360 {
361 $property = $this->getObjectProperties()->getPropertyTitleAndDescription()->withTitle(
362 ilStr::shortenTextExtended($title, $this->max_title ?? self::TITLE_LENGTH, $this->add_dots)
363 );
364
365 $this->object_properties = $this->getObjectProperties()->withPropertyTitleAndDescription($property);
366
367 $this->title = $property->getTitle();
368
369 // WebDAV needs to access the untranslated title of an object
370 $this->untranslatedTitle = $this->title;
371 }
372
373 final public function getDescription(): string
374 {
375 return $this->desc;
376 }
377
378 final public function setDescription(string $description): void
379 {
380 $property = $this->getObjectProperties()
381 ->getPropertyTitleAndDescription()->withDescription($description);
382
383 $this->object_properties = $this->getObjectProperties()->withPropertyTitleAndDescription($property);
384
385 // Shortened form is storted in object_data. Long form is stored in object_description
386 $this->desc = $property->getDescription();
387 $this->long_desc = $property->getLongDescription();
388 }
389
393 public function getLongDescription(): string
394 {
395 if ($this->long_desc !== '') {
396 return $this->long_desc;
397 }
398
399 if ($this->desc !== '') {
400 return $this->desc;
401 }
402 return '';
403 }
404
405 final public function getImportId(): string
406 {
407 return $this->import_id;
408 }
409
410 final public function setImportId(string $import_id): void
411 {
412 $this->object_properties = $this->getObjectProperties()->withImportId($import_id);
413 $this->import_id = $import_id;
414 }
415
419 final public static function _lookupObjIdByImportId(string $import_id): int
420 {
421 global $DIC;
422 $db = $DIC->database();
423
424 $sql =
425 "SELECT obj_id" . PHP_EOL
426 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
427 . "WHERE import_id = " . $db->quote($import_id, "text") . PHP_EOL
428 . "ORDER BY create_date DESC" . PHP_EOL
429 ;
430 $result = $db->query($sql);
431
432 if ($db->numRows($result) == 0) {
433 return 0;
434 }
435
436 $row = $db->fetchObject($result);
437
438 return (int) $row->obj_id;
439 }
440
444 public function setOfflineStatus(bool $status): void
445 {
446 $property_is_online = $this->getObjectProperties()->getPropertyIsOnline()->withOnline();
447 if ($status) {
448 $property_is_online = $property_is_online->withOffline();
449 }
450
451 $this->object_properties = $this->getObjectProperties()->withPropertyIsOnline($property_is_online);
452 }
453
454 public function getOfflineStatus(): bool
455 {
456 return !$this->getObjectProperties()->getPropertyIsOnline()->getIsOnline();
457 }
458
459 public function supportsOfflineHandling(): bool
460 {
461 return $this->obj_definition->supportsOfflineHandling($this->getType());
462 }
463
464 public static function _lookupImportId(int $obj_id): string
465 {
466 global $DIC;
467
468 $db = $DIC->database();
469
470 $sql =
471 "SELECT import_id" . PHP_EOL
472 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
473 . "WHERE obj_id = " . $db->quote($obj_id, "integer") . PHP_EOL
474 ;
475
476 $res = $db->query($sql);
477 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
478 return (string) $row->import_id;
479 }
480 return '';
481 }
482
483 final public function getOwner(): int
484 {
485 return $this->owner;
486 }
487
491 final public function getOwnerName(): string
492 {
493 return ilObject::_lookupOwnerName($this->getOwner());
494 }
495
499 final public static function _lookupOwnerName(int $owner_id): string
500 {
501 global $DIC;
502 $lng = $DIC->language();
503
504 $owner = null;
505 if ($owner_id != -1) {
506 if (ilObject::_exists($owner_id)) {
507 $owner = new ilObjUser($owner_id);
508 }
509 }
510
511 $own_name = $lng->txt("unknown");
512 if (is_object($owner)) {
513 $own_name = $owner->getFullname();
514 }
515
516 return $own_name;
517 }
518
519 final public function setOwner(int $usr_id): void
520 {
521 $this->owner = $usr_id;
522 }
523
527 final public function getCreateDate(): string
528 {
529 return $this->create_date;
530 }
531
535 final public function getLastUpdateDate(): string
536 {
537 return $this->last_update;
538 }
539
540
544 public function create(): int
545 {
546 global $DIC;
547 $user = $DIC["ilUser"];
548
549 if (!isset($this->type)) {
550 $message = sprintf("%s::create(): No object type given!", get_class($this));
551 $this->error->raiseError($message, $this->error->WARNING);
552 }
553
554 $this->log->write("ilObject::create(), start");
555
556 // determine owner
557 $owner = 0;
558 if ($this->getOwner() > 0) {
559 $owner = $this->getOwner();
560 } elseif (is_object($user)) {
561 $owner = $user->getId();
562 }
563
564 $now_string = (new DataFactory())->clock()->utc()->now()
565 ->format(self::DATABASE_DATE_FORMAT);
566
567 $this->id = $this->db->nextId(self::TABLE_OBJECT_DATA);
568 $values = [
569 "obj_id" => ["integer", $this->getId()],
570 "type" => ["text", $this->getType()],
571 "title" => ["text", $this->getTitle()],
572 "description" => ["text", $this->getDescription()],
573 "owner" => ["integer", $owner],
574 "create_date" => ["date", $now_string],
575 "last_update" => ["date", $now_string],
576 "import_id" => ["text", $this->getImportId()],
577 ];
578
579 $this->db->insert(self::TABLE_OBJECT_DATA, $values);
580 $this->object_properties = null;
581
582 // Save long form of description if is rbac object
583 if ($this->obj_definition->isRBACObject($this->getType())) {
584 $values = [
585 'obj_id' => ['integer',$this->id],
586 'description' => ['clob', $this->getLongDescription()]
587 ];
588 $this->db->insert('object_description', $values);
589 }
590
591 if ($this->supportsOfflineHandling()) {
592 $property_is_online = $this->getObjectProperties()->getPropertyIsOnline()->withOffline();
593 $this->getObjectProperties()->storePropertyIsOnline($property_is_online);
594 }
595
596 if ($this->obj_definition->isOrgUnitPermissionType($this->type)) {
597 ilOrgUnitGlobalSettings::getInstance()->saveDefaultPositionActivationStatus($this->id);
598 }
599
600 // the line ($this->read();) messes up meta data handling: meta data,
601 // that is not saved at this time, gets lost, so we query for the dates alone
602 $sql =
603 "SELECT last_update, create_date" . PHP_EOL
604 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
605 . "WHERE obj_id = " . $this->db->quote($this->id, "integer") . PHP_EOL
606 ;
607 $obj_set = $this->db->query($sql);
608 $obj_rec = $this->db->fetchAssoc($obj_set);
609 $this->last_update = $obj_rec["last_update"];
610 $this->create_date = $obj_rec["create_date"];
611
612 // set owner for new objects
613 $this->setOwner($owner);
614
615 // write log entry
616 $this->log->write(
617 sprintf(
618 "ilObject::create(), finished, obj_id: %s, type: %s, title: %s",
619 $this->getId(),
620 $this->getType(),
621 $this->getTitle()
622 )
623 );
624
625 $this->app_event_handler->raise(
626 'components/ILIAS/ILIASObject',
627 'create',
628 [
629 'obj_id' => $this->id,
630 'obj_type' => $this->type
631 ]
632 );
633
634 return $this->id;
635 }
636
637 public function update(): bool
638 {
639 $this->getObjectProperties()->storeCoreProperties();
640
641 $this->app_event_handler->raise(
642 'components/ILIAS/ILIASObject',
643 'update',
644 [
645 'obj_id' => $this->getId(),
646 'obj_type' => $this->getType(),
647 'ref_id' => $this->getRefId()
648 ]
649 );
650
651 return true;
652 }
653
663 final public function MDUpdateListener(string $element): void
664 {
665 if ($this->beforeMDUpdateListener($element)) {
666 $this->app_event_handler->raise(
667 'components/ILIAS/ILIASObject',
668 'update',
669 ['obj_id' => $this->getId(),
670 'obj_type' => $this->getType(),
671 'ref_id' => $this->getRefId()
672 ]
673 );
674
675 // Update Title and description
676 if ($element == 'General') {
677 $paths = $this->lom_services->paths();
678 $reader = $this->lom_services->read(
679 $this->getId(),
680 0,
681 $this->getType(),
682 $paths->custom()->withNextStep('general')->get()
683 );
684
685 $this->setTitle($reader->firstData($paths->title())->value());
686 $this->setDescription($reader->firstData($paths->descriptions())->value());
687
688 $this->update();
689 }
690 $this->doMDUpdateListener($element);
691 }
692 }
693
694 protected function doMDUpdateListener(string $a_element): void
695 {
696 }
697
698 protected function beforeMDUpdateListener(string $a_element): bool
699 {
700 return true;
701 }
702
703 final public function createMetaData(): void
704 {
705 if ($this->beforeCreateMetaData()) {
706 global $DIC;
707 $ilUser = $DIC["ilUser"];
708
709 $this->lom_services->derive()->fromBasicProperties(
710 $this->getTitle(),
711 $this->getLongDescription(),
712 $ilUser->getPref('language')
713 )->forObject($this->getId(), 0, $this->getType());
714
715 $this->doCreateMetaData();
716 }
717 }
718
719 protected function doCreateMetaData(): void
720 {
721 }
722
723 protected function beforeCreateMetaData(): bool
724 {
725 return true;
726 }
727
728 final public function updateMetaData(): void
729 {
730 if ($this->beforeUpdateMetaData()) {
731 $paths = $this->lom_services->paths();
732
733 $manipulator = $this->lom_services->manipulate($this->getId(), 0, $this->getType())
734 ->prepareCreateOrUpdate($paths->title(), $this->getTitle());
735
736 if ($this->getDescription() !== '') {
737 $manipulator = $manipulator->prepareCreateOrUpdate(
738 $paths->firstDescription(),
739 $this->getLongDescription()
740 );
741 } else {
742 $manipulator = $manipulator->prepareDelete($paths->firstDescription());
743 }
744
745 $manipulator->execute();
746 $this->doUpdateMetaData();
747 }
748 }
749
750 protected function doUpdateMetaData(): void
751 {
752 }
753
754 protected function beforeUpdateMetaData(): bool
755 {
756 return true;
757 }
758
759 final public function deleteMetaData(): void
760 {
761 if ($this->beforeDeleteMetaData()) {
762 $this->lom_services->deleteAll($this->getId(), 0, $this->getType());
763 $this->doDeleteMetaData();
764 }
765 }
766
767 protected function doDeleteMetaData(): void
768 {
769 }
770
771 protected function beforeDeleteMetaData(): bool
772 {
773 return true;
774 }
775
779 final public function updateOwner(): void
780 {
781 $values = [
782 "owner" => ["integer", $this->getOwner()],
783 "last_update" => [
784 "date",
785 (new DateTimeImmutable('@' . time(), new DateTimeZone('UTC')))
786 ->format(self::DATABASE_DATE_FORMAT)
787 ]
788 ];
789
790 $where = [
791 "obj_id" => ["integer", $this->getId()]
792 ];
793
794 $this->db->update(self::TABLE_OBJECT_DATA, $values, $where);
795
796 // get current values from database so last_update is updated as well
797 $this->read();
798 }
799
800 final public static function _getIdForImportId(string $import_id): int
801 {
802 global $DIC;
803 $db = $DIC->database();
804 $db->setLimit(1, 0);
805
806 $sql =
807 "SELECT obj_id" . PHP_EOL
808 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
809 . "WHERE import_id = " . $db->quote($import_id, "text") . PHP_EOL
810 . "ORDER BY create_date DESC" . PHP_EOL
811 ;
812
813 $result = $db->query($sql);
814
815 if ($row = $db->fetchAssoc($result)) {
816 return (int) $row["obj_id"];
817 }
818
819 return 0;
820 }
821
826 final public static function _getAllReferences(int $id): array
827 {
828 global $DIC;
829 $db = $DIC->database();
830
831 $sql =
832 "SELECT ref_id" . PHP_EOL
833 . "FROM object_reference" . PHP_EOL
834 . "WHERE obj_id = " . $db->quote($id, 'integer') . PHP_EOL
835 ;
836
837 $result = $db->query($sql);
838
839 $ref = [];
840 while ($row = $db->fetchAssoc($result)) {
841 $ref[(int) $row["ref_id"]] = (int) $row["ref_id"];
842 }
843
844 return $ref;
845 }
846
847 public static function _lookupTitle(int $obj_id): string
848 {
849 global $DIC;
850 return (string) $DIC["ilObjDataCache"]->lookupTitle($obj_id);
851 }
852
856 public static function lookupOfflineStatus(int $obj_id): bool
857 {
858 global $DIC;
859 return $DIC['ilObjDataCache']->lookupOfflineStatus($obj_id);
860 }
861
865 final public static function _lookupOwner(int $obj_id): int
866 {
867 global $DIC;
868 return (int) $DIC["ilObjDataCache"]->lookupOwner($obj_id);
869 }
870
874 final public static function _getIdsForTitle(string $title, string $type = '', bool $partial_match = false): array
875 {
876 global $DIC;
877 $db = $DIC->database();
878
879 $where = "title = " . $db->quote($title, "text");
880 if ($partial_match) {
881 $where = $db->like("title", "text", '%' . $title . '%');
882 }
883
884 $sql =
885 "SELECT obj_id" . PHP_EOL
886 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
887 . "WHERE " . $where . PHP_EOL
888 ;
889
890 if ($type != '') {
891 $sql .= " AND type = " . $db->quote($type, "text");
892 }
893
894 $result = $db->query($sql);
895
896 $object_ids = [];
897 while ($row = $db->fetchAssoc($result)) {
898 $object_ids[] = (int) $row['obj_id'];
899 }
900
901 return $object_ids;
902 }
903
904 final public static function _lookupDescription(int $obj_id): string
905 {
906 global $DIC;
907 return (string) $DIC["ilObjDataCache"]->lookupDescription($obj_id);
908 }
909
910 final public static function _lookupLastUpdate(int $obj_id, bool $formatted = false): string
911 {
912 global $DIC;
913
914 $last_update = $DIC["ilObjDataCache"]->lookupLastUpdate($obj_id);
915
916 if ($formatted) {
918 }
919
920 return (string) $last_update;
921 }
922
923 final public static function _getLastUpdateOfObjects(array $obj_ids): string
924 {
925 global $DIC;
926 $db = $DIC->database();
927
928 $sql =
929 "SELECT MAX(last_update) as last_update" . PHP_EOL
930 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
931 . "WHERE " . $db->in("obj_id", $obj_ids, false, "integer") . PHP_EOL
932 ;
933
934 $result = $db->query($sql);
935 $row = $db->fetchAssoc($result);
936
937 return (string) $row["last_update"];
938 }
939
940 final public static function _lookupObjId(int $ref_id): int
941 {
942 global $DIC;
943 return $DIC["ilObjDataCache"]->lookupObjId($ref_id);
944 }
945
946 final public static function _setDeletedDate(int $ref_id, int $deleted_by): void
947 {
948 global $DIC;
949 $db = $DIC->database();
950
951 $values = [
952 "deleted" => ["date", $db->now()],
953 "deleted_by" => ["integer", $deleted_by]
954 ];
955
956 $where = [
957 "ref_id" => ["integer", $ref_id]
958 ];
959
960 $db->update("object_reference", $values, $where);
961 }
962
966 public static function setDeletedDates(array $ref_ids, int $user_id): void
967 {
968 global $DIC;
969 $db = $DIC->database();
970
971 $sql =
972 "UPDATE object_reference" . PHP_EOL
973 . "SET deleted = " . $db->now() . ", " . PHP_EOL
974 . "deleted_by = " . $db->quote($user_id, "integer") . PHP_EOL
975 . "WHERE " . $db->in("ref_id", $ref_ids, false, "integer") . PHP_EOL;
976
977 $db->manipulate($sql);
978 }
979
980 final public static function _resetDeletedDate(int $ref_id): void
981 {
982 global $DIC;
983 $db = $DIC->database();
984
985 $values = [
986 "deleted" => ["timestamp", null],
987 "deleted_by" => ["integer", 0]
988 ];
989
990 $where = [
991 "ref_id" => ["integer", $ref_id]
992 ];
993
994 $db->update("object_reference", $values, $where);
995 }
996
997 final public static function _lookupDeletedDate(int $ref_id): ?string
998 {
999 global $DIC;
1000 $db = $DIC->database();
1001
1002 $sql =
1003 "SELECT deleted" . PHP_EOL
1004 . "FROM object_reference" . PHP_EOL
1005 . "WHERE ref_id = " . $db->quote($ref_id, "integer") . PHP_EOL
1006 ;
1007 $result = $db->query($sql);
1008 $row = $db->fetchAssoc($result);
1009
1010 return $row["deleted"] ?? null;
1011 }
1012
1016 final public static function _writeTitle(int $obj_id, string $title): void
1017 {
1018 global $DIC;
1019 $db = $DIC->database();
1020
1021 $values = [
1022 "title" => ["text", $title],
1023 "last_update" => ["date", $db->now()]
1024 ];
1025
1026 $where = [
1027 "obj_id" => ["integer", $obj_id]
1028 ];
1029
1030 $db->update(self::TABLE_OBJECT_DATA, $values, $where);
1031 }
1032
1036 final public static function _writeDescription(int $obj_id, string $desc): void
1037 {
1038 global $DIC;
1039
1040 $db = $DIC->database();
1041 $obj_definition = $DIC["objDefinition"];
1042
1043 $desc = ilStr::shortenTextExtended($desc, self::DESC_LENGTH, true);
1044
1045 $values = [
1046 "description" => ["text", $desc],
1047 "last_update" => ["date", $db->now()]
1048 ];
1049
1050 $where = [
1051 "obj_id" => ["integer", $obj_id]
1052 ];
1053
1054 $db->update(self::TABLE_OBJECT_DATA, $values, $where);
1055
1056
1058 // Update long description
1059 $sql =
1060 "SELECT obj_id, description" . PHP_EOL
1061 . "FROM object_description" . PHP_EOL
1062 . "WHERE obj_id = " . $db->quote($obj_id, 'integer') . PHP_EOL
1063 ;
1064 $result = $db->query($sql);
1065
1066 if ($result->numRows()) {
1067 $values = [
1068 "description" => ["clob", $desc]
1069 ];
1070 $db->update("object_description", $values, $where);
1071 } else {
1072 $values = [
1073 "description" => ["clob",$desc],
1074 "obj_id" => ["integer",$obj_id]
1075 ];
1076 $db->insert("object_description", $values);
1077 }
1078 }
1079 }
1080
1084 final public static function _writeImportId(int $obj_id, string $import_id): void
1085 {
1086 global $DIC;
1087 $db = $DIC->database();
1088
1089 $values = [
1090 "import_id" => ["text", $import_id],
1091 "last_update" => ["date", $db->now()]
1092 ];
1093
1094 $where = [
1095 "obj_id" => ["integer", $obj_id]
1096 ];
1097
1098 $db->update(self::TABLE_OBJECT_DATA, $values, $where);
1099 }
1100
1101 final public static function _lookupType(int $id, bool $reference = false): string
1102 {
1103 global $DIC;
1104
1105 if ($reference) {
1106 return $DIC["ilObjDataCache"]->lookupType($DIC["ilObjDataCache"]->lookupObjId($id));
1107 }
1108
1109 return $DIC["ilObjDataCache"]->lookupType($id);
1110 }
1111
1112 final public static function _isInTrash(int $ref_id): bool
1113 {
1114 global $DIC;
1115 return $DIC->repositoryTree()->isDeleted($ref_id);
1116 }
1117
1121 final public static function _hasUntrashedReference(int $obj_id): bool
1122 {
1123 $ref_ids = ilObject::_getAllReferences($obj_id);
1124 foreach ($ref_ids as $ref_id) {
1126 return true;
1127 }
1128 }
1129
1130 return false;
1131 }
1132
1133 final public static function _lookupObjectId(int $ref_id): int
1134 {
1135 global $DIC;
1136 return $DIC["ilObjDataCache"]->lookupObjId($ref_id);
1137 }
1138
1146 final public static function _getObjectsDataForType(string $type, bool $omit_trash = false): array
1147 {
1148 global $DIC;
1149 $db = $DIC->database();
1150
1151 $sql =
1152 "SELECT obj_id, type, title, description, owner, create_date, last_update, import_id, offline" . PHP_EOL
1153 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
1154 . "WHERE type = " . $db->quote($type, "text") . PHP_EOL
1155 ;
1156 $result = $db->query($sql);
1157
1158 $objects = [];
1159 while ($row = $db->fetchAssoc($result)) {
1160 if ((!$omit_trash) || ilObject::_hasUntrashedReference((int) $row["obj_id"])) {
1161 $objects[$row["title"] . "." . $row["obj_id"]] = [
1162 "id" => $row["obj_id"],
1163 "type" => $row["type"],
1164 "title" => $row["title"],
1165 "description" => $row["description"]
1166 ];
1167 }
1168 }
1169 ksort($objects);
1170 return $objects;
1171 }
1172
1173
1179 public function putInTree(int $parent_ref_id): void
1180 {
1181 $this->tree->insertNode($this->getRefId(), $parent_ref_id);
1182 $this->handleAutoRating();
1183
1184 $log_entry = sprintf(
1185 "ilObject::putInTree(), parent_ref: %s, ref_id: %s, obj_id: %s, type: %s, title: %s",
1186 $parent_ref_id,
1187 $this->getRefId(),
1188 $this->getId(),
1189 $this->getType(),
1190 $this->getTitle()
1191 );
1192
1193 $this->log->write($log_entry);
1194
1195 $this->app_event_handler->raise(
1196 'components/ILIAS/ILIASObject',
1197 'putObjectInTree',
1198 [
1199 'object' => $this,
1200 'obj_type' => $this->getType(),
1201 'obj_id' => $this->getId(),
1202 'parent_ref_id' => $parent_ref_id
1203 ]
1204 );
1205 }
1206
1207 public function setPermissions(int $parent_ref_id): void
1208 {
1209 $this->setParentRolePermissions($parent_ref_id);
1210 $this->initDefaultRoles();
1211 }
1212
1218 public function setParentRolePermissions(int $parent_ref_id): bool
1219 {
1220 $parent_roles = $this->rbac_review->getParentRoleIds($parent_ref_id);
1221 foreach ($parent_roles as $parent_role) {
1222 if ($parent_role['obj_id'] == SYSTEM_ROLE_ID) {
1223 continue;
1224 }
1225 $operations = $this->rbac_review->getOperationsOfRole(
1226 (int) $parent_role['obj_id'],
1227 $this->getType(),
1228 (int) $parent_role['parent']
1229 );
1230 $this->rbac_admin->grantPermission(
1231 (int) $parent_role['obj_id'],
1232 $operations,
1233 $this->getRefId()
1234 );
1235 }
1236 return true;
1237 }
1238
1242 public function createReference(): int
1243 {
1244 if (!isset($this->id)) {
1245 $message = "ilObject::createNewReference(): No obj_id given!";
1246 $this->error->raiseError($message, $this->error->WARNING);
1247 }
1248
1249 $next_id = $this->db->nextId('object_reference');
1250
1251 $values = [
1252 "ref_id" => ["integer", $next_id],
1253 "obj_id" => ["integer", $this->getId()]
1254 ];
1255
1256 $this->db->insert("object_reference", $values);
1257
1258 $this->ref_id = $next_id;
1259 $this->referenced = true;
1260
1261 return $this->ref_id;
1262 }
1263
1264 final public function countReferences(): int
1265 {
1266 if (!isset($this->id)) {
1267 $message = "ilObject::countReferences(): No obj_id given!";
1268 $this->error->raiseError($message, $this->error->WARNING);
1269 }
1270
1271 $sql =
1272 "SELECT COUNT(ref_id) num" . PHP_EOL
1273 . "FROM object_reference" . PHP_EOL
1274 . "WHERE obj_id = " . $this->db->quote($this->id, 'integer') . PHP_EOL
1275 ;
1276
1277 $res = $this->db->query($sql);
1278 $row = $this->db->fetchObject($res);
1279
1280 return (int) $row->num;
1281 }
1282
1291 public function delete(): bool
1292 {
1293 global $DIC;
1294 $rbac_admin = $DIC["rbacadmin"];
1295
1296 $remove = false;
1297
1298 // delete object_data entry
1299 if ((!$this->referenced) || ($this->countReferences() == 1)) {
1300 $type = ilObject::_lookupType($this->getId());
1301 if ($this->type != $type) {
1302 $log_entry = sprintf(
1303 "ilObject::delete(): Type mismatch. Object with obj_id: %s was instantiated by type '%s'. DB type is: %s",
1304 $this->id,
1305 $this->type,
1306 $type
1307 );
1308
1309 $this->log->write($log_entry);
1310 $this->error->raiseError(
1311 sprintf("ilObject::delete(): Type mismatch. (%s/%s)", $this->type, $this->id),
1312 $this->error->WARNING
1313 );
1314 }
1315
1316 $this->app_event_handler->raise('components/ILIAS/ILIASObject', 'beforeDeletion', ['object' => $this]);
1317
1318 $this->getObjectProperties()->deletePropertyTranslations();
1319
1320 $sql =
1321 "DELETE FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
1322 . "WHERE obj_id = " . $this->db->quote($this->getId(), "integer") . PHP_EOL
1323 ;
1324 $this->db->manipulate($sql);
1325
1326 $sql =
1327 "DELETE FROM object_description" . PHP_EOL
1328 . "WHERE obj_id = " . $this->db->quote($this->getId(), "integer") . PHP_EOL
1329 ;
1330 $this->db->manipulate($sql);
1331
1332 $this->log->write(
1333 sprintf(
1334 "ilObject::delete(), deleted object, obj_id: %s, type: %s, title: %s",
1335 $this->getId(),
1336 $this->getType(),
1337 $this->getTitle()
1338 )
1339 );
1340
1341 // keep log of core object data
1343
1344 // remove news
1345 $news_item = new ilNewsItem();
1346 $news_item->deleteNewsOfContext($this->getId(), $this->getType());
1348
1350
1351 // BEGIN WebDAV: Delete WebDAV properties
1352 $sql =
1353 "DELETE FROM dav_property" . PHP_EOL
1354 . "WHERE obj_id = " . $this->db->quote($this->getId(), 'integer') . PHP_EOL
1355 ;
1356 $this->db->manipulate($sql);
1357 // END WebDAV: Delete WebDAV properties
1358
1359 ilECSImportManager::getInstance()->_deleteByObjId($this->getId());
1362
1363 $remove = true;
1364 } else {
1365 $this->log->write(
1366 sprintf(
1367 "ilObject::delete(), object not deleted, number of references: %s, obj_id: %s, type: %s, title: %s",
1368 $this->countReferences(),
1369 $this->getId(),
1370 $this->getType(),
1371 $this->getTitle()
1372 )
1373 );
1374 }
1375
1376 // delete object_reference entry
1377 if ($this->referenced) {
1379
1380 $this->app_event_handler->raise('components/ILIAS/ILIASObject', 'deleteReference', ['ref_id' => $this->getRefId()]);
1381
1382 $sql =
1383 "DELETE FROM object_reference" . PHP_EOL
1384 . "WHERE ref_id = " . $this->db->quote($this->getRefId(), 'integer') . PHP_EOL
1385 ;
1386 $this->db->manipulate($sql);
1387
1388 $this->log->write(
1389 sprintf(
1390 "ilObject::delete(), reference deleted, ref_id: %s, obj_id: %s, type: %s, title: %s",
1391 $this->getRefId(),
1392 $this->getId(),
1393 $this->getType(),
1394 $this->getTitle()
1395 )
1396 );
1397
1398 // DELETE PERMISSION ENTRIES IN RBAC_PA
1399 // DONE: method overwritten in ilObjRole & ilObjUser.
1400 // this call only applies for objects in rbac (not usr,role,rolt)
1401 // TODO: Do this for role templates too
1402 $rbac_admin->revokePermission($this->getRefId(), 0, false);
1403
1404 ilRbacLog::delete($this->getRefId());
1405
1406 // Remove applied didactic template setting
1408 }
1409
1410 // remove conditions
1411 if ($this->referenced) {
1412 $ch = new ilConditionHandler();
1413 $ch->delete($this->getRefId());
1414 unset($ch);
1415 }
1416
1417 return $remove;
1418 }
1419
1427 public function initDefaultRoles(): void
1428 {
1429 }
1430
1431 public function applyDidacticTemplate(int $tpl_id): void
1432 {
1433 ilLoggerFactory::getLogger('obj')->debug('Applying didactic template with id: ' . $tpl_id);
1434 if ($tpl_id) {
1435 foreach (ilDidacticTemplateActionFactory::getActionsByTemplateId($tpl_id) as $action) {
1436 $action->setRefId($this->getRefId());
1437 $action->apply();
1438 }
1439 }
1440
1442 }
1443
1452 public static function _exists(int $id, bool $reference = false, ?string $type = null): bool
1453 {
1454 global $DIC;
1455 $db = $DIC->database();
1456
1457 if ($reference) {
1458 $sql =
1459 "SELECT object_data.obj_id" . PHP_EOL
1460 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
1461 . "LEFT JOIN object_reference ON object_reference.obj_id = object_data.obj_id " . PHP_EOL
1462 . "WHERE object_reference.ref_id= " . $db->quote($id, "integer") . PHP_EOL
1463 ;
1464 } else {
1465 $sql =
1466 "SELECT object_data.obj_id" . PHP_EOL
1467 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
1468 . "WHERE obj_id = " . $db->quote($id, "integer") . PHP_EOL
1469 ;
1470 }
1471
1472 if ($type) {
1473 $sql .= " AND object_data.type = " . $db->quote($type, "text") . PHP_EOL;
1474 }
1475
1476 $result = $db->query($sql);
1477
1478 return (bool) $db->numRows($result);
1479 }
1480
1481 public function getXMLZip(): string
1482 {
1483 return "";
1484 }
1485 public function getHTMLDirectory(): bool
1486 {
1487 return false;
1488 }
1489
1490 final public static function _getObjectsByType(string $obj_type = "", ?int $owner = null): array
1491 {
1492 global $DIC;
1493 $db = $DIC->database();
1494
1495 $order = " ORDER BY title";
1496
1497 $where = "";
1498 if ($obj_type) {
1499 $where = "WHERE type = " . $db->quote($obj_type, "text");
1500
1501 if (!is_null($owner)) {
1502 $where .= " AND owner = " . $db->quote($owner, "integer");
1503 }
1504 }
1505
1506 $sql =
1507 "SELECT obj_id, type, title, description, owner, create_date, last_update, import_id, offline" . PHP_EOL
1508 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
1509 . $where . PHP_EOL
1510 . $order . PHP_EOL
1511 ;
1512 $result = $db->query($sql);
1513
1514 $arr = [];
1515 if ($db->numRows($result) > 0) {
1516 while ($row = $db->fetchAssoc($result)) {
1517 $row["desc"] = $row["description"];
1518 $arr[$row["obj_id"]] = $row;
1519 }
1520 }
1521
1522 return $arr;
1523 }
1524
1531 final public static function _prepareCloneSelection(
1532 array $ref_ids,
1533 string $new_type,
1534 bool $show_path = true
1535 ): array {
1536 global $DIC;
1537
1538 $db = $DIC->database();
1539 $lng = $DIC->language();
1540 $obj_definition = $DIC["objDefinition"];
1541
1542 $sql =
1543 "SELECT obj_data.title obj_title, path_data.title path_title, child" . PHP_EOL
1544 . "FROM tree " . PHP_EOL
1545 . "JOIN object_reference obj_ref ON child = obj_ref.ref_id " . PHP_EOL
1546 . "JOIN object_data obj_data ON obj_ref.obj_id = obj_data.obj_id " . PHP_EOL
1547 . "JOIN object_reference path_ref ON parent = path_ref.ref_id " . PHP_EOL
1548 . "JOIN object_data path_data ON path_ref.obj_id = path_data.obj_id " . PHP_EOL
1549 . "WHERE " . $db->in("child", $ref_ids, false, "integer") . PHP_EOL
1550 . "ORDER BY obj_data.title" . PHP_EOL
1551 ;
1552 $res = $db->query($sql);
1553
1554 if (!$obj_definition->isPlugin($new_type)) {
1555 $options[0] = $lng->txt('obj_' . $new_type . '_select');
1556 } else {
1557 $options[0] = ilObjectPlugin::lookupTxtById($new_type, "obj_" . $new_type . "_select");
1558 }
1559
1560 while ($row = $db->fetchObject($res)) {
1561 if (strlen($title = $row->obj_title) > 40) {
1562 $title = substr($title, 0, 40) . '...';
1563 }
1564
1565 if ($show_path) {
1566 if (strlen($path = $row->path_title) > 40) {
1567 $path = substr($path, 0, 40) . '...';
1568 }
1569
1570 $title .= ' (' . $lng->txt('path') . ': ' . $path . ')';
1571 }
1572
1573 $options[$row->child] = $title;
1574 }
1575 return $options ?: [];
1576 }
1577
1581 public function cloneObject(int $target_id, int $copy_id = 0, bool $omit_tree = false): ?ilObject
1582 {
1584 global $DIC;
1585
1586 $ilUser = $DIC["ilUser"];
1587 $rbac_admin = $DIC["rbacadmin"];
1588
1589 $class_name = ('ilObj' . $this->obj_definition->getClassName($this->getType()));
1590
1591 $options = ilCopyWizardOptions::_getInstance($copy_id);
1592
1593 $this->obj_log->debug($this->getTitle());
1594 $this->obj_log->debug("isTreeCopyDisabled: " . $options->isTreeCopyDisabled());
1595 $this->obj_log->debug("omit_tree: " . $omit_tree);
1596
1598 $new_obj = new $class_name(0, false);
1599 $new_obj->setOwner($ilUser->getId());
1600 $new_obj->title = $this->getTitle();
1601 $new_obj->long_desc = $this->getLongDescription();
1602 $new_obj->desc = $this->getDescription();
1603 $new_obj->type = $this->getType();
1604
1605 // Choose upload mode to avoid creation of additional settings, db entries ...
1606 $new_obj->create(true);
1607
1608 if (!$options->isTreeCopyDisabled() && !$omit_tree) {
1609 $title_with_suffix = $this->appendCopyInfo($target_id, $copy_id, $new_obj->getId());
1610 $title = mb_strlen($title_with_suffix) < self::TITLE_LENGTH ? $title_with_suffix : $title;
1611 $this->obj_log->debug("title incl. copy info: " . $title);
1612 $new_obj->setTitle($title);
1613 $new_obj->update();
1614 }
1615
1616 if ($this->supportsOfflineHandling()) {
1617 if ($options->isRootNode($this->getRefId())) {
1618 $new_obj->getObjectProperties()->storePropertyIsOnline(
1619 $new_obj->getObjectProperties()->getPropertyIsOnline()->withOffline()
1620 );
1621 } else {
1622 $new_obj->getObjectProperties()->storePropertyIsOnline(
1623 $this->getObjectProperties()->getPropertyIsOnline()
1624 );
1625 }
1626 }
1627
1628 if (!$options->isTreeCopyDisabled() && !$omit_tree) {
1629 ilLoggerFactory::getLogger('obj')->debug('Tree copy is enabled');
1630 $new_obj->createReference();
1631 $new_obj->putInTree($target_id);
1632 $new_obj->setPermissions($target_id);
1633
1634 // when copying from personal workspace we have no current ref id
1635 if ($this->getRefId()) {
1636 // copy local roles
1637 $rbac_admin->copyLocalRoles($this->getRefId(), $new_obj->getRefId());
1638 }
1639 } else {
1640 ilLoggerFactory::getLogger('obj')->debug('Tree copy is disabled');
1641 }
1642
1643 ilAdvancedMDValues::_cloneValues($copy_id, $this->getId(), $new_obj->getId());
1644
1645 // BEGIN WebDAV: Clone WebDAV properties
1646 $sql =
1647 "INSERT INTO dav_property" . PHP_EOL
1648 . "(obj_id, node_id, ns, name, value)" . PHP_EOL
1649 . "SELECT " . $this->db->quote($new_obj->getId(), 'integer') . ", node_id, ns, name, value " . PHP_EOL
1650 . "FROM dav_property" . PHP_EOL
1651 . "WHERE obj_id = " . $this->db->quote($this->getId(), 'integer') . PHP_EOL
1652 ;
1653 $this->db->manipulate($sql);
1654 // END WebDAV: Clone WebDAV properties
1655
1656 $customIconFactory = $DIC['object.customicons.factory'];
1657 $customIcon = $customIconFactory->getByObjId($this->getId(), $this->getType());
1658 $customIcon->copy($new_obj->getId());
1659
1660 $new_obj->getObjectProperties()->storePropertyTileImage(
1661 $new_obj->getObjectProperties()->getPropertyTileImage()->withTileImage(
1662 $this->getObjectProperties()->getPropertyTileImage()
1663 ->getTileImage()->cloneFor($new_obj->getId())
1664 )
1665 );
1666
1667 $this->app_event_handler->raise(
1668 'components/ILIAS/ILIASObject',
1669 'cloneObject',
1670 [
1671 'object' => $new_obj,
1672 'cloned_from_object' => $this,
1673 ]
1674 );
1675
1676 return $new_obj;
1677 }
1678
1682 final public function appendCopyInfo(
1683 int $target_id,
1684 int $copy_id,
1685 int $new_obj_id
1686 ): string {
1687 $cp_options = ilCopyWizardOptions::_getInstance($copy_id);
1688 if (!$cp_options->isRootNode($this->getRefId())) {
1689 return $this->getTitle();
1690 }
1691
1692
1693 $obj_translations = $this->getObjectProperties()->clonePropertyTranslations($new_obj_id);
1694
1695 $other_children_of_same_type = $this->tree->getChildsByType($target_id, $this->type);
1696
1697 if ($obj_translations->getLanguages() === []) {
1698 $existing_titles = array_map(
1699 fn(array $child): string => $child['title'],
1700 $other_children_of_same_type
1701 );
1702
1703 return $this->appendNumberOfCopiesToTitle(
1704 $this->getTitle(),
1705 $existing_titles
1706 );
1707 }
1708
1709 return $this->appendCopyInfoToTranslations($obj_translations, $other_children_of_same_type);
1710 }
1711
1713 Translations $obj_translations,
1714 array $other_children_of_same_type
1715 ): string {
1716 $nodes_translations = array_map(
1717 fn(array $child): Translations =>
1718 $this->translations_repository->getFor($child['obj_id']),
1719 $other_children_of_same_type
1720 );
1721
1722 $title_translations_per_lang = array_reduce(
1723 $nodes_translations,
1724 $this->getCallbackForTitlesPerLanguageTransformation(),
1725 []
1726 );
1727
1728 $installed_langs = $this->lng->getInstalledLanguages();
1729 foreach ($obj_translations->getLanguages() as $language) {
1730 $obj_translations = $obj_translations->withLanguage(
1731 $language->withTitle(
1732 $this->appendNumberOfCopiesToTitle(
1733 $language->getTitle(),
1734 $title_translations_per_lang[$language->getLanguageCode()] ?? []
1735 )
1736 )
1737 );
1738 }
1739
1740 $this->translations_repository->store($obj_translations);
1741
1742 return $obj_translations->getDefaultTitle();
1743 }
1744
1746 {
1747 return function (array $npl, ?Translations $nt): array {
1748 $langs = $nt->getLanguages();
1749 foreach ($langs as $lang) {
1750 if (!array_key_exists($lang->getLanguageCode(), $npl)) {
1751 $npl[$lang->getLanguageCode()] = [];
1752 }
1753 $npl[$lang->getLanguageCode()][] = $lang->getTitle();
1754 }
1755 return $npl;
1756 };
1757 }
1758
1760 string $title,
1761 array $other_titles_for_lang
1762 ): string {
1763 $title_without_suffix = $this->buildTitleWithoutCopySuffix($title);
1764 if ($this->isTitleUnique($title_without_suffix, $other_titles_for_lang)) {
1765 return $title_without_suffix;
1766 }
1767
1768 for ($i = 1; true; $i++) {
1769 $title_with_suffix = "{$title_without_suffix} ({$i})";
1770 if ($this->isTitleUnique($title_with_suffix, $other_titles_for_lang)) {
1771 return $title_with_suffix;
1772 }
1773 }
1774 }
1775
1776 private function isTitleUnique(string $title, array $nodes): bool
1777 {
1778 foreach ($nodes as $node) {
1779 if (($title === $node)) {
1780 return false;
1781 }
1782 }
1783 return true;
1784 }
1785
1786 private function buildTitleWithoutCopySuffix(string $title): string
1787 {
1788 if (preg_match('/ \‍((\d+)\‍)$/', $title, $matches)) {
1789 return substr($title, 0, -strlen($matches[0]));
1790 }
1791
1792 return $title;
1793 }
1794
1802 public function cloneDependencies(int $target_id, int $copy_id): bool
1803 {
1804 ilConditionHandler::cloneDependencies($this->getRefId(), $target_id, $copy_id);
1805
1806 $tpl_id = ilDidacticTemplateObjSettings::lookupTemplateId($this->getRefId());
1807 if ($tpl_id) {
1808 $factory = new ilObjectFactory();
1809 $obj = $factory->getInstanceByRefId($target_id, false);
1810 if ($obj instanceof ilObject) {
1811 $obj->applyDidacticTemplate($tpl_id);
1812 }
1813 }
1814 return true;
1815 }
1816
1820 public function cloneMetaData(ilObject $target_obj): bool
1821 {
1822 $this->lom_services->derive()
1823 ->fromObject($this->getId(), 0, $this->getType())
1824 ->forObject($target_obj->getId(), 0, $target_obj->getType());
1825 return true;
1826 }
1827
1828 public static function getIconForReference(
1829 int $ref_id,
1830 int $obj_id,
1831 string $size,
1832 string $type = "",
1833 bool $offline = false
1834 ): string {
1836 global $DIC;
1837 $icon_factory = $DIC['ui.factory']->symbol()->icon();
1838 $irss = $DIC['resource_storage'];
1839
1840 if ($obj_id == "" && $type == "") {
1841 return "";
1842 }
1843
1844 if ($type === "") {
1845 $type = ilObject::_lookupType($obj_id);
1846 }
1847
1848 if ($size === "") {
1849 $size = "big";
1850 }
1851
1852 if ($obj_id) {
1854 $property_icon = LocalDIC::dic()['properties.additional.repository']->getFor($obj_id)->getPropertyIcon();
1855 $custom_icon = $property_icon->getCustomIcon();
1856 if ($custom_icon?->exists()) {
1857 return $custom_icon->getFullPath() . '?tmp=' . filemtime($custom_icon->getFullPath());
1858 }
1859
1860 $file_type_specific_icon = $property_icon->getObjectTypeSpecificIcon($obj_id, $icon_factory, $irss);
1861 if ($file_type_specific_icon !== null) {
1862 return $file_type_specific_icon->getIconPath();
1863 }
1864
1865 $dtpl_icon_factory = ilDidacticTemplateIconFactory::getInstance();
1866 if ($ref_id) {
1867 $path = $dtpl_icon_factory->getIconPathForReference($ref_id);
1868 } else {
1869 $path = $dtpl_icon_factory->getIconPathForObject($obj_id);
1870 }
1871 if ($path) {
1872 return $path . '?tmp=' . filemtime($path);
1873 }
1874 }
1875
1876 if (!$offline) {
1877 return self::getIconForType($type);
1878 }
1879 return "./images/standard/icon_{$type}.svg";
1880 }
1881
1882 public static function getIconForType(string $type): string
1883 {
1884 global $DIC;
1885 $objDefinition = $DIC['objDefinition'];
1886 if (!$objDefinition->isPluginTypeName($type)) {
1887 return ilUtil::getImagePath("standard/icon_{$type}.svg");
1888 }
1889
1890 if ($objDefinition->getClassName($type) !== '') {
1891 $class_name = "il{$objDefinition->getClassName($type)}Plugin";
1892 $location = $objDefinition->getLocation($type);
1893 if (is_file($location . "/class.{$class_name}.php")) {
1894 return call_user_func([$class_name, '_getIcon'], $type);
1895 }
1896 }
1897 return ilUtil::getImagePath('standard/icon_cmps.svg');
1898 }
1899
1908 final public static function _getIcon(
1909 int $obj_id = 0,
1910 string $size = "big",
1911 string $type = "",
1912 bool $offline = false
1913 ): string {
1914 return self::getIconForReference(0, $obj_id, $size, $type, $offline);
1915 }
1916
1917 protected function handleAutoRating(): void
1918 {
1919 if ($this->process_auto_reating
1920 && $this->hasAutoRating()
1921 && method_exists($this, "setRating")
1922 ) {
1923 $this->setRating(true);
1924 $this->update();
1925 }
1926 }
1927
1928 protected function hasAutoRating(): bool
1929 {
1930 $ref_id = $this->getRefId();
1931 $type = $this->type;
1932
1933 if (!$ref_id || !in_array($type, ["file", "lm", "wiki"])) {
1934 return false;
1935 }
1936
1937 return $this->selfOrParentWithRatingEnabled();
1938 }
1939
1940 public function selfOrParentWithRatingEnabled(): bool
1941 {
1942 $tree = $this->tree;
1943 $ref_id = $this->getRefId();
1944 $parent_ref_id = $tree->checkForParentType($ref_id, "grp");
1945 if (!$parent_ref_id) {
1946 $parent_ref_id = $tree->checkForParentType($ref_id, "crs");
1947 }
1948 if ($parent_ref_id) {
1949 // get auto rate setting
1950 $parent_obj_id = ilObject::_lookupObjId($parent_ref_id);
1952 $parent_obj_id,
1954 );
1955 }
1956 return false;
1957 }
1958
1962 public static function collectDeletionDependencies(
1963 array &$deps,
1964 int $ref_id,
1965 int $obj_id,
1966 string $type,
1967 int $depth = 0
1968 ): void {
1969 global $DIC;
1970
1971 $objDefinition = $DIC["objDefinition"];
1972 $tree = $DIC->repositoryTree();
1973
1974 if ($depth == 0) {
1975 $deps["dep"] = [];
1976 }
1977
1978 $deps["del_ids"][$obj_id] = $obj_id;
1979
1980 if (!$objDefinition->isPluginTypeName($type)) {
1981 $class_name = "ilObj" . $objDefinition->getClassName($type);
1982 $odeps = call_user_func([$class_name, "getDeletionDependencies"], $obj_id);
1983 if (is_array($odeps)) {
1984 foreach ($odeps as $id => $message) {
1985 $deps["dep"][$id][$obj_id][] = $message;
1986 }
1987 }
1988
1989 // get deletion dependency of children
1990 foreach ($tree->getChilds($ref_id) as $c) {
1991 ilObject::collectDeletionDependencies($deps, (int) $c["child"], (int) $c["obj_id"], (string) $c["type"], $depth + 1);
1992 }
1993 }
1994
1995 // delete all dependencies to objects that will be deleted, too
1996 if ($depth == 0) {
1997 foreach ($deps["del_ids"] as $obj_id) {
1998 unset($deps["dep"][$obj_id]);
1999 }
2000 $deps = $deps["dep"];
2001 }
2002 }
2003
2007 public static function getDeletionDependencies(int $obj_id): array
2008 {
2009 return [];
2010 }
2011
2012 public static function getLongDescriptions(array $obj_ids): array
2013 {
2014 global $DIC;
2015 $db = $DIC->database();
2016
2017 $sql =
2018 "SELECT obj_id, description" . PHP_EOL
2019 . "FROM object_description" . PHP_EOL
2020 . "WHERE " . $db->in("obj_id", $obj_ids, false, "integer") . PHP_EOL
2021 ;
2022 $result = $db->query($sql);
2023
2024 $all = [];
2025 while ($row = $db->fetchAssoc($result)) {
2026 $all[$row["obj_id"]] = $row["description"];
2027 }
2028 return $all;
2029 }
2030
2031 public static function getAllOwnedRepositoryObjects(int $user_id): array
2032 {
2033 global $DIC;
2034
2035 $db = $DIC->database();
2036 $obj_definition = $DIC["objDefinition"];
2037
2038 // restrict to repository
2039 $types = array_keys($obj_definition->getSubObjectsRecursively("root"));
2040
2041 $sql =
2042 "SELECT od.obj_id, od.type, od.title" . PHP_EOL
2043 . "FROM object_data od" . PHP_EOL
2044 . "JOIN object_reference oref ON(oref.obj_id = od.obj_id)" . PHP_EOL
2045 . "JOIN tree ON (tree.child = oref.ref_id)" . PHP_EOL
2046 ;
2047
2048 if ($user_id) {
2049 $sql .= "WHERE od.owner = " . $db->quote($user_id, "integer") . PHP_EOL;
2050 } else {
2051 $sql .=
2052 "LEFT JOIN usr_data ud ON (ud.usr_id = od.owner)" . PHP_EOL
2053 . "WHERE (od.owner < " . $db->quote(1, "integer") . PHP_EOL
2054 . "OR od.owner IS NULL OR ud.login IS NULL)" . PHP_EOL
2055 . "AND od.owner <> " . $db->quote(-1, "integer") . PHP_EOL
2056 ;
2057 }
2058
2059 $sql .=
2060 "AND " . $db->in("od.type", $types, false, "text") . PHP_EOL
2061 . "AND tree.tree > " . $db->quote(0, "integer") . PHP_EOL
2062 ;
2063
2064 $res = $db->query($sql);
2065
2066 $all = [];
2067 while ($row = $db->fetchAssoc($res)) {
2068 $all[$row["type"]][$row["obj_id"]] = $row["title"];
2069 }
2070
2071 return $all;
2072 }
2073
2077 public static function fixMissingTitles($type, array &$obj_title_map)
2078 {
2079 global $DIC;
2080 $db = $DIC->database();
2081
2082 if (!in_array($type, ["catr", "crsr", "sess", "grpr", "prgr"])) {
2083 return;
2084 }
2085
2086 // any missing titles?
2087 $missing_obj_ids = [];
2088 foreach ($obj_title_map as $obj_id => $title) {
2089 if (!trim($title)) {
2090 $missing_obj_ids[] = $obj_id;
2091 }
2092 }
2093
2094 if (!sizeof($missing_obj_ids)) {
2095 return;
2096 }
2097
2098 switch ($type) {
2099 case "grpr":
2100 case "catr":
2101 case "crsr":
2102 case "prgr":
2103 $sql =
2104 "SELECT oref.obj_id, od.type, od.title" . PHP_EOL
2105 . "FROM object_data od" . PHP_EOL
2106 . "JOIN container_reference oref ON (od.obj_id = oref.target_obj_id)" . PHP_EOL
2107 . "AND " . $db->in("oref.obj_id", $missing_obj_ids, false, "integer") . PHP_EOL
2108 ;
2109 $result = $db->query($sql);
2110
2111 while ($row = $db->fetchAssoc($result)) {
2112 $obj_title_map[$row["obj_id"]] = $row["title"];
2113 }
2114 break;
2115 case "sess":
2116 foreach ($missing_obj_ids as $obj_id) {
2117 $sess = new ilObjSession($obj_id, false);
2118 $obj_title_map[$obj_id] = $sess->getFirstAppointment()->appointmentToString();
2119 }
2120 break;
2121 }
2122 }
2123
2124 public static function _lookupCreationDate(int $obj_id): string
2125 {
2126 global $DIC;
2127 $db = $DIC->database();
2128
2129 $sql =
2130 "SELECT create_date" . PHP_EOL
2131 . "FROM " . self::TABLE_OBJECT_DATA . PHP_EOL
2132 . "WHERE obj_id = " . $db->quote($obj_id, "integer") . PHP_EOL
2133 ;
2134 $result = $db->query($sql);
2135 $rec = $db->fetchAssoc($result);
2136 return $rec["create_date"];
2137 }
2138
2147 public function getPossibleSubObjects(bool $filter = true): array
2148 {
2149 return $this->obj_definition->getSubObjects($this->type, $filter);
2150 }
2151
2152 public static function _getObjectTypeIdByTitle(string $type, ?\ilDBInterface $ilDB = null): ?int
2153 {
2154 if (!$ilDB) {
2155 global $DIC;
2156 $ilDB = $DIC->database();
2157 }
2158
2159 $sql =
2160 "SELECT obj_id FROM object_data" . PHP_EOL
2161 . "WHERE type = 'typ'" . PHP_EOL
2162 . "AND title = " . $ilDB->quote($type, 'text') . PHP_EOL
2163 ;
2164
2165 $res = $ilDB->query($sql);
2166 if ($ilDB->numRows($res) == 0) {
2167 return null;
2168 }
2169
2170 $row = $ilDB->fetchAssoc($res);
2171 return (int) $row['obj_id'] ?? null;
2172 }
2173}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$location
Definition: buildRTE.php:22
Builds data types.
Definition: Factory.php:36
Class handles translation mode for an object.
const IL_CAL_DATETIME
error(string $a_errmsg)
return true
static _deleteByObjId(int $a_obj_id)
Delete by objekt id.
static _cloneValues(int $copy_id, int $a_source_id, int $a_target_id, ?string $a_sub_type=null, ?int $a_source_sub_id=null, ?int $a_target_sub_id=null)
Clone Advanced Meta Data.
Global event handler.
static _deleteSettingsOfBlock(int $a_block_id, string $a_block_type)
INTERNAL CLASS: Please do not use in consumer code.
static cloneDependencies(int $a_src_ref_id, int $a_target_ref_id, int $a_copy_id)
static _lookupContainerSetting(int $a_id, string $a_keyword, ?string $a_default_value=null)
static _getInstance(int $a_copy_id)
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
static getActionsByTemplateId(int $a_tpl_id)
Get actions of one template.
static assignTemplate(int $a_ref_id, int $a_obj_id, int $a_tpl_id)
static getInstance()
Get the singleton instance of this ilECSImportManager.
Error Handling & global info handling.
static _deleteByObjId(int $a_obj_id)
language handling
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...
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
A news item can be created by different sources.
User class.
static deleteAllEntries(int $ref_id)
Delete all db entries for ref id.
parses the objects.xml it handles the xml-description of all ilias objects
isPlugin(string $obj_name)
get RBAC status by type returns true if object type is an (activated) plugin type
isRBACObject(string $obj_name)
get RBAC status by type returns true if object type is a RBAC object type
getSubObjectsRecursively(string $obj_type, bool $include_source_obj=true, bool $add_admin_objects=false)
Get all sub objects by type.
Class ilObjectFactory This class offers methods to get instances of the type-specific object classes ...
static lookupTxtById(string $plugin_id, string $lang_var)
Class ilObject Basic functions for all objects.
static _lookupObjectId(int $ref_id)
static _lookupType(int $id, bool $reference=false)
string $desc
setPermissions(int $parent_ref_id)
createReference()
creates reference for object
static _getIcon(int $obj_id=0, string $size="big", string $type="", bool $offline=false)
Get icon for repository item.
string $title
const TITLE_LENGTH
bool $add_dots
static _lookupOwnerName(int $owner_id)
Lookup owner name for owner id.
ilRbacReview $rbac_review
cloneMetaData(ilObject $target_obj)
Copy meta data.
static _writeDescription(int $obj_id, string $desc)
write description to db (static)
putInTree(int $parent_ref_id)
maybe this method should be in tree object!?
static _setDeletedDate(int $ref_id, int $deleted_by)
array $objectList
initDefaultRoles()
init default roles settings Purpose of this function is to create a local role folder and local roles...
static _hasUntrashedReference(int $obj_id)
checks whether an object has at least one reference that is not in trash
static _lookupOwner(int $obj_id)
Lookup owner user ID for object ID.
appendNumberOfCopiesToTitle(string $title, array $other_titles_for_lang)
string $create_date
static _getAllReferences(int $id)
get all reference ids for object ID
updateOwner()
update owner of object in db
const LONG_DESC_LENGTH
appendCopyInfoToTranslations(Translations $obj_translations, array $other_children_of_same_type)
supportsOfflineHandling()
cloneDependencies(int $target_id, int $copy_id)
Clone object dependencies.
ilLanguage $lng
doMDUpdateListener(string $a_element)
static _lookupDeletedDate(int $ref_id)
selfOrParentWithRatingEnabled()
static collectDeletionDependencies(array &$deps, int $ref_id, int $obj_id, string $type, int $depth=0)
Collect deletion dependencies.
ilAppEventHandler $app_event_handler
static _isInTrash(int $ref_id)
getPossibleSubObjects(bool $filter=true)
get all possible sub objects of this type the object can decide which types of sub objects are possib...
buildTitleWithoutCopySuffix(string $title)
static _lookupObjIdByImportId(string $import_id)
Get (latest) object id for an import id.
beforeDeleteMetaData()
static _writeTitle(int $obj_id, string $title)
write title to db (static)
setId(int $id)
ilTree $tree
static _getIdForImportId(string $import_id)
applyDidacticTemplate(int $tpl_id)
bool $call_by_reference
beforeUpdateMetaData()
static _lookupImportId(int $obj_id)
ilObjectDefinition $obj_definition
string $long_desc
static _getIdsForTitle(string $title, string $type='', bool $partial_match=false)
isTitleUnique(string $title, array $nodes)
getLastUpdateDate()
Get last update date in YYYY-MM-DD HH-MM-SS format.
bool $process_auto_reating
setType(string $type)
ilErrorHandling $error
static _prepareCloneSelection(array $ref_ids, string $new_type, bool $show_path=true)
Prepare copy wizard object selection.
appendCopyInfo(int $target_id, int $copy_id, int $new_obj_id)
Prepend Copy info if object with same name exists in that container.
static getDeletionDependencies(int $obj_id)
Get deletion dependencies.
static setDeletedDates(array $ref_ids, int $user_id)
LOMServices $lom_services
Aggregator $properties_aggregator
setTitle(string $title)
setImportId(string $import_id)
ilLogger $log
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
static _getLastUpdateOfObjects(array $obj_ids)
static _lookupLastUpdate(int $obj_id, bool $formatted=false)
getOwnerName()
get full name of object owner
withReferences()
determines whether objects are referenced or not (got ref ids or not)
Properties $object_properties
ilLogger $obj_log
setOwner(int $usr_id)
getLongDescription()
get object long description (stored in object_description)
string $untranslatedTitle
bool $register
ilRbacAdmin $rbac_admin
string $last_update
static _writeImportId(int $obj_id, string $import_id)
write import id to db (static)
static getAllOwnedRepositoryObjects(int $user_id)
const TABLE_OBJECT_DATA
setOfflineStatus(bool $status)
create()
note: title, description and type should be set when this function is called
ilObjUser $user
static _lookupCreationDate(int $obj_id)
static _getObjectTypeIdByTitle(string $type, ?\ilDBInterface $ilDB=null)
getUntranslatedTitle()
Get untranslated object title WebDAV needs to access the untranslated title of an object.
TranslationsRepository $translations_repository
string $type
static getIconForType(string $type)
getCallbackForTitlesPerLanguageTransformation()
static _getObjectsDataForType(string $type, bool $omit_trash=false)
get all objects of a certain type
beforeMDUpdateListener(string $a_element)
static _getObjectsByType(string $obj_type="", ?int $owner=null)
const DATABASE_DATE_FORMAT
const DESC_LENGTH
static _resetDeletedDate(int $ref_id)
static getLongDescriptions(array $obj_ids)
ILIAS $ilias
static _lookupObjId(int $ref_id)
string $import_id
flushObjectProperties()
MDUpdateListener(string $element)
Metadata update listener.
setParentRolePermissions(int $parent_ref_id)
Initialize the permissions of parent roles (local roles of categories, global roles....
setDescription(string $description)
static _lookupTitle(int $obj_id)
static _lookupDescription(int $obj_id)
beforeCreateMetaData()
ilDBInterface $db
getCreateDate()
Get create date in YYYY-MM-DD HH-MM-SS format.
static fixMissingTitles($type, array &$obj_title_map)
Try to fix missing object titles.
getPresentationTitle()
get presentation title Normally same as title Overwritten for sessions
setRefId(int $ref_id)
static lookupOfflineStatus(int $obj_id)
Lookup offline status using objectDataCache.
Class ilRbacAdmin Core functions for role based access control.
copyLocalRoles(int $a_source_id, int $a_target_id)
Copy local roles This method creates a copy of all local role.
revokePermission(int $a_ref_id, int $a_rol_id=0, bool $a_keep_protected=true)
Revokes permissions of an object of one role.
static delete(int $ref_id)
class ilRbacReview Contains Review functions of core Rbac.
static shortenTextExtended(string $a_str, int $a_len, bool $a_dots=false, bool $a_next_blank=false, bool $a_keep_extension=false)
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
getChilds(int $a_node_id, string $a_order="", string $a_direction="ASC")
get child nodes of given node
checkForParentType(int $a_ref_id, string $a_type, bool $a_exclude_source_check=false)
Check for parent type e.g check if a folder (ref_id 3) is in a parent course obj => checkForParentTyp...
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
const SYSTEM_ROLE_ID
Definition: constants.php:29
$c
Definition: deliver.php:25
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface ilDBInterface.
update(string $table_name, array $values, array $where)
@description $where MUST contain existing columns only.
insert(string $table_name, array $values)
fetchObject(ilDBStatement $query_result)
setLimit(int $limit, int $offset=0)
like(string $column, string $type, string $value="?", bool $case_insensitive=true)
Generate a like subquery.
numRows(ilDBStatement $statement)
quote($value, string $type)
manipulate(string $query)
Run a (write) Query on the database.
query(string $query)
Run a (read-only) Query on the database.
fetchAssoc(ilDBStatement $statement)
in(string $field, array $values, bool $negate=false, string $type="")
$ref_id
Definition: ltiauth.php:66
$path
Definition: ltiservices.php:30
$res
Definition: ltiservices.php:69
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
Class ilObjForumAdministration.
global $DIC
Definition: shib_login.php:26
$lang
Definition: xapiexit.php:25
$message
Definition: xapiexit.php:31