ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.ilConditionHandler.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
78{
79 public const string OPERATOR_PASSED = 'passed';
80 public const string OPERATOR_FINISHED = 'finished';
81 public const string OPERATOR_NOT_FINISHED = 'not_finished';
82 public const string OPERATOR_NOT_MEMBER = 'not_member';
83 public const string OPERATOR_FAILED = 'failed';
84 public const string OPERATOR_LP = 'learning_progress';
85 public const string OPERATOR_ACCREDITED_OR_PASSED = 'accredited_or_passed';
86
87 public const string OPERATOR_RESULT_RANGE_PERCENTAGE = 'result_range_percentage';
88
89 public const int UNIQUE_CONDITIONS = 1;
90
91 // conditions are used for all tree references of the target object.
92 // This is currently only used for lm chapters and likely to be abandonded in the future
93 public const int SHARED_CONDITIONS = 0;
94
95 public static array $cond_for_target_cache = array();
96 public static array $cond_target_rows = array();
97
98 protected ilDBInterface $db;
99 protected ilLanguage $lng;
101 protected ilTree $tree;
102 protected ilLogger $logger;
103
104 protected string $error_message = '';
105
106 protected int $target_obj_id = 0;
107 protected int $target_ref_id = 0;
108 protected string $target_type = '';
109 protected int $trigger_obj_id = 0;
110 protected int $trigger_ref_id = 0;
111 protected string $trigger_type = '';
113 protected string $operator = '';
114 protected string $value = '';
115 protected bool $validation = true;
116 private bool $circle = false;
117
118 private bool $obligatory = true;
119 private bool $hidden_status = false;
120
121 public function __construct()
122 {
123 global $DIC;
124
125 $this->db = $DIC->database();
126 $this->lng = $DIC->language();
127 $this->objDefinition = $DIC['objDefinition'];
128 $this->tree = $DIC->repositoryTree();
129 $this->logger = $DIC->logger()->ac();
130 $this->validation = true;
131 }
132
133 public static function resetCache(): void
134 {
135 self::$cond_for_target_cache = [];
136 self::$cond_target_rows = [];
137 }
138
142 public static function _isReferenceHandlingOptional(string $a_type): bool
143 {
144 return $a_type === 'st';
145 }
146
147
148 private static function getConditionController(int $a_target_ref_id): ?ilConditionControllerInterface
149 {
150 global $DIC;
151 $obj_definition = $DIC['objDefinition'];
152 $tree = $DIC->repositoryTree();
153
154 // check if parent takes over control of condition
155 $parent_ref_id = $tree->getParentId($a_target_ref_id);
156 $parent_obj_id = ilObject::_lookupObjId($parent_ref_id);
157 $parent_type = ilObject::_lookupType($parent_obj_id);
158
159 $class = $obj_definition->getClassName($parent_type);
160 $class_name = "il" . $class . "ConditionController";
161 $location = $obj_definition->getLocation($parent_type);
162 $path_to_controller = implode('/', [
163 ILIAS_ABSOLUTE_PATH,
164 $location,
165 "class." . $class_name . ".php"
166 ]);
167
168 // if yes, get from parent
169 if ($class !== "" && is_file($path_to_controller)) {
170 $controller = new $class_name();
171 if ($controller->isContainerConditionController($parent_ref_id)) {
172 return $controller;
173 }
174 }
175 return null;
176 }
177
181 public static function lookupEffectiveHiddenStatusByTarget(int $a_target_ref_id): bool
182 {
183 $controller = self::getConditionController($a_target_ref_id);
184 if ($controller !== null) {
185 return (bool) $controller->getConditionSetForRepositoryObject($a_target_ref_id)->getHiddenStatus();
186 }
187 return self::lookupPersistedHiddenStatusByTarget($a_target_ref_id);
188 }
189
190 public static function lookupPersistedHiddenStatusByTarget(int $a_target_ref_id): bool
191 {
192 global $DIC;
193
194 $ilDB = $DIC->database();
195
196 $query = 'SELECT hidden_status FROM conditions ' .
197 'WHERE target_ref_id = ' . $ilDB->quote($a_target_ref_id, 'integer');
198 $res = $ilDB->query($query);
199 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
200 return (bool) $row->hidden_status;
201 }
202 return false;
203 }
204
211 public static function _adjustMovedObjectConditions(int $a_ref_id): bool
212 {
213 return true;
214 }
215
219 protected static function _getDistinctTargetRefIds(): array
220 {
221 global $DIC;
222
223 $ilDB = $DIC['ilDB'];
224
225 $query = "SELECT DISTINCT target_ref_id ref FROM conditions ";
226 $res = $ilDB->query($query);
227 $ref_ids = [];
228 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
229 $ref_ids[] = (int) $row->ref;
230 }
231 return $ref_ids;
232 }
233
239 protected static function _deleteTargetConditionsByRefId(int $a_target_ref_id): bool
240 {
241 global $DIC;
242
243 $ilDB = $DIC['ilDB'];
244
245 $query = "DELETE FROM conditions " .
246 "WHERE target_ref_id = " . $ilDB->quote($a_target_ref_id, 'integer') . " " .
247 "AND target_type != 'st' ";
248 $res = $ilDB->manipulate($query);
249 return true;
250 }
251
252 public function setReferenceHandlingType(int $a_type): void
253 {
254 $this->condition_reference_type = $a_type;
255 }
256
257 public function getReferenceHandlingType(): int
258 {
260 }
261
262 public function setErrorMessage(string $a_msg): void
263 {
264 $this->error_message = $a_msg;
265 }
266
267 public function getErrorMessage(): string
268 {
270 }
271
272 public function setTargetRefId(int $a_target_ref_id): void
273 {
274 $this->target_ref_id = $a_target_ref_id;
275 }
276
277 public function getTargetRefId(): int
278 {
280 }
281
282 public function setTargetObjId(int $a_target_obj_id): void
283 {
284 $this->target_obj_id = $a_target_obj_id;
285 }
286
287 public function getTargetObjId(): int
288 {
290 }
291
295 public function setTargetType(string $a_target_type): void
296 {
297 $this->target_type = $a_target_type;
298 }
299
303 public function getTargetType(): string
304 {
305 return $this->target_type;
306 }
307
308 public function setTriggerRefId(int $a_trigger_ref_id): void
309 {
310 $this->trigger_ref_id = $a_trigger_ref_id;
311 }
312
313 public function getTriggerRefId(): int
314 {
316 }
317
318 public function setTriggerObjId(int $a_trigger_obj_id): void
319 {
320 $this->trigger_obj_id = $a_trigger_obj_id;
321 }
322
323 public function getTriggerObjId(): int
324 {
326 }
327
331 public function setTriggerType(string $a_trigger_type): void
332 {
333 $this->trigger_type = $a_trigger_type;
334 }
335
339 public function getTriggerType(): string
340 {
341 return $this->trigger_type;
342 }
343
344 public function setOperator(string $a_operator): void
345 {
346 $this->operator = $a_operator;
347 }
348
349 public function getOperator(): string
350 {
351 return $this->operator;
352 }
353
354 public function setValue(string $a_value): void
355 {
356 $this->value = $a_value;
357 }
358
359 public function getValue(): string
360 {
361 return $this->value;
362 }
363
367 public function setObligatory(bool $a_obl): void
368 {
369 $this->obligatory = $a_obl;
370 }
371
375 public function getObligatory(): bool
376 {
377 return $this->obligatory;
378 }
379
380 public function setHiddenStatus(bool $a_status): void
381 {
382 $this->hidden_status = $a_status;
383 }
384
385 public function getHiddenStatus(): bool
386 {
388 }
389
390 public function enableAutomaticValidation(bool $a_validate = true): void
391 {
392 $this->validation = $a_validate;
393 }
394
395 public function getTriggerTypes(): array
396 {
397 $trigger_types = array('crs', 'exc', 'tst', 'sahs', 'svy', 'lm', 'iass', 'prg', 'copa', 'lti', 'cmix');
398
399 // Add operator lp trigger
401 // only if object type has lp
402 foreach ($this->objDefinition->getAllRepositoryTypes() as $t) {
403 if (ilObjectLP::isSupportedObjectType($t) && !in_array($t, $trigger_types, true)) {
404 $trigger_types[] = $t;
405 }
406 }
407 }
408 foreach ($this->objDefinition->getPlugins() as $p_type => $p_info) {
409 try {
410 $name = 'ilObj' . $p_info['class_name'] . 'Access';
411 $reflection = new ReflectionClass($name);
412 if ($reflection->implementsInterface('ilConditionHandling')) {
413 $trigger_types[] = $p_type;
414 }
415 } catch (ReflectionException $e) {
416 $this->logger->warning('Cannot create instance for ' . $name);
417 $this->logger->warning($e->getMessage());
418 }
419 }
420 $active_triggers = array();
421 foreach ($trigger_types as $type) {
422 if (count($this->getOperatorsByTriggerType($type))) {
423 $active_triggers[] = $type;
424 }
425 }
426 return $active_triggers;
427 }
428
432 public function getOperatorsByTriggerType(string $a_type): array
433 {
434 global $DIC;
435
436 $objDefinition = $DIC['objDefinition'];
437
438 if ($a_type === 'crsg') {
439 return ['not_member'];
440 }
441
442 $class = $objDefinition->getClassName($a_type);
443 $full_class = "ilObj" . $class . "Access";
444 $reflection = new ReflectionClass($full_class);
445 if ($reflection->implementsInterface('ilConditionHandling')) {
446 $operators = call_user_func(
447 array($full_class, 'getConditionOperators'),
448 $a_type
449 );
450 } else {
451 $operators = [];
452 }
453
454 // Add operator lp
456 // only if object type has lp
457
459 array_unshift($operators, self::OPERATOR_LP);
460 }
461 }
462 return $operators;
463 }
464
468 public function storeCondition(): bool
469 {
470 // first insert, then validate: it's easier to check for circles if the new condition is in the db table
471 $next_id = $this->db->nextId('conditions');
472 $query = 'INSERT INTO conditions (condition_id,target_ref_id,target_obj_id,target_type,' .
473 'trigger_ref_id,trigger_obj_id,trigger_type,operator,value,ref_handling,obligatory,hidden_status) ' .
474 'VALUES (' .
475 $this->db->quote($next_id, 'integer') . ',' .
476 $this->db->quote($this->getTargetRefId(), 'integer') . "," .
477 $this->db->quote($this->getTargetObjId(), 'integer') . "," .
478 $this->db->quote($this->getTargetType(), 'text') . "," .
479 $this->db->quote($this->getTriggerRefId(), 'integer') . "," .
480 $this->db->quote($this->getTriggerObjId(), 'integer') . "," .
481 $this->db->quote($this->getTriggerType(), 'text') . "," .
482 $this->db->quote($this->getOperator(), 'text') . "," .
483 $this->db->quote($this->getValue(), 'text') . ", " .
484 $this->db->quote($this->getReferenceHandlingType(), 'integer') . ', ' .
485 $this->db->quote($this->getObligatory(), 'integer') . ', ' .
486 $this->db->quote($this->getHiddenStatus(), 'integer') . ' ' .
487 ')';
488
489 $res = $this->db->manipulate($query);
490
491 if ($this->validation && !$this->validate()) {
492 $this->deleteCondition($next_id);
493 return false;
494 }
495 return true;
496 }
497
498 public function checkExists(): bool
499 {
500 $query = "SELECT * FROM conditions " .
501 "WHERE target_ref_id = " . $this->db->quote($this->getTargetRefId(), 'integer') . " " .
502 "AND target_obj_id = " . $this->db->quote($this->getTargetObjId(), 'integer') . " " .
503 "AND trigger_ref_id = " . $this->db->quote($this->getTriggerRefId(), 'integer') . " " .
504 "AND trigger_obj_id = " . $this->db->quote($this->getTriggerObjId(), 'integer') . " " .
505 "AND operator = " . $this->db->quote($this->getOperator(), 'text');
506 $res = $this->db->query($query);
507 return (bool) $res->numRows();
508 }
509
510 public function updateCondition(int $a_id): void
511 {
512 $query = "UPDATE conditions SET " .
513 "target_ref_id = " . $this->db->quote($this->getTargetRefId(), 'integer') . ", " .
514 "operator = " . $this->db->quote($this->getOperator(), 'text') . ", " .
515 "value = " . $this->db->quote($this->getValue(), 'text') . ", " .
516 "ref_handling = " . $this->db->quote($this->getReferenceHandlingType(), 'integer') . ", " .
517 'obligatory = ' . $this->db->quote($this->getObligatory(), 'integer') . ' ' .
518 "WHERE condition_id = " . $this->db->quote($a_id, 'integer');
519 $res = $this->db->manipulate($query);
520 }
521
522 public function updateHiddenStatus(bool $a_status): void
523 {
524 $query = 'UPDATE conditions SET ' .
525 'hidden_status = ' . $this->db->quote($a_status, 'integer') . ' ' .
526 'WHERE target_ref_id = ' . $this->db->quote($this->getTargetRefId(), 'integer');
527 $this->db->manipulate($query);
528 }
529
533 public static function updateObligatory(int $a_id, bool $a_status): void
534 {
535 global $DIC;
536
537 $ilDB = $DIC->database();
538 $query = "UPDATE conditions SET " .
539 'obligatory = ' . $ilDB->quote($a_status, 'integer') . ' ' .
540 "WHERE condition_id = " . $ilDB->quote($a_id, 'integer');
541 $res = $ilDB->manipulate($query);
542 }
543
548 public function delete(int $a_ref_id): void
549 {
550 $query = "DELETE FROM conditions WHERE " .
551 "target_ref_id = " . $this->db->quote($a_ref_id, 'integer') . " " .
552 "OR trigger_ref_id = " . $this->db->quote($a_ref_id, 'integer');
553 $res = $this->db->manipulate($query);
554 }
555
560 public function deleteByObjId(int $a_obj_id): void
561 {
562 $query = "DELETE FROM conditions WHERE " .
563 "target_obj_id = " . $this->db->quote($a_obj_id, 'integer') . " " .
564 "OR trigger_obj_id = " . $this->db->quote($a_obj_id, 'integer');
565 $res = $this->db->manipulate($query);
566 }
567
568 public function deleteCondition(int $a_id): void
569 {
570 $query = "DELETE FROM conditions " .
571 "WHERE condition_id = " . $this->db->quote($a_id, 'integer');
572 $res = $this->db->manipulate($query);
573 }
574
578 public static function getNumberOfConditionsOfTrigger(string $a_trigger_obj_type, int $a_trigger_id): int
579 {
580 global $DIC;
581 $db = $DIC->database();
582
583 $query = 'select count(*) num from conditions ' .
584 'where trigger_obj_id = ' . $db->quote($a_trigger_id, ilDBConstants::T_INTEGER) . ' ' .
585 'and trigger_type = ' . $db->quote($a_trigger_obj_type, ilDBConstants::T_TEXT);
586 $res = $db->query($query);
587 $row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT);
588 return (int) $row->num;
589 }
590
596 public static function _getPersistedConditionsOfTrigger(string $a_trigger_obj_type, int $a_trigger_id): array
597 {
598 global $DIC;
599
600 $ilDB = $DIC['ilDB'];
601
602 $query = "SELECT * FROM conditions " .
603 "WHERE trigger_obj_id = " . $ilDB->quote($a_trigger_id, 'integer') . " " .
604 " AND trigger_type = " . $ilDB->quote($a_trigger_obj_type, 'text');
605
606 $res = $ilDB->query($query);
607 $conditions = [];
608 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
609 $tmp_array = [];
610 $tmp_array['id'] = (int) $row->condition_id;
611 $tmp_array['target_ref_id'] = (int) $row->target_ref_id;
612 $tmp_array['target_obj_id'] = (int) $row->target_obj_id;
613 $tmp_array['target_type'] = (string) $row->target_type;
614 $tmp_array['trigger_ref_id'] = (int) $row->trigger_ref_id;
615 $tmp_array['trigger_obj_id'] = (int) $row->trigger_obj_id;
616 $tmp_array['trigger_type'] = (string) $row->trigger_type;
617 $tmp_array['operator'] = (string) $row->operator;
618 $tmp_array['value'] = (string) $row->value;
619 $tmp_array['ref_handling'] = (int) $row->ref_handling;
620 $tmp_array['obligatory'] = (bool) $row->obligatory;
621 $tmp_array['hidden_status'] = (bool) $row->hidden_status;
622 $conditions[] = $tmp_array;
623 }
624 return $conditions;
625 }
626
632 public static function _getEffectiveConditionsOfTarget(
633 int $a_target_ref_id,
634 int $a_target_obj_id,
635 string $a_target_type = ""
636 ): array {
637 $controller = self::getConditionController($a_target_ref_id);
638 if ($controller !== null) {
640 $set = $controller->getConditionSetForRepositoryObject($a_target_ref_id);
641 // convert to old structure
642 $cond = [];
643 foreach ($set->getConditions() as $c) {
644 $obligatory = $set->getAllObligatory() || $c->getObligatory();
645 $trigger = $c->getTrigger();
646 $cond[] = [
647 "target_ref_id" => $a_target_ref_id,
648 "target_obj_id" => $a_target_obj_id,
649 "target_type" => $a_target_type,
650 "trigger_ref_id" => $trigger->getRefId(),
651 "trigger_obj_id" => $trigger->getObjId(),
652 "trigger_type" => $trigger->getType(),
653 "operator" => $c->getOperator(),
654 "value" => $c->getValue(),
655 "ref_handling" => 1,
656 "obligatory" => $obligatory,
657 "num_obligatory" => $set->getNumObligatory(),
658 "hidden_status" => $set->getHiddenStatus()
659 ];
660 }
661 return $cond;
662 }
663
664 return self::_getPersistedConditionsOfTarget($a_target_ref_id, $a_target_obj_id, $a_target_type);
665 }
666
671 public static function _getPersistedConditionsOfTarget(
672 int $a_target_ref_id,
673 int $a_target_obj_id,
674 string $a_target_type = ""
675 ): array {
676 global $DIC;
677
678 $ilDB = $DIC['ilDB'];
679
680 // get type if no type given
681 if ($a_target_type === "") {
682 $a_target_type = ilObject::_lookupType($a_target_obj_id);
683 }
684
685 // check conditions for target cache
686 if (isset(self::$cond_for_target_cache[$a_target_ref_id . ":" . $a_target_obj_id . ":" .
687 $a_target_type])) {
688 return self::$cond_for_target_cache[$a_target_ref_id . ":" . $a_target_obj_id . ":" .
689 $a_target_type];
690 }
691
692 // check rows cache
693 if (isset(self::$cond_target_rows[$a_target_type . ":" . $a_target_obj_id])) {
694 $rows = self::$cond_target_rows[$a_target_type . ":" . $a_target_obj_id];
695 } else {
696 // query data from db
697 $query = "SELECT * FROM conditions " .
698 "WHERE target_obj_id = " . $ilDB->quote($a_target_obj_id, 'integer') . " " .
699 " AND target_type = " . $ilDB->quote($a_target_type, 'text');
700
701 $res = $ilDB->query($query);
702 $rows = array();
703 while ($row = $ilDB->fetchAssoc($res)) {
704 $item = [];
705 $item['condition_id'] = (int) $row['condition_id'];
706 $item['target_ref_id'] = (int) $row['target_ref_id'];
707 $item['target_obj_id'] = (int) $row['target_obj_id'];
708 $item['trigger_ref_id'] = (int) $row['trigger_ref_id'];
709 $item['trigger_obj_id'] = (int) $row['trigger_obj_id'];
710 $item['target_type'] = (string) $row['target_type'];
711 $item['trigger_type'] = (string) $row['trigger_type'];
712 $item['operator'] = (string) $row['operator'];
713 $item['value'] = (string) $row['value'];
714 $item['ref_handling'] = (int) $row['ref_handling'];
715 $item['obligatory'] = (bool) $row['obligatory'];
716 $item['num_obligatory'] = (int) $row['num_obligatory'];
717 $item['hidden_status'] = (bool) $row['hidden_status'];
718
719 $rows[] = $item;
720 }
721 }
722
723 reset($rows);
724 $conditions = [];
725 foreach ($rows as $row) {
726 if (($row["ref_handling"] == self::UNIQUE_CONDITIONS) && $row["target_ref_id"] != $a_target_ref_id) {
727 continue;
728 }
729
730 $row["id"] = $row["condition_id"];
731 $conditions[] = $row;
732 }
733 // write conditions for target cache
734 self::$cond_for_target_cache[$a_target_ref_id . ":" . $a_target_obj_id . ":" .
735 $a_target_type] = $conditions;
736 return $conditions;
737 }
738
742 public static function preloadPersistedConditionsForTargetRecords(string $a_type, array $a_obj_ids): void
743 {
744 global $DIC;
745
746 $ilDB = $DIC['ilDB'];
747
748 if (is_array($a_obj_ids) && count($a_obj_ids) > 0) {
749 $res = $ilDB->query("SELECT * FROM conditions " .
750 "WHERE " . $ilDB->in("target_obj_id", $a_obj_ids, false, "integer") .
751 " AND target_type = " . $ilDB->quote($a_type, 'text'));
752 $rows = array();
753 while ($row = $ilDB->fetchAssoc($res)) {
754 $item = [];
755 $item['condition_id'] = (int) $row['condition_id'];
756 $item['target_ref_id'] = (int) $row['target_ref_id'];
757 $item['target_obj_id'] = (int) $row['target_obj_id'];
758 $item['trigger_ref_id'] = (int) $row['trigger_ref_id'];
759 $item['trigger_obj_id'] = (int) $row['trigger_obj_id'];
760 $item['target_type'] = (string) $row['target_type'];
761 $item['trigger_type'] = (string) $row['trigger_type'];
762 $item['operator'] = (string) $row['operator'];
763 $item['value'] = (string) $row['value'];
764 $item['ref_handling'] = (int) $row['ref_handling'];
765 $item['obligatory'] = (bool) $row['obligatory'];
766 $item['num_obligatory'] = (int) $row['num_obligatory'];
767 $item['hidden_status'] = (bool) $row['hidden_status'];
768 self::$cond_target_rows[$a_type . ":" . $row["target_obj_id"]][] = $item;
769 }
770 // init obj ids without any record
771 foreach ($a_obj_ids as $obj_id) {
772 if (!isset(self::$cond_target_rows[$a_type . ":" . $obj_id])) {
773 self::$cond_target_rows[$a_type . ":" . $obj_id] = array();
774 }
775 }
776 }
777 }
778
779 public static function _getCondition(int $a_id): array
780 {
781 global $DIC;
782
783 $ilDB = $DIC['ilDB'];
784
785 $query = "SELECT * FROM conditions " .
786 "WHERE condition_id = " . $ilDB->quote($a_id, 'integer');
787
788 $res = $ilDB->query($query);
789 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
790 $tmp_array['id'] = (int) $row->condition_id;
791 $tmp_array['target_ref_id'] = (int) $row->target_ref_id;
792 $tmp_array['target_obj_id'] = (int) $row->target_obj_id;
793 $tmp_array['target_type'] = (string) $row->target_type;
794 $tmp_array['trigger_ref_id'] = (int) $row->trigger_ref_id;
795 $tmp_array['trigger_obj_id'] = (int) $row->trigger_obj_id;
796 $tmp_array['trigger_type'] = (string) $row->trigger_type;
797 $tmp_array['operator'] = (string) $row->operator;
798 $tmp_array['value'] = (string) $row->value;
799 $tmp_array['ref_handling'] = (int) $row->ref_handling;
800 $tmp_array['obligatory'] = (bool) $row->obligatory;
801 $tmp_array['hidden_status'] = (bool) $row->hidden_status;
802 $tmp_array['num_obligatory'] = (int) $row->num_obligatory;
803 return $tmp_array;
804 }
805 return [];
806 }
807
813 public static function _checkCondition(array $condition, int $a_usr_id = 0): bool
814 {
815 global $DIC;
816
817 $ilUser = $DIC['ilUser'];
818 $objDefinition = $DIC['objDefinition'];
819 $a_usr_id = $a_usr_id ?: $ilUser->getId();
820
821 // check lp
822 if ($condition['operator'] === self::OPERATOR_LP) {
823 return ilLPStatus::_hasUserCompleted($condition['trigger_obj_id'], $a_usr_id);
824 }
825 switch ($condition['trigger_type']) {
826 case 'crsg':
828 (int) $condition['trigger_obj_id'],
829 (string) $condition['operator'],
830 (string) $condition['value'],
831 (int) $a_usr_id
832 );
833 }
834 $class = $objDefinition->getClassName($condition['trigger_type']);
835 $full_class = "ilObj" . $class . "Access";
836
837 if (!(is_a($full_class, "ilConditionHandling", true))) {
838 return false;
839 }
840
841 $fullfilled = call_user_func(
842 array($full_class, 'checkCondition'),
843 (int) $condition['trigger_obj_id'],
844 (string) $condition['operator'],
845 (string) $condition['value'],
846 (int) $a_usr_id
847 );
848 return $fullfilled;
849 }
850
852 int $a_target_ref_id,
853 int $a_target_obj_id,
854 string $a_obj_type = ''
855 ): array {
856 $conditions = self::_getEffectiveConditionsOfTarget($a_target_ref_id, $a_target_obj_id);
857
858 $opt = array();
859 foreach ($conditions as $con) {
860 if ($con['obligatory']) {
861 continue;
862 }
863 $opt[] = $con;
864 }
865 return $opt;
866 }
867
869 int $a_target_ref_id,
870 int $a_target_obj_id,
871 string $a_obj_type = ''
872 ): array {
873 $conditions = self::_getPersistedConditionsOfTarget($a_target_ref_id, $a_target_obj_id);
874
875 $opt = array();
876 foreach ($conditions as $con) {
877 if ($con['obligatory']) {
878 continue;
879 }
880 $opt[] = $con;
881 }
882 return $opt;
883 }
884
885 public static function lookupObligatoryConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id): int
886 {
887 global $DIC;
888
889 $ilDB = $DIC['ilDB'];
890
891 $query = 'SELECT max(num_obligatory) obl from conditions WHERE ' .
892 'target_ref_id = ' . $ilDB->quote($a_target_ref_id, 'integer') . ' ' .
893 'AND target_obj_id = ' . $ilDB->quote($a_target_obj_id, 'integer') . ' ' .
894 'GROUP BY (num_obligatory)';
895 $res = $ilDB->query($query);
896
897 $obl = 0;
898 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
899 $obl = (int) $row->obl;
900 }
901 return $obl;
902 }
903
905 int $a_target_ref_id,
906 int $a_target_obj_id,
907 string $a_target_obj_type = ''
908 ): int {
909 global $DIC;
910
911 $ilDB = $DIC['ilDB'];
912
913 // Get all conditions
914 $all = self::_getEffectiveConditionsOfTarget($a_target_ref_id, $a_target_obj_id, $a_target_obj_type);
915 $opt = self::getEffectiveOptionalConditionsOfTarget($a_target_ref_id, $a_target_obj_id, $a_target_obj_type);
916
917 $set_obl = 0;
918 if (isset($all[0])) {
919 $set_obl = $all[0]['num_obligatory'];
920 }
921
922 // existing value is valid
923 if ($set_obl > 0 &&
924 $set_obl < count($all) &&
925 $set_obl > (count($all) - count($opt) + 1)) {
926 return $set_obl;
927 }
928
929 if (count($opt)) {
930 $result = count($all) - count($opt) + 1;
931 } else {
932 $result = count($all);
933 }
934 return $result;
935 }
936
938 int $a_target_ref_id,
939 int $a_target_obj_id,
940 string $a_target_obj_type = '',
941 bool $a_force_update = false
942 ): int {
943 global $DIC;
944
945 $ilDB = $DIC['ilDB'];
946
947 // Get all conditions
948
949 self::resetCache();
950 $all = self::_getPersistedConditionsOfTarget($a_target_ref_id, $a_target_obj_id, $a_target_obj_type);
951 $opt = self::getPersistedOptionalConditionsOfTarget($a_target_ref_id, $a_target_obj_id, $a_target_obj_type);
952
953 $set_obl = 0;
954 if (isset($all[0])) {
955 $set_obl = $all[0]['num_obligatory'];
956 }
957
958 // existing value is valid
959 if ($set_obl > 0 &&
960 $set_obl < count($all) &&
961 $set_obl > (count($all) - count($opt) + 1)) {
962 return $set_obl;
963 }
964
965 if (count($opt)) {
966 $result = count($all) - count($opt) + 1;
967 } else {
968 $result = count($all);
969 }
970 if ($a_force_update) {
971 self::saveNumberOfRequiredTriggers($a_target_ref_id, $a_target_obj_id, $result);
972 }
973 return $result;
974 }
975
976 public static function saveNumberOfRequiredTriggers(int $a_target_ref_id, int $a_target_obj_id, int $a_num): void
977 {
978 global $DIC;
979
980 $ilDB = $DIC['ilDB'];
981
982 $query = 'UPDATE conditions ' .
983 'SET num_obligatory = ' . $ilDB->quote($a_num, 'integer') . ' ' .
984 'WHERE target_ref_id = ' . $ilDB->quote($a_target_ref_id, 'integer') . ' ' .
985 'AND target_obj_id = ' . $ilDB->quote($a_target_obj_id, 'integer');
986
987 $ilDB->manipulate($query);
988 }
989
994 public static function _checkAllConditionsOfTarget(
995 int $a_target_ref_id,
996 int $a_target_id,
997 string $a_target_type = "",
998 int $a_usr_id = 0
999 ): bool {
1000 global $DIC;
1001
1002 $ilUser = $DIC['ilUser'];
1003 $tree = $DIC['tree'];
1004 $logger = $DIC->logger()->ac();
1005
1006 $a_usr_id = $a_usr_id ?: $ilUser->getId();
1007 $conditions = self::_getEffectiveConditionsOfTarget(
1008 $a_target_ref_id,
1009 $a_target_id,
1010 $a_target_type
1011 );
1012 if (!count($conditions)) {
1013 return true;
1014 }
1015
1016 if (ilMemberViewSettings::getInstance()->isActive()) {
1017 return true;
1018 }
1019
1020 // First check obligatory conditions
1021 $optional = self::getEffectiveOptionalConditionsOfTarget($a_target_ref_id, $a_target_id, $a_target_type);
1022 $num_required = self::calculateEffectiveRequiredTriggers($a_target_ref_id, $a_target_id, $a_target_type);
1023 $passed = 0;
1024 foreach ($conditions as $condition) {
1025 if ($tree->isDeleted($condition['trigger_ref_id'])) {
1026 continue;
1027 }
1028 $check = self::_checkCondition($condition, $a_usr_id);
1029
1030 if ($check) {
1031 ++$passed;
1032 } else {
1033 // #0027223 if condition is obligatory => return false
1034 if ($condition['obligatory']) {
1035 return false;
1036 }
1037 }
1038 }
1039 return $passed >= $num_required;
1040 }
1041
1042 // PRIVATE
1043 protected function validate(): bool
1044 {
1045 // check if obj_id is already assigned
1046 $trigger_obj = ilObjectFactory::getInstanceByRefId($this->getTriggerRefId());
1047 $target_obj = ilObjectFactory::getInstanceByRefId($this->getTargetRefId());
1048
1049 if ($trigger_obj !== null && $target_obj !== null) {
1050 // check for circle
1051 $this->target_obj_id = $target_obj->getId();
1052
1053 if ($this->checkCircle($this->getTargetRefId(), $target_obj->getId())) {
1054 $this->setErrorMessage($this->lng->txt('condition_circle_created'));
1055
1056 unset($trigger_obj, $target_obj);
1057 return false;
1058 }
1059 return true;
1060 }
1061 return false;
1062 }
1063
1064 protected function checkCircle(int $a_ref_id, int $a_obj_id): bool
1065 {
1066 foreach (self::_getPersistedConditionsOfTarget($a_ref_id, $a_obj_id) as $condition) {
1067 if ($condition['trigger_obj_id'] == $this->target_obj_id) {
1068 $this->circle = true;
1069 break;
1070 }
1071
1072 $this->checkCircle($condition['trigger_ref_id'], $condition['trigger_obj_id']);
1073 }
1074 return $this->circle;
1075 }
1076
1077 public static function cloneDependencies(int $a_src_ref_id, int $a_target_ref_id, int $a_copy_id): void
1078 {
1079 $cwo = ilCopyWizardOptions::_getInstance($a_copy_id);
1080 $mappings = $cwo->getMappings();
1081
1082 $valid = 0;
1083 $conditions = self::_getPersistedConditionsOfTarget(
1084 $a_src_ref_id,
1085 ilObject::_lookupObjId($a_src_ref_id)
1086 );
1087 foreach ($conditions as $con) {
1088 if ($mappings[$con['trigger_ref_id']] ?? false) {
1089 $newCondition = new ilConditionHandler();
1090
1091 $target_obj = ilObject::_lookupObjId($a_target_ref_id);
1092 $target_typ = ilObject::_lookupType($target_obj);
1093
1094 $newCondition->setTargetRefId($a_target_ref_id);
1095 $newCondition->setTargetObjId($target_obj);
1096 $newCondition->setTargetType($target_typ);
1097
1098 $trigger_ref = $mappings[$con['trigger_ref_id']];
1099 $trigger_obj = ilObject::_lookupObjId($trigger_ref);
1100 $trigger_typ = ilObject::_lookupType($trigger_obj);
1101
1102 $newCondition->setTriggerRefId($trigger_ref);
1103 $newCondition->setTriggerObjId($trigger_obj);
1104 $newCondition->setTriggerType($trigger_typ);
1105 $newCondition->setOperator($con['operator']);
1106 $newCondition->setValue($con['value']);
1107 $newCondition->setReferenceHandlingType($con['ref_handling']);
1108 $newCondition->setObligatory($con['obligatory']);
1109
1110 // :TODO: not sure about this
1111 $newCondition->setHiddenStatus(self::lookupPersistedHiddenStatusByTarget($a_src_ref_id));
1112
1113 if ($newCondition->storeCondition()) {
1114 $valid++;
1115
1116 //Copy num_obligatory, to be checked below
1117 self::saveNumberOfRequiredTriggers(
1118 $a_target_ref_id,
1119 $target_obj,
1120 $con['num_obligatory']
1121 );
1122 }
1123 }
1124 }
1125 if ($valid) {
1126 $tgt_obj_id = ilObject::_lookupObjId($a_target_ref_id);
1127
1128 // num_obligatory
1129 self::calculatePersistedRequiredTriggers(
1130 $a_target_ref_id,
1131 $tgt_obj_id,
1132 ilObject::_lookupType($tgt_obj_id),
1133 true
1134 );
1135 }
1136 }
1137}
$check
Definition: buildRTE.php:81
$location
Definition: buildRTE.php:22
INTERNAL CLASS: Please do not use in consumer code.
getTargetType()
get target obj type
static getPersistedOptionalConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id, string $a_obj_type='')
static _getPersistedConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id, string $a_target_type="")
get all persisted conditions of target object
static preloadPersistedConditionsForTargetRecords(string $a_type, array $a_obj_ids)
setTargetType(string $a_target_type)
set target object type
static getConditionController(int $a_target_ref_id)
checkCircle(int $a_ref_id, int $a_obj_id)
deleteByObjId(int $a_obj_id)
delete all trigger and target entries This method is called from ilObject::delete() if an object is r...
getTriggerType()
get trigger obj type
static saveNumberOfRequiredTriggers(int $a_target_ref_id, int $a_target_obj_id, int $a_num)
getOperatorsByTriggerType(string $a_type)
setTriggerType(string $a_trigger_type)
set trigger object type
static lookupEffectiveHiddenStatusByTarget(int $a_target_ref_id)
Lookup hidden status (also take container control into account)
static calculateEffectiveRequiredTriggers(int $a_target_ref_id, int $a_target_obj_id, string $a_target_obj_type='')
getObligatory()
Get obligatory status.
updateHiddenStatus(bool $a_status)
storeCondition()
store new condition in database
static _isReferenceHandlingOptional(string $a_type)
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...
setOperator(string $a_operator)
static _getPersistedConditionsOfTrigger(string $a_trigger_obj_type, int $a_trigger_id)
Get all persisted conditions of trigger object Note: This only gets persisted conditions NOT (dynamic...
const string OPERATOR_RESULT_RANGE_PERCENTAGE
enableAutomaticValidation(bool $a_validate=true)
static cloneDependencies(int $a_src_ref_id, int $a_target_ref_id, int $a_copy_id)
static _adjustMovedObjectConditions(int $a_ref_id)
In the moment it is not allowed to create preconditions on objects that are located outside of a cour...
const string OPERATOR_ACCREDITED_OR_PASSED
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
static getEffectiveOptionalConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id, string $a_obj_type='')
setTriggerRefId(int $a_trigger_ref_id)
setTargetRefId(int $a_target_ref_id)
setObligatory(bool $a_obl)
Set obligatory status.
static lookupObligatoryConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id)
static _getCondition(int $a_id)
static updateObligatory(int $a_id, bool $a_status)
Toggle condition obligatory status.
static _deleteTargetConditionsByRefId(int $a_target_ref_id)
Delete conditions by target ref id Note: only conditions on the target type are deleted Conditions on...
static getNumberOfConditionsOfTrigger(string $a_trigger_obj_type, int $a_trigger_id)
get all conditions of trigger object
static calculatePersistedRequiredTriggers(int $a_target_ref_id, int $a_target_obj_id, string $a_target_obj_type='', bool $a_force_update=false)
static lookupPersistedHiddenStatusByTarget(int $a_target_ref_id)
setTriggerObjId(int $a_trigger_obj_id)
ilObjectDefinition $objDefinition
setTargetObjId(int $a_target_obj_id)
static _getInstance(int $a_copy_id)
static _hasUserCompleted(int $a_obj_id, int $a_user_id)
Lookup user object completion.
language handling
Component logger with individual log levels by component id.
static _checkCondition(int $trigger_obj_id, string $operator, $value, int $a_usr_id=0)
parses the objects.xml it handles the xml-description of all ilias objects
getClassName(string $obj_name)
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
static isSupportedObjectType(string $type)
static _lookupType(int $id, bool $reference=false)
static _lookupObjId(int $ref_id)
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
isDeleted(int $a_node_id)
This is a wrapper for isSaved() with a more useful name.
getParentId(int $a_node_id)
get parent id of given node
$c
Definition: deliver.php:25
$valid
Interface for containers that take over control of conditions for repository object targets.
Interface ilDBInterface.
quote($value, string $type)
query(string $query)
Run a (read-only) Query on the database.
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26