ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilConditionHandlerGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
24 use ILIAS\Conditions\Configuration\ConditionTriggerProvider as ConditionTriggerProvider;
31 
41 {
42  private const string LIST_MODE_UNDEFINED = 'undefined';
43  private const string LIST_MODE_ALL = 'all';
44  private const string LIST_MODE_SUBSET = 'subset';
45 
46  protected ilCtrl $ctrl;
47  protected ilLanguage $lng;
49  protected ilTree $tree;
55  private Factory $refinery;
58 
60  protected ?ilObject $target_obj = null;
61  protected int $target_id = 0;
62  protected string $target_type = '';
63  protected string $target_title = '';
64  protected int $target_ref_id = 0;
65 
66  protected bool $automatic_validation = true;
67 
68  public function __construct(?int $a_ref_id = null)
69  {
70  global $DIC;
71 
72  $this->ch_obj = new ilConditionHandler();
73  $this->ctrl = $DIC->ctrl();
74  $this->lng = $DIC->language();
75  $this->lng->loadLanguageModule('rbac');
76  $this->lng->loadLanguageModule('cond');
77  $this->tpl = $DIC->ui()->mainTemplate();
78  $this->tree = $DIC->repositoryTree();
79  $this->access = $DIC->access();
80  $this->toolbar = $DIC->toolbar();
81  $this->conditionUtil = $DIC->conditions()->util();
82  $this->objectDefinition = $DIC['objDefinition'];
83  $this->http = $DIC->http();
84  $this->refinery = $DIC->refinery();
85  $this->ui_factory = $DIC->ui()->factory();
86  $this->ui_renderer = $DIC->ui()->renderer();
87 
88  if ($a_ref_id) {
89  $target_obj = ilObjectFactory::getInstanceByRefId($a_ref_id);
90  if ($target_obj !== null) {
91  $this->setTargetId($target_obj->getId());
92  $this->setTargetRefId($target_obj->getRefId());
93  $this->setTargetType($target_obj->getType());
94  $this->setTargetTitle($target_obj->getTitle());
95  }
96  }
97  }
98 
99 
100  protected function initConditionIdFromQuery(): int
101  {
102  if ($this->http->wrapper()->query()->has('condition_id')) {
103  return $this->http->wrapper()->query()->retrieve(
104  'condition_id',
105  $this->refinery->kindlyTo()->int()
106  );
107  }
108  return 0;
109  }
110 
111  protected function initConditionsIdsFromPost(): SplFixedArray
112  {
113  if ($this->http->wrapper()->post()->has('conditions')) {
114  return SplFixedArray::fromArray(
115  $this->http->wrapper()->post()->retrieve(
116  'conditions',
117  $this->refinery->kindlyTo()->listOf(
118  $this->refinery->kindlyTo()->int()
119  )
120  )
121  );
122  }
123  return new SplFixedArray(0);
124  }
125 
126  protected function initItemIdsFromPost(): SplFixedArray
127  {
128  if ($this->http->wrapper()->post()->has('item_ids')) {
129  return SplFixedArray::fromArray(
130  $this->http->wrapper()->post()->retrieve(
131  'item_ids',
132  $this->refinery->kindlyTo()->listOf(
133  $this->refinery->kindlyTo()->int()
134  )
135  )
136  );
137  }
138  return new SplFixedArray(0);
139  }
140 
141  protected function initObligatoryItemsFromPost(): SplFixedArray
142  {
143  if ($this->http->wrapper()->post()->has('obl')) {
144  return SplFixedArray::fromArray(
145  $this->http->wrapper()->post()->retrieve(
146  'obl',
147  $this->refinery->kindlyTo()->listOf(
148  $this->refinery->kindlyTo()->int()
149  )
150  )
151  );
152  }
153  return new SplFixedArray(0);
154  }
155 
156  protected function initListModeFromPost(): string
157  {
158  return $this->http->wrapper()->post()->retrieve(
159  'list_mode',
160  $this->refinery->byTrying([
161  $this->refinery->kindlyTo()->string(),
162  $this->refinery->always(self::LIST_MODE_UNDEFINED)
163  ])
164  );
165  }
166 
167  protected function initSourceIdFromQuery(): int
168  {
169  if ($this->http->wrapper()->query()->has('source_id')) {
170  return $this->http->wrapper()->query()->retrieve(
171  'source_id',
172  $this->refinery->kindlyTo()->int()
173  );
174  }
175  return 0;
176  }
177 
178  public static function translateOperator(int $a_obj_id, string $a_operator, string $value = ''): string
179  {
180  global $DIC;
181 
182  $lng = $DIC->language();
183  switch ($a_operator) {
185  $lng->loadLanguageModule('trac');
186 
187  $obj_settings = new ilLPObjSettings($a_obj_id);
188  return $lng->txt('condition_' . $a_operator) . ': ' .
189  ilLPObjSettings::_mode2Text($obj_settings->getMode());
190 
192  $postfix = '';
193  $value_arr = unserialize($value);
194  if ($value_arr !== false) {
195  $postfix = ': ';
196  if (ilObject::_lookupType($a_obj_id) === 'crs') {
197  $postfix .= ilCourseObjective::lookupObjectiveTitle((int) $value_arr['objective']) . ' ';
198  }
199  $postfix .= $value_arr['min_percentage'] . ' - ' . $value_arr['max_percentage'] . '%';
200  }
201  return $lng->txt('condition_' . $a_operator) . $postfix;
202 
203  default:
204  $lng->loadLanguageModule('rbac');
205  return $lng->txt('condition_' . $a_operator);
206  }
207  }
208 
210  {
211  return $this->ch_obj;
212  }
213 
214  public function setBackButtons(array $a_btn_arr): void
215  {
216  ilSession::set('precon_btn', $a_btn_arr);
217  }
218 
219  public function getBackButtons(): array
220  {
221  if (ilSession::has('precon_btn')) {
222  return ilSession::get('precon_btn');
223  }
224  return [];
225  }
226 
227  public function executeCommand(): void
228  {
229  global $DIC;
230 
231  $ilErr = $DIC['ilErr'];
232 
233  if (!$this->access->checkAccess('write', '', $this->getTargetRefId())) {
234  $ilErr->raiseError($this->lng->txt('permission_denied'), $ilErr->WARNING);
235  }
236 
237  $next_class = $this->ctrl->getNextClass($this);
238  $cmd = $this->ctrl->getCmd();
239  switch ($next_class) {
240  default:
241  if (empty($cmd)) {
242  $cmd = "view";
243  }
244  $this->$cmd();
245  break;
246  }
247  }
248 
249  public function setAutomaticValidation(bool $a_status): void
250  {
251  $this->automatic_validation = $a_status;
252  }
253 
254  public function getAutomaticValidation(): bool
255  {
257  }
258 
259  public function setTargetId(int $a_target_id): void
260  {
261  $this->target_id = $a_target_id;
262  }
263 
264  public function getTargetId(): int
265  {
266  return $this->target_id;
267  }
268 
269  public function setTargetRefId(int $a_target_ref_id): void
270  {
271  $this->target_ref_id = $a_target_ref_id;
272  }
273 
274  public function getTargetRefId(): int
275  {
276  return $this->target_ref_id;
277  }
278 
279  public function setTargetType(string $a_target_type): void
280  {
281  $this->target_type = $a_target_type;
282  }
283 
284  public function getTargetType(): string
285  {
286  return $this->target_type;
287  }
288 
289  public function setTargetTitle(string $a_target_title): void
290  {
291  $this->target_title = $a_target_title;
292  }
293 
297  public function isTargetReferenced(): bool
298  {
299  return (bool) $this->getTargetRefId();
300  }
301 
302  public function getTargetTitle(): string
303  {
304  return $this->target_title;
305  }
306 
307 
308 
309 
310  protected function showObligatoryForm(
311  string $list_mode = self::LIST_MODE_ALL
312  ): ?ilPropertyFormGUI {
313  if (!$this->objectDefinition->isRBACObject($this->getTargetType())) {
314  return null;
315  }
316 
318  $form = new ilPropertyFormGUI();
319  $form->setFormAction($this->ctrl->getFormAction($this, 'listConditions'));
320  $form->setTitle($this->lng->txt('precondition_obligatory_settings'));
321  $form->addCommandButton('saveObligatorySettings', $this->lng->txt('save'));
322 
323  $hide = new ilCheckboxInputGUI($this->lng->txt('rbac_precondition_hide'), 'hidden');
325  $hide->setValue("1");
326  $hide->setInfo($this->lng->txt('rbac_precondition_hide_info'));
327  $form->addItem($hide);
328 
329  $mode = new ilRadioGroupInputGUI($this->lng->txt("rbac_precondition_mode"), "list_mode");
330  $form->addItem($mode);
331  $mode->setValue($list_mode);
332 
333  $mall = new ilRadioOption($this->lng->txt("rbac_precondition_mode_all"), "all");
334  $mall->setInfo($this->lng->txt("rbac_precondition_mode_all_info"));
335  $mode->addOption($mall);
336 
337  if (count($all) > 1) {
338  $min = 1;
339  $max = count($all) - 1;
340 
341  $msubset = new ilRadioOption($this->lng->txt("rbac_precondition_mode_subset"), "subset");
342  $msubset->setInfo($this->lng->txt("rbac_precondition_mode_subset_info"));
343  $mode->addOption($msubset);
344 
345  $obl = new ilNumberInputGUI($this->lng->txt('precondition_num_obligatory'), 'required');
346  $obl->setInfo($this->lng->txt('precondition_num_optional_info'));
347 
349  $this->getTargetRefId(),
350  $this->getTargetId()
351  );
352  $obl->setValue($num_required > 0 ? (string) $num_required : null);
353  $obl->setRequired(true);
354  $obl->setSize(1);
355  $obl->setMinValue($min);
356  $obl->setMaxValue($max);
357  $msubset->addSubItem($obl);
358  }
359 
360  $old_mode = new ilHiddenInputGUI("old_list_mode");
361  $old_mode->setValue($list_mode);
362  $form->addItem($old_mode);
363 
364  return $form;
365  }
366 
367  public function edit(?ilPropertyFormGUI $form = null): void
368  {
369  $condition_id = $this->initConditionIdFromQuery();
370  if (!$condition_id) {
371  $this->tpl->setOnScreenMessage('failure', "Missing id: condition_id");
372  $this->listConditions();
373  return;
374  }
375  $this->ctrl->setParameter($this, 'condition_id', $condition_id);
376  $condition = ilConditionHandler::_getCondition($condition_id);
377 
378  if (!$form instanceof ilPropertyFormGUI) {
379  $form = $this->initFormCondition($condition['trigger_ref_id'], $condition_id, 'edit');
380  }
381  $this->tpl->setContent($form->getHTML());
382  }
383 
384  public function updateCondition(): void
385  {
386  $condition_id = $this->initConditionIdFromQuery();
387  if (!$condition_id) {
388  $this->tpl->setOnScreenMessage('failure', "Missing id: condition_id");
389  $this->listConditions();
390  return;
391  }
392  // Update condition
393  $condition_handler = new ilConditionHandler();
394  $condition = ilConditionHandler::_getCondition($condition_id);
395 
396  $form = $this->initFormCondition(
397  $condition['trigger_ref_id'],
398  $condition_id,
399  'edit'
400  );
401 
402  if (!$form->checkInput()) {
403  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
404  $this->edit($form);
405  return;
406  }
407 
408  $condition_handler->setOperator((string) $form->getInput('operator'));
409  $condition_handler->setObligatory((bool) $form->getInput('obligatory'));
410  $condition_handler->setTargetRefId($this->getTargetRefId());
411  $condition_handler->setValue('');
412  switch ($this->getTargetType()) {
413  case 'st':
414  $condition_handler->setReferenceHandlingType((int) $form->getInput('ref_handling'));
415  break;
416 
417  default:
418  $condition_handler->setReferenceHandlingType(ilConditionHandler::UNIQUE_CONDITIONS);
419  break;
420  }
421  $condition_handler->updateCondition($condition['id']);
422 
423  // Update relevant sco's
424  if ($condition['trigger_type'] === 'sahs') {
425  $olp = ilObjectLP::getInstance($condition['trigger_obj_id']);
426  $collection = $olp->getCollectionInstance();
427  if ($collection) {
428  $collection->delete();
429  }
430  $item_ids = $this->initItemIdsFromPost();
431  if (count($item_ids)) { // #12901
432  $collection->activateEntries($item_ids->toArray());
433  }
434  ilLPStatusWrapper::_refreshStatus($condition['trigger_obj_id']);
435  }
436  $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
437  $this->ctrl->redirect($this, 'listConditions');
438  }
439 
440  protected function adjustConditionsAfterDeletion(): void
441  {
443  $this->getTargetRefId(),
444  $this->getTargetId()
445  );
447  $this->getTargetRefId(),
448  $this->getTargetId()
449  );
450  if (
451  count($conditions) === 1 &&
452  count($optional_conditions) > 0
453  ) {
454  // set to obligatory
455  foreach ($conditions as $condition) {
456  ilConditionHandler::updateObligatory($condition['id'], true);
457  }
458  }
460  $this->getTargetRefId(),
461  $this->getTargetId()
462  );
463  if (
464  $num_obligatory == count($conditions)
465  ) {
466  // set all obligatory
467  foreach ($conditions as $condition) {
468  ilConditionHandler::updateObligatory($condition['id'], true);
469  }
470  } elseif (
471  $num_obligatory > count($conditions)
472  ) {
473  // reduce required triggers to maximum
475  $this->getTargetRefId(),
476  $this->getTargetId(),
477  count($conditions) - 1
478  );
479  }
480  }
481 
482  public function selector(): void
483  {
484  $this->tpl->setOnScreenMessage('info', $this->lng->txt("condition_select_object"));
485 
486  $exp = new ilConditionSelector($this, "selector");
487  $exp->setTypeWhiteList(array_merge(
488  $this->getConditionHandler()->getTriggerTypes(),
489  array("root", "cat", "grp", "fold", "crs", "prg")
490  ));
491  //setRefId have to be after setTypeWhiteList!
492  $exp->setRefId($this->getTargetRefId());
493  $exp->setClickableTypes($this->getConditionHandler()->getTriggerTypes());
494 
495  if (!$exp->handleCommand()) {
496  $this->tpl->setContent($exp->getHTML());
497  }
498  }
499 
500  public function add(?ilPropertyFormGUI $form = null): void
501  {
502  $source_id = $this->initSourceIdFromQuery();
503  if (!$source_id) {
504  $this->tpl->setOnScreenMessage('failure', "Missing id: condition_id");
505  $this->selector();
506  return;
507  }
508  if (!$form instanceof ilPropertyFormGUI) {
509  $form = $this->initFormCondition($source_id, 0, 'add');
510  }
511  $this->tpl->setContent($form->getHTML());
512  }
513 
517  public function assign(): void
518  {
519  $source_id = $this->initSourceIdFromQuery();
520  if (!$source_id) {
521  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_condition_selected'));
522  $this->selector();
523  return;
524  }
525 
526  $form = $this->initFormCondition($source_id, 0, 'add');
527  if (!$form->checkInput()) {
528  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
529  $this->add($form);
530  return;
531  }
532  $this->ch_obj->setTargetRefId($this->getTargetRefId());
533  $this->ch_obj->setTargetObjId($this->getTargetId());
534  $this->ch_obj->setTargetType($this->getTargetType());
535 
536  switch ($this->getTargetType()) {
537  case 'st':
538  $this->ch_obj->setReferenceHandlingType((int) $form->getInput('ref_handling'));
539  break;
540 
541  default:
542  $this->ch_obj->setReferenceHandlingType(ilConditionHandler::UNIQUE_CONDITIONS);
543  break;
544  }
545  // this has to be changed, if non referenced trigger are implemted
546  $trigger_obj = ilObjectFactory::getInstanceByRefId($source_id);
547  if ($trigger_obj !== null) {
548  $this->ch_obj->setTriggerRefId($trigger_obj->getRefId());
549  $this->ch_obj->setTriggerObjId($trigger_obj->getId());
550  $this->ch_obj->setTriggerType($trigger_obj->getType());
551  }
552  $this->ch_obj->setOperator($form->getInput('operator'));
553  $this->ch_obj->setObligatory((bool) $form->getInput('obligatory'));
554  $this->ch_obj->setHiddenStatus(ilConditionHandler::lookupPersistedHiddenStatusByTarget($this->getTargetRefId()));
555  $this->ch_obj->setValue('');
556 
557  // Save assigned sco's
558  if ($this->ch_obj->getTriggerType() === 'sahs') {
559  $olp = ilObjectLP::getInstance($this->ch_obj->getTriggerObjId());
560  $collection = $olp->getCollectionInstance();
561  if ($collection) {
562  $collection->delete();
563  }
564 
565  $items_ids = $this->initItemIdsFromPost();
566  if (count($items_ids)) { // #12901
567  $collection->activateEntries($items_ids->toArray());
568  }
569  }
570  $this->ch_obj->enableAutomaticValidation($this->getAutomaticValidation());
571  if (!$this->ch_obj->storeCondition()) {
572  $this->tpl->setOnScreenMessage('failure', $this->ch_obj->getErrorMessage(), true);
573  } else {
574  $this->tpl->setOnScreenMessage('success', $this->lng->txt('added_new_condition'), true);
575  }
576  $this->ctrl->redirect($this, 'listConditions');
577  }
578 
579  public function getConditionsOfTarget(): array
580  {
581  $cond = [];
583  $this->getTargetRefId(),
584  $this->getTargetId(),
585  $this->getTargetType()
586  ) as $condition) {
587  if ($condition['operator'] === 'not_member') {
588  continue;
589  }
590 
591  $cond[] = $condition;
592  }
593  return $cond;
594  }
595 
596  private function initFormCondition(
597  int $a_source_id,
598  int $a_condition_id = 0,
599  string $a_mode = 'add'
600  ): ilPropertyFormGUI {
601  $trigger_obj_id = ilObject::_lookupObjId($a_source_id);
602  $trigger_type = ilObject::_lookupType($trigger_obj_id);
603 
604  $condition = ilConditionHandler::_getCondition($a_condition_id);
605  $form = new ilPropertyFormGUI();
606  $this->ctrl->setParameter($this, 'source_id', $a_source_id);
607  $form->setFormAction($this->ctrl->getFormAction($this));
608 
609  $info_source = new ilNonEditableValueGUI($this->lng->txt("rbac_precondition_source"));
610  $info_source->setValue(ilObject::_lookupTitle(ilObject::_lookupObjId($a_source_id)));
611  $form->addItem($info_source);
612 
613  $info_target = new ilNonEditableValueGUI($this->lng->txt("rbac_precondition_target"));
614  $info_target->setValue($this->getTargetTitle());
615  $form->addItem($info_target);
616 
617  $obl = new ilHiddenInputGUI('obligatory');
618  if ($a_condition_id) {
619  $obl->setValue((string) (bool) $condition['obligatory']);
620  } else {
621  $obl->setValue("1");
622  }
623  $form->addItem($obl);
624 
625  $sel = new ilSelectInputGUI($this->lng->txt('condition'), 'operator');
626  $ch_obj = new ilConditionHandler();
627  $operators = [];
628  if ($a_mode === 'add') {
629  $operators[''] = $this->lng->txt('select_one');
630  }
631  foreach ($ch_obj->getOperatorsByTriggerType($trigger_type) as $operator) {
632  $operators[$operator] = $this->lng->txt('condition_' . $operator);
633  }
634  $sel->setValue($condition['operator'] ?? '');
635  $sel->setOptions($operators);
636  $sel->setRequired(true);
637  $form->addItem($sel);
638 
640  $rad_opt = new ilRadioGroupInputGUI($this->lng->txt('cond_ref_handling'), 'ref_handling');
641  $rad_opt->setValue((string) ($condition['ref_handling'] ?? ilConditionHandler::SHARED_CONDITIONS));
642 
643  $opt2 = new ilRadioOption(
644  $this->lng->txt('cond_ref_shared'),
645  (string) ilConditionHandler::SHARED_CONDITIONS
646  );
647  $rad_opt->addOption($opt2);
648 
649  $opt1 = new ilRadioOption(
650  $this->lng->txt('cond_ref_unique'),
652  );
653  $rad_opt->addOption($opt1);
654 
655  $form->addItem($rad_opt);
656  }
657 
658  // Additional settings for SCO's
659  if ($trigger_type === 'sahs') {
660  $this->lng->loadLanguageModule('trac');
661 
662  $cus = new ilCheckboxGroupInputGUI($this->lng->txt('trac_sahs_relevant_items'), 'item_ids');
663  $cus->setInfo($this->lng->txt('trac_lp_determination_info_sco'));
664  $cus->setRequired(true);
665 
666  $olp = ilObjectLP::getInstance($trigger_obj_id);
667  $collection = $olp->getCollectionInstance();
668  $checked = [];
669  if ($collection) {
670  foreach ($collection->getPossibleItems() as $item_id => $sahs_item) {
671  $sco = new ilCheckboxOption($sahs_item['title'], (string) $item_id);
672  if ($collection->isAssignedEntry($item_id)) {
673  $checked[] = $item_id;
674  }
675  $cus->addOption($sco);
676  }
677  }
678  $cus->setValue($checked);
679  $form->addItem($cus);
680  }
681  switch ($a_mode) {
682  case 'edit':
683  $form->setTitleIcon(ilUtil::getImagePath('standard/icon_' . $this->getTargetType() . '.svg'));
684  $form->setTitle($this->lng->txt('rbac_edit_condition'));
685  $form->addCommandButton('updateCondition', $this->lng->txt('save'));
686  $form->addCommandButton('listConditions', $this->lng->txt('cancel'));
687  break;
688 
689  case 'add':
690  $form->setTitleIcon(ilUtil::getImagePath('standard/icon_' . $this->getTargetType() . '.svg'));
691  $form->setTitle($this->lng->txt('add_condition'));
692  $form->addCommandButton('assign', $this->lng->txt('save'));
693  $form->addCommandButton('selector', $this->lng->txt('back'));
694  break;
695  }
696  return $form;
697  }
698 
699  protected function listConditions(bool $load_form_with_request = false): void
700  {
702  $this->getTargetRefId(),
703  $this->getTargetId(),
704  $this->getTargetType()
705  );
706  $allow_optional_preconditions = (bool) count($optional_conditions);
707  $table = new ConditionTriggerTableGUI(
708  new ConditionTriggerProvider(
709  $this->getTargetRefId(),
710  $this->getTargetId(),
711  $this->getTargetType()
712  ),
713  $allow_optional_preconditions
714  );
715 
716  // add condition button
717  $add_condition_trigger_button = $this->ui_factory->button()->standard(
718  $this->lng->txt('add_condition'),
719  $this->ctrl->getLinkTarget($this, 'selector')
720  );
721  $add_condition_trigger_button = $this->ui_renderer->render($add_condition_trigger_button);
722 
723  $form = $this->initCompulsoryForm($load_form_with_request);
724  $form_content = '';
725  if ($form instanceof StandardForm) {
726  $form_content = $this->ui_renderer->render([$form]);
727  }
728  $this->tpl->setContent(
729  $add_condition_trigger_button .
730  $form_content .
731  $table->render()
732  );
733  }
734 
735  protected function handleConditionTriggerTableActions(): void
736  {
737  $action = $this->http->wrapper()->query()->retrieve(
738  ConditionTriggerTableGUI::ACTION_TOKEN_NS,
739  $this->refinery->byTrying(
740  [
741  $this->refinery->kindlyTo()->string(),
742  $this->refinery->always('')
743  ]
744  )
745  );
746  match ($action) {
747  'editConditionTrigger' => $this->editConditionTrigger(),
748  'saveCompulsory' => $this->saveCompulsoryStatus(),
749  'confirmDeleteConditionTrigger' => $this->confirmDeleteConditionTrigger(),
750  default => $this->ctrl->redirect($this, 'listConditions')
751  };
752  }
753 
754  protected function saveCompulsoryStatus(): void
755  {
757  $this->getTargetRefId(),
758  $this->getTargetId(),
759  $this->getTargetType()
760  );
761 
762  $compulsory_ids = $this->http->wrapper()->query()->retrieve(
763  ConditionTriggerTableGUI::ID_TOKEN_NS,
764  $this->refinery->byTrying(
765  [
766  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int()),
767  $this->refinery->always([])
768  ]
769  )
770  );
771 
772  if (count($compulsory_ids) > (count($all_conditions) - 2)) {
773  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("rbac_precondition_minimum_optional"), true);
774  $this->ctrl->redirect($this, 'listConditions');
775  }
776 
777  foreach ($all_conditions as $item) {
778  $status = false;
779  if (in_array($item['condition_id'], $compulsory_ids)) {
780  $status = true;
781  }
782  ilConditionHandler::updateObligatory($item['condition_id'], $status);
783  }
784 
785  // re-calculate
787  $this->getTargetRefId(),
788  $this->getTargetId(),
789  $this->getTargetType(),
790  true
791  );
792 
793  $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
794  $this->ctrl->redirect($this, 'listConditions');
795  }
796 
797  protected function confirmDeleteConditionTrigger(): void
798  {
799  $condition_trigger_ids = $this->http->wrapper()->query()->retrieve(
800  ConditionTriggerTableGUI::ID_TOKEN_NS,
801  $this->refinery->byTrying(
802  [
803  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int()),
804  // Actions for entire table sends a fixed token in an array, instead of all row ids
805  $this->refinery->custom()->transformation(function ($var) {
806  if (
807  is_array($var) &&
808  count($var) === 1 &&
809  (string) $var[0] === 'ALL_OBJECTS'
810  ) {
811  return $var;
812  }
813  throw new UnexpectedValueException('Unexpected string in row_id array.');
814  }),
815  $this->refinery->always([])
816  ]
817  )
818  );
819 
820  if ($condition_trigger_ids === ['ALL_OBJECTS']) {
821  $condition_trigger_ids = [];
823  $this->getTargetRefId(),
824  $this->getTargetId(),
825  $this->getTargetType()
826  ) as $condition) {
827  $condition_trigger_ids[] = $condition['id'];
828  }
829  }
830 
831  $items = [];
832  foreach ($condition_trigger_ids as $condition_trigger_id) {
833  $condition = ilConditionHandler::_getCondition($condition_trigger_id);
834  $items[] = $this->ui_factory->modal()->interruptiveItem()->standard(
835  (string) $condition_trigger_id,
836  ilObject::_lookupTitle($condition['trigger_obj_id']) .
837  ' (' . $this->lng->txt('condition') . ':' .
838  $this->lng->txt('condition_' . $condition['operator']) . ')'
839  );
840  }
841 
842  $output = $this->ui_renderer->renderAsync(
843  [
844  $this->ui_factory->modal()->interruptive(
845  $this->lng->txt('confirm'),
846  $this->lng->txt('rbac_condition_delete_sure'),
847  $this->ctrl->getFormAction($this, 'deleteConditionTrigger')
848  )->withAffectedItems($items)
849  ]
850  );
851 
852  $this->http->saveResponse($this->http->response()->withBody(
853  Streams::ofString($output)
854  ));
855  $this->http->sendResponse();
856  $this->http->close();
857  }
858 
859  protected function deleteConditionTrigger(): void
860  {
861  $condition_trigger_ids = $this->http->wrapper()->post()->retrieve(
862  'interruptive_items',
863  $this->refinery->byTrying(
864  [
865  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int()),
866  $this->refinery->always([])
867  ]
868  )
869  );
870  if (!count($condition_trigger_ids)) {
871  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_condition_selected'));
872  $this->listConditions();
873  return;
874  }
875 
876  foreach ($condition_trigger_ids as $condition_id) {
877  $this->ch_obj->deleteCondition($condition_id);
878  }
880  $this->tpl->setOnScreenMessage('success', $this->lng->txt('condition_deleted'), true);
881  $this->ctrl->redirect($this, 'listConditions');
882  }
883 
884  protected function initCompulsoryForm(bool $with_request = false): ?StandardForm
885  {
886  if (!$this->objectDefinition->isRBACObject($this->getTargetType())) {
887  return null;
888  }
889 
892  $this->getTargetRefId(),
893  $this->getTargetId(),
894  $this->getTargetType()
895  );
896 
897  $old_status = $this->ui_factory->input()->field()->hidden()->withValue(
898  (string) (count($optional_conditions) ? self::LIST_MODE_SUBSET : self::LIST_MODE_ALL)
899  );
900 
901  $hidden = $this->ui_factory->input()->field()->checkbox(
902  $this->lng->txt('rbac_precondition_hide'),
903  $this->lng->txt('rbac_precondition_hide_info')
905 
906  $condition_mode_all = $this->ui_factory->input()->field()->group(
907  [],
908  $this->lng->txt('rbac_precondition_mode_all'),
909  $this->lng->txt('rbac_precondition_mode_all_info')
910  );
911  $list_mode_items[self::LIST_MODE_ALL] = $condition_mode_all;
912 
913  $subset_limit = [];
914  if (count($all_conditions) > 1) {
915 
917  $this->getTargetRefId(),
918  $this->getTargetId()
919  );
920  $subset_limit['num_compulsory'] =
921  $this->ui_factory->input()
922  ->field()
923  ->numeric(
924  $this->lng->txt('precondition_num_obligatory'),
925  $this->lng->txt('precondition_num_optional_info')
926  )
927  ->withValue($num_required > 0 ? $num_required : null)
928  ->withAdditionalTransformation(
929  $this->refinery->logical()->parallel(
930  [
931  $this->refinery->int()->isGreaterThan(0),
932  $this->refinery->int()->isLessThan(count($all_conditions))
933  ]
934  )
935  );
936  }
937  if (count($all_conditions) > 1) {
938  $condition_mode_subset = $this->ui_factory->input()->field()->group(
939  $subset_limit,
940  $this->lng->txt('rbac_precondition_mode_subset'),
941  $this->lng->txt('rbac_precondition_mode_subset_info')
942  );
943  $list_mode_items[self::LIST_MODE_SUBSET] = $condition_mode_subset;
944  }
945 
946  $list_mode = $this->ui_factory->input()->field()->switchableGroup(
947  $list_mode_items,
948  $this->lng->txt('rbac_precondition_mode')
949  )->withValue(
951  $this->getTargetRefId(),
952  $this->getTargetId(),
953  $this->getTargetType()
954  )) ? self::LIST_MODE_SUBSET : self::LIST_MODE_ALL
955  );
956 
957  $main_section = $this->ui_factory->input()->field()->section(
958  [
959  'old_status' => $old_status,
960  'hidden_status' => $hidden,
961  'list_mode' => $list_mode
962  ],
963  $this->lng->txt('precondition_obligatory_settings')
964  );
965  $form = $this->ui_factory->input()->container()->form()->standard(
966  $this->ctrl->getFormAction($this, 'saveCompulsoryForm'),
967  [
968  'compulsory_configuration' => $main_section
969  ]
970  );
971  if ($with_request) {
972  $form = $form->withRequest($this->http->request());
973  }
974  return $form;
975  }
976 
977  protected function saveCompulsoryForm(): void
978  {
979  $form = $this->initCompulsoryForm(true);
980  $data = $form->getData();
981  if (!$data) {
982  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
983  $this->listConditions(true);
984  return;
985  }
986  $cond = new ilConditionHandler();
987  $cond->setTargetRefId($this->getTargetRefId());
988  $cond->updateHiddenStatus($data['compulsory_configuration']['hidden_status']);
989 
990  $old_status = $data['compulsory_configuration']['old_status'];
991  switch ($data['compulsory_configuration']['list_mode'][0]) {
992  case self::LIST_MODE_ALL:
993  if ($old_status != self::LIST_MODE_ALL) {
995  $this->getTargetRefId(),
996  $this->getTargetId(),
997  $this->getTargetType()
998  );
999  // Set all optional conditions to obligatory
1000  foreach ($optional_conditions as $item) {
1001  ilConditionHandler::updateObligatory($item["condition_id"], true);
1002  }
1003  }
1004  break;
1005  case self::LIST_MODE_SUBSET:
1006  $num_required = $data['compulsory_configuration']['list_mode'][1]['num_compulsory'];
1007  if ($old_status != self::LIST_MODE_SUBSET) {
1009  $this->getTargetRefId(),
1010  $this->getTargetId(),
1011  $this->getTargetType()
1012  );
1013  foreach ($all_conditions as $item) {
1014  ilConditionHandler::updateObligatory($item["condition_id"], false);
1015  }
1016  }
1018  $this->getTargetRefId(),
1019  $this->getTargetId(),
1020  (int) $num_required
1021  );
1022  break;
1023  }
1024  $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
1025  $this->ctrl->redirect($this, 'listConditions');
1026  }
1027 
1028  protected function addConditionTrigger(bool $with_request = false): void
1029  {
1030  $source_id = $this->initSourceIdFromQuery();
1031  if (!$source_id) {
1032  $this->tpl->setOnScreenMessage('failure', "Missing id: condition_id");
1033  $this->selector();
1034  return;
1035  }
1036  $this->ctrl->setParameter($this, 'source_id', $source_id);
1037  $form = $this->initConditionTriggerForm($with_request, $source_id, 0);
1038  $this->tpl->setContent($this->ui_renderer->render([$form]));
1039  }
1040 
1041  protected function editConditionTrigger(bool $with_request = false): void
1042  {
1043  if ($this->http->wrapper()->query()->has(ConditionTriggerTableGUI::ID_TOKEN_NS)) {
1044  $condition_id = $this->http->wrapper()->query()->retrieve(
1045  ConditionTriggerTableGUI::ID_TOKEN_NS,
1046  $this->refinery->byTrying(
1047  [
1048  $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int()),
1049  $this->refinery->always([])
1050  ]
1051  )
1052  );
1053  $condition_id = end($condition_id);
1054  } else {
1055  $condition_id = $this->initConditionIdFromQuery();
1056  }
1057  if (!$condition_id) {
1058  $this->tpl->setOnScreenMessage('failure', "Missing id: condition_id");
1059  $this->listConditions();
1060  return;
1061  }
1062  $condition = ilConditionHandler::_getCondition($condition_id);
1063  $this->ctrl->setParameter($this, 'condition_id', $condition_id);
1064  $form = $this->initConditionTriggerForm(
1065  $with_request,
1066  $condition['trigger_ref_id'],
1067  $condition_id,
1068  'edit'
1069  );
1070  $this->tpl->setContent($this->ui_renderer->render([$form]));
1071  }
1072 
1073  private function initConditionTriggerForm(bool $with_request, int $trigger_id, int $condition_id, string $mode = 'add'): StandardForm
1074  {
1075  $trigger_type = ilObject::_lookupType($trigger_id, true);
1076  $trigger_obj_id = ilObject::_lookupObjId($trigger_id);
1077  $condition_handler = new ilConditionHandler();
1078  $condition = ilConditionHandler::_getCondition($condition_id);
1079 
1080  if ($mode == 'edit') {
1081  $main_section_items['obligatory'] = $this->ui_factory->input()->field()->hidden()
1082  ->withValue($condition['obligatory']);
1083  }
1084 
1085  $group_items = [];
1086  foreach ($condition_handler->getOperatorsByTriggerType($trigger_type) as $operator) {
1087  switch ($operator) {
1089  $group_items[$operator] = $this->ui_factory->input()->field()->group(
1090  [
1091  'result_range_percentage' => $this->initRangeConditionInputItem(
1092  $trigger_id,
1093  $trigger_obj_id,
1094  $condition
1095  )
1096  ],
1097  $this->lng->txt('condition_' . $operator)
1098  );
1099  break;
1100 
1102  $this->lng->loadLanguageModule('trac');
1103 
1104  $obj_settings = new ilLPObjSettings($trigger_obj_id);
1105  $label = $this->lng->txt('condition_' . $operator) . ': ' .
1106  ilLPObjSettings::_mode2Text($obj_settings->getMode());
1107  $group_items[$operator] = $this->ui_factory->input()->field()->group([], $label);
1108  break;
1109 
1110  default:
1111  $group_items[$operator] = $this->ui_factory->input()->field()->group(
1112  [],
1113  $this->lng->txt('condition_' . $operator)
1114  );
1115 
1116  }
1117  }
1118  $main_section_items['operator'] = $this->ui_factory->input()->field()->switchableGroup(
1119  $group_items,
1120  $this->lng->txt('condition')
1121  )->withRequired(true);
1122  if ($mode == 'edit') {
1123  $main_section_items['operator'] = $main_section_items['operator']->withValue((string) ($condition['operator']));
1124  }
1125 
1126  // main section
1127  $main_section = $this->ui_factory->input()->field()->section(
1128  $main_section_items,
1129  $this->lng->txt('add_condition') . ' (' . ilObject::_lookupTitle($trigger_obj_id) . ')'
1130  );
1131  // form
1132  $form = $this->ui_factory->input()->container()->form()->standard(
1133  $this->ctrl->getLinkTarget($this, $mode === 'add' ? 'saveConditionTrigger' : 'updateConditionTrigger'),
1134  [
1135  'condition_configuration' => $main_section
1136  ]
1137  );
1138  if ($with_request) {
1139  $form = $form->withRequest($this->http->request());
1140  }
1141  return $form;
1142  }
1143 
1144  protected function initRangeConditionInputItem(int $trigger_ref_id, int $trigger_obj_id, array $condition): Section
1145  {
1146  list($stored_objective_id, $stored_min, $stored_max) = $this->extractValueOptionsFromCondition($condition);
1147  if (ilObject::_lookupType($trigger_obj_id) === 'crs') {
1148  $course = ilObjectFactory::getInstanceByRefId($trigger_ref_id);
1149  if (($course instanceof ilObjCourse) && $course->getViewMode() == ilCourseConstants::IL_CRS_VIEW_OBJECTIVE) {
1150  $select_options = [];
1151  foreach (ilCourseObjective::_getObjectiveIds($trigger_obj_id) as $objective_id) {
1152  $objective = new ilCourseObjective($course, $objective_id);
1153  $select_options[$objective_id] = $objective->getTitle();
1154  }
1155  $this->lng->loadLanguageModule('crs');
1156  $sections['objective'] = $this->ui_factory->input()->field()->select(
1157  $this->lng->txt('crs_objectives'),
1158  $select_options,
1159  )->withRequired(true);
1160  if ($stored_objective_id > 0) {
1161  $sections['objective'] = $sections['objective']->withValue($stored_objective_id);
1162  }
1163  }
1164  }
1165  $sections['min'] = $this->ui_factory->input()->field()->numeric(
1166  $this->lng->txt('precondition_operator_range_min'),
1168  $this->refinery->logical()->parallel(
1169  [
1170  $this->refinery->int()->isGreaterThanOrEqual(0),
1171  $this->refinery->int()->isLessThanOrEqual(100)
1172  ]
1173  )
1174  )->withRequired(true)
1175  ->withValue($stored_min);
1176  $sections['max'] = $this->ui_factory->input()->field()->numeric(
1177  $this->lng->txt('precondition_operator_range_max'),
1179  $this->refinery->logical()->parallel(
1180  [
1181  $this->refinery->int()->isGreaterThan(0),
1182  $this->refinery->int()->isLessThanOrEqual(100)
1183  ]
1184  )
1185  )->withRequired(true)
1186  ->withValue($stored_max);
1187  return $this->ui_factory->input()->field()->section(
1188  $sections,
1189  ''
1190  )->withAdditionalTransformation(
1191  $this->refinery->custom()->constraint(
1192  function ($min_max) {
1193  return $min_max['min'] < $min_max['max'];
1194  },
1195  $this->lng->txt('precondition_operator_range_err_min_max')
1196  )
1197  );
1198  }
1199 
1200  protected function extractValueOptionsFromInput(array $data): string
1201  {
1202  if ($data['condition_configuration']['operator'][0] !== ilConditionHandler::OPERATOR_RESULT_RANGE_PERCENTAGE) {
1203  return '';
1204  }
1205  return serialize(
1206  [
1207  'objective' => $data['condition_configuration']['operator'][1]['result_range_percentage']['objective'] ?? null,
1208  'min_percentage' => $data['condition_configuration']['operator'][1]['result_range_percentage']['min'],
1209  'max_percentage' => $data['condition_configuration']['operator'][1]['result_range_percentage']['max']
1210 
1211  ]
1212  );
1213  }
1214 
1215  protected function extractValueOptionsFromCondition(array $condition): array
1216  {
1217  if (($condition['value'] ?? '') === '') {
1218  return [0,0,0];
1219  }
1220  $value_arr = unserialize($condition['value']);
1221  if ($value_arr === false) {
1222  return [0,0,0];
1223  }
1224  return [
1225  $value_arr['objective'] ?? 0,
1226  $value_arr['min_percentage'] ?? 0,
1227  $value_arr['max_percentage'] ?? 0
1228  ];
1229  }
1230 
1231  protected function updateConditionTrigger(): void
1232  {
1233  $condition_id = $this->initConditionIdFromQuery();
1234  if (!$condition_id) {
1235  $this->tpl->setOnScreenMessage('failure', "Missing id: condition_id");
1236  $this->listConditions();
1237  return;
1238  }
1239  $condition = ilConditionHandler::_getCondition($condition_id);
1240  $form = $this->initConditionTriggerForm(true, $condition['trigger_ref_id'], $condition_id, 'edit');
1241  $data = $form->getData();
1242  if (!$data) {
1243  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
1244  $this->editConditionTrigger(true);
1245  return;
1246  }
1247 
1248  // Update condition
1249  $condition_handler = new ilConditionHandler();
1250  $condition_handler->setOperator($data['condition_configuration']['operator'][0]);
1251  $condition_handler->setObligatory((bool) $data['condition_configuration']['obligatory']);
1252  $condition_handler->setTargetRefId($this->getTargetRefId());
1253  $condition_handler->setValue($this->extractValueOptionsFromInput($data));
1254  $condition_handler->updateCondition($condition_id);
1255  $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true);
1256  $this->ctrl->redirect($this, 'listConditions');
1257 
1288  }
1289 
1290  protected function saveConditionTrigger(): void
1291  {
1292  $source_id = $this->initSourceIdFromQuery();
1293  if (!$source_id) {
1294  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_condition_selected'), true);
1295  $this->ctrl->redirect($this, 'listConditions');
1296  return;
1297  }
1298 
1299  $form = $this->initConditionTriggerForm(true, $source_id, 0);
1300  $data = $form->getData();
1301  if (!$data) {
1302  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input'));
1303  $this->addConditionTrigger(true);
1304  return;
1305  }
1306 
1307  $condition = new ilConditionHandler();
1308  $condition->setTargetRefId($this->getTargetRefId());
1309  $condition->setTargetObjId($this->getTargetId());
1310  $condition->setTargetType($this->getTargetType());
1311  $trigger = ilObjectFactory::getInstanceByRefId($source_id, false);
1312  if ($trigger instanceof ilObject) {
1313  $condition->setTriggerRefId($trigger->getRefId());
1314  $condition->setTriggerObjId($trigger->getId());
1315  $condition->setTriggerType($trigger->getType());
1316  }
1317  $condition->setOperator($data['condition_configuration']['operator'][0]);
1318  $condition->setObligatory((bool) ($data['condition_configuration']['obligatory'] ?? true));
1319  $condition->setHiddenStatus(ilConditionHandler::lookupPersistedHiddenStatusByTarget($this->getTargetRefId()));
1320  $condition->setValue($this->extractValueOptionsFromInput($data));
1321  $condition->enableAutomaticValidation($this->getAutomaticValidation());
1322  if (!$condition->storeCondition()) {
1323  $this->tpl->setOnScreenMessage('failure', $condition->getErrorMessage(), true);
1324  } else {
1325  $this->tpl->setOnScreenMessage('success', $this->lng->txt('added_new_condition'), true);
1326  }
1327  $this->ctrl->redirect($this, 'listConditions');
1328 
1361  }
1362 
1363 
1364 }
static get(string $a_var)
This class represents an option in a radio group.
ilGlobalTemplateInterface $tpl
static _getCondition(int $a_id)
This class represents an option in a checkbox group.
This class represents a selection list property in a property form.
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...
editConditionTrigger(bool $with_request=false)
static _isReferenceHandlingOptional(string $a_type)
setInfo(string $a_info)
static translateOperator(int $a_obj_id, string $a_operator, string $value='')
static lookupObligatoryConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id)
setTargetRefId(int $a_target_ref_id)
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)
showObligatoryForm(string $list_mode=self::LIST_MODE_ALL)
loadLanguageModule(string $a_module)
Load language module.
assign()
assign new trigger condition to target
static _getObjectiveIds(int $course_id, bool $a_activated_only=false)
const string OPERATOR_RESULT_RANGE_PERCENTAGE
static lookupPersistedHiddenStatusByTarget(int $a_target_ref_id)
setTargetTitle(string $a_target_title)
$ilErr
Definition: raiseError.php:33
static _lookupObjId(int $ref_id)
static saveNumberOfRequiredTriggers(int $a_target_ref_id, int $a_target_obj_id, int $a_num)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
This class represents a hidden form property in a property form.
static http()
Fetches the global http state from ILIAS.
This class represents a property in a property form.
initCompulsoryForm(bool $with_request=false)
addConditionTrigger(bool $with_request=false)
add(?ilPropertyFormGUI $form=null)
static _lookupTitle(int $obj_id)
class ilcourseobjective
This class represents a number property in a property form.
Condition utility object Wraps some ilConditionHandler methods (which will become deprecated) Depende...
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
global $DIC
Definition: shib_login.php:26
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
static has($a_var)
This class represents a property in a property form.
static lookupObjectiveTitle(int $a_objective_id, bool $a_add_description=false)
withValue($value)
Get an input like this with another value displayed on the client side.
Definition: Group.php:61
initRangeConditionInputItem(int $trigger_ref_id, int $trigger_obj_id, array $condition)
static getPersistedOptionalConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id, string $a_obj_type='')
setTargetType(string $a_target_type)
edit(?ilPropertyFormGUI $form=null)
initFormCondition(int $a_source_id, int $a_condition_id=0, string $a_mode='add')
isTargetReferenced()
Check if target has refernce id.
static _lookupType(int $id, bool $reference=false)
static getInstance(int $obj_id)
initConditionTriggerForm(bool $with_request, int $trigger_id, int $condition_id, string $mode='add')
extractValueOptionsFromCondition(array $condition)
static set(string $a_var, $a_val)
Set a value.
static _getPersistedConditionsOfTarget(int $a_target_ref_id, int $a_target_obj_id, string $a_target_type="")
get all persisted conditions of target object
listConditions(bool $load_form_with_request=false)
static _mode2Text(int $a_mode)