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