ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ObjectiveRenderer.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 namespace ILIAS\Containter\Content;
22 
25 
31 {
32  public const MATERIALS_TESTS = 1;
33  public const MATERIALS_OTHER = 2;
34 
35  public const CHECKBOX_NONE = 0;
36  public const CHECKBOX_ADMIN = 1;
37  public const CHECKBOX_DOWNLOAD = 2;
38  protected array $rendered_items;
39  protected \ilCourseObjectiveListGUI $objective_list_gui;
40  protected \ilLanguage $lng;
41  protected \ILIAS\Container\StandardGUIRequest $request;
42  protected \ILIAS\Style\Content\Object\ObjectFacade $content_style_domain;
43  protected \ilLOTestAssignments $test_assignments;
44  protected \ilContainerRenderer $renderer;
45  protected \ilLOSettings $loc_settings;
46 
47  protected \ilContainerGUI $container_gui;
48  protected \ilContainer $container;
49  protected string $view_mode;
52  protected array $list_gui = [];
53  protected string $output_html = "";
54 
55  public function __construct(
56  InternalDomainService $domain,
57  InternalGUIService $gui,
58  string $view_mode,
59  \ilContainerGUI $container_gui,
60  \ilContainerRenderer $container_renderer
61  ) {
62  global $DIC;
63 
64  $this->domain = $domain; // setting and access (visible, read, write access)
65  $this->gui = $gui; // getting ilCtrl
67  $container = $container_gui->getObject();
68  $this->view_mode = $view_mode; // tile/list (of container)
69  $this->container_gui = $container_gui; // tile/list (of container)
71  $container = $container_gui->getObject();
72  $this->container = $container; // id, refid, other stuff
73  $this->loc_settings = \ilLOSettings::getInstanceByObjId($this->container->getId());
74  $this->test_assignments = \ilLOTestAssignments::getInstance($this->container->getId());
75  $this->renderer = $container_renderer;
76  $this->content_style_domain = $DIC
77  ->contentStyle()
78  ->domain()
79  ->styleForObjId(0);
80  $this->request = $gui
81  ->standardRequest();
82  $this->lng = $domain->lng();
83  }
84 
85 
86  public function renderObjectives(): string
87  {
88  $mode = $this->domain->content()->mode($this->container);
89  $user = $this->domain->user();
90  $access = $this->domain->access();
91  $lng = $this->domain->lng();
92 
93  $is_manage = $mode->isAdminMode();
94  $is_order = $mode->isOrderingMode();
95 
96  if (!$is_manage) {
97 
98  // render objectives
99  $this->showObjectives($is_order);
100 
101  // check for results
102  $has_results = \ilLOUserResults::hasResults($this->container->getId(), $user->getId());
103 
104  $tst_obj_id = \ilObject::_lookupObjId($this->loc_settings->getInitialTest());
105 
106  // render initial/qualified test
107  if (
108  $this->loc_settings->getInitialTest() &&
109  $this->loc_settings->isGeneralInitialTestVisible() &&
110  !$this->loc_settings->isInitialTestStart() &&
112  $tst_obj_id,
114  '',
115  $user->getId()
116  )
117  ) {
118  $this->output_html .= $this->renderTest($this->loc_settings->getInitialTest(), null, true);
119  } elseif (
120  $this->loc_settings->getQualifiedTest() &&
121  $this->loc_settings->isGeneralQualifiedTestVisible()
122  ) {
123  $this->output_html .= $this->renderTest($this->loc_settings->getQualifiedTest(), null, false);
124  }
125 
126  // render other materials
127  //$this->showMaterials(self::MATERIALS_OTHER, false, !$is_order);
128  } else {
129 
130  // render all materials
131  // not needed anymore
132  //$this->showMaterials(null, true);
133  }
134 
135  // reset results by setting or for admins
136  if (
137  \ilLOSettings::getInstanceByObjId($this->container->getId())->isResetResultsEnabled() or
138  $access->checkAccess('write', '', $this->container->getRefId())
139  ) {
140  if ($has_results) {
141  if (!$is_manage && !$is_order) {
142  $this->showButton('askReset', $lng->txt('crs_reset_results'));
143  }
144  }
145  }
146  return $this->output_html;
147  }
148 
149  public function getContent(): string
150  {
151  return $this->output_html;
152  }
153 
154  public function showObjectives(bool $a_is_order = false): void
155  {
156  $lng = $this->domain->lng();
157  $ilSetting = $this->domain->settings();
158  // All objectives
159  if (!count($objective_ids = \ilCourseObjective::_getObjectiveIds($this->container->getId(), true))) {
160  return;
161  }
162  $this->objective_list_gui = new \ilCourseObjectiveListGUI();
163  $this->objective_list_gui->setContainerObject($this->container_gui);
164  if ($ilSetting->get("icon_position_in_lists") === "item_rows") {
165  $this->objective_list_gui->enableIcon(true);
166  }
167 
168  $acc = null;
169  if (!$a_is_order) {
170  $acc = new \ilAccordionGUI();
171  $acc->setUseSessionStorage(true);
172  $acc->setAllowMultiOpened(true);
173  $acc->setBehaviour(\ilAccordionGUI::FIRST_OPEN);
174  $acc->setId("crsobjtv_" . $this->container->getId());
175  } else {
176  $this->renderer->addCustomBlock('lobj', $lng->txt('crs_objectives'));
177  }
178 
179  $lur_data = $this->parseLOUserResults();
180  $has_initial = \ilLOSettings::getInstanceByObjId($this->container->getId())->worksWithInitialTest();
181  $has_lo_page = false;
182  $obj_cnt = 0;
183  foreach ($objective_ids as $objective_id) {
184  if (
185  $has_initial &&
186  (
187  !isset($lur_data[$objective_id]) or
189  $this->container->getId(),
190  \ilLOSettings::getInstanceByObjId($this->container->getId())->getInitialTest(),
191  $objective_id
192  )
193  )
194  ) {
195  $lur_data[$objective_id] = array("type" => \ilLOSettings::TYPE_TEST_INITIAL);
196  }
197  if ($html = $this->renderObjective((int) $objective_id, $has_lo_page, $acc, $lur_data[$objective_id] ?? null)) {
198  $this->renderer->addItemToBlock('lobj', 'lobj', $objective_id, $html);
199  }
200  $obj_cnt++;
201  }
202 
203  // buttons for showing/hiding all objectives
204  if (!$a_is_order && $obj_cnt > 1) {
205  $this->showButton("", $lng->txt("crs_show_all_obj"), "", "crs_show_all_obj_btn");
206  $this->showButton("", $lng->txt("crs_hide_all_obj"), "", "crs_hide_all_obj_btn");
207  $acc->setShowAllElement("crs_show_all_obj_btn");
208  $acc->setHideAllElement("crs_hide_all_obj_btn");
209  }
210 
211  // order/block
212  if ($a_is_order) {
213  $this->output_html .= $this->renderer->getHTML();
214 
215  $this->renderer->resetDetails();
216  }
217  // view/accordion
218  else {
219  $this->output_html .= "<div class='ilCrsObjAcc'>" . $acc->getHTML() . "</div>";
220  }
221  }
222 
223  protected function renderTest(
224  int $a_test_ref_id,
225  ?int $a_objective_id,
226  bool $a_is_initial = false
227  ): string {
228  $tree = $this->domain->repositoryTree();
229  $lng = $this->domain->lng();
230 
231  $node_data = [];
232  if ($a_test_ref_id) {
233  $node_data = $tree->getNodeData($a_test_ref_id);
234  }
235  if (!isset($node_data['child']) || !$node_data['child']) {
236  return '';
237  }
238 
239  // update ti
240  if ($a_objective_id) {
241  if ($a_is_initial) {
242  $title = sprintf($lng->txt('crs_loc_itst_for_objective'), \ilCourseObjective::lookupObjectiveTitle($a_objective_id));
243  } else {
244  $title = sprintf($lng->txt('crs_loc_qtst_for_objective'), \ilCourseObjective::lookupObjectiveTitle($a_objective_id));
245  }
246  $node_data['objective_id'] = $a_objective_id;
247  $node_data['objective_status'] = false;
248  } else {
249  $obj_id = \ilObject::_lookupObjId($a_test_ref_id);
250  $title = \ilObject::_lookupTitle($obj_id);
251 
252  $title .= (
253  ' (' .
254  (
255  $a_is_initial
256  ? $lng->txt('crs_loc_itest_info')
257  : $lng->txt('crs_loc_qtest_info')
258  ) .
259  ')'
260  );
261  $node_data['objective_id'] = 0;
262  }
263 
264  $node_data['title'] = $title;
265  return "<div class='ilContObjectivesViewTestItem'>" . $this->renderer->getItemRenderer()->renderItem($node_data) . "</div>";
266  }
267 
268  // Show all other (no assigned tests, no assigned materials) materials
269  /*
270  protected function showMaterials(
271  int $a_mode = null,
272  bool $a_is_manage = false,
273  bool $a_as_accordion = false
274  ) {
275  $lng = $this->domain->lng();
276 
277  if (is_array($this->items["_all"])) {
278  $this->objective_map = $this->buildObjectiveMap();
279 
280  // all rows
281  $item_r = array();
282 
283  $position = 1;
284  foreach ($this->items["_all"] as $k => $item_data) {
285  if ($a_mode == self::MATERIALS_TESTS and $item_data['type'] != 'tst') {
286  continue;
287  }
288  if ($item_data['type'] == 'itgr') {
289  continue;
290  }
291  if (!$a_is_manage) {
292  // if test object is qualified or initial do not show here
293  $assignments = ilLOTestAssignments::getInstance($this->getContainerObject()->getId());
294  if ($assignments->getTypeByTest($item_data['child']) != ilLOSettings::TYPE_TEST_UNDEFINED) {
295  continue;
296  }
297  }
298 
299  if ($this->rendered_items[$item_data["child"]] !== true &&
300  !$this->renderer->hasItem($item_data["child"])) {
301  $this->rendered_items[$item_data['child']] = true;
302 
303  // TODO: Position (DONE ?)
304  $html = $this->renderItem($item_data, $position++, !($a_mode == self::MATERIALS_TESTS));
305  if ($html != "") {
306  $item_r[] = array("html" => $html, "id" => $item_data["child"], "type" => $item_data["type"]);
307  }
308  }
309  }
310 
311  // if we have at least one item, output the block
312  if (count($item_r) > 0) {
313  if (!$a_as_accordion) {
314  $pos = 0;
315 
316  switch ($a_mode) {
317  case self::MATERIALS_TESTS:
318  $block_id = "tst";
319  $this->renderer->addTypeBlock($block_id);
320  break;
321 
322  case self::MATERIALS_OTHER:
323  $block_id = "oth";
324  $this->renderer->addCustomBlock($block_id, $lng->txt('crs_other_resources'));
325  break;
326 
327  // manage
328  default:
329  $block_id = "all";
330  $this->renderer->addCustomBlock($block_id, $lng->txt('content'));
331  break;
332  }
333 
334  // :TODO:
335  if ($a_mode != self::MATERIALS_TESTS) {
336  $pos = $this->getItemGroupsHTML();
337  }
338 
339  foreach ($item_r as $h) {
340  if (!$this->renderer->hasItem($h["id"])) {
341  $this->renderer->addItemToBlock($block_id, $h["type"], $h["id"], $h["html"]);
342  }
343  }
344 
345  $this->output_html .= $this->renderer->getHTML();
346  } else {
347  $txt = "";
348  switch ($a_mode) {
349  case self::MATERIALS_TESTS:
350  $txt = $lng->txt('objs_tst');
351  break;
352 
353  case self::MATERIALS_OTHER:
354  $txt = $lng->txt('crs_other_resources');
355  break;
356  }
357 
358  $acc = new ilAccordionGUI();
359  $acc->setId("crsobjtvmat" . $a_mode . "_" . $this->container_obj->getId());
360 
361  $acc_content = array();
362  foreach ($item_r as $h) {
363  $acc_content[] = $h["html"];
364  }
365  $acc->addItem($txt, $this->buildAccordionContent($acc_content));
366 
367  $this->output_html .= $acc->getHTML();
368  }
369  }
370  }
371  }*/
372 
373 
374  /* unsure where this one is called...
375  protected function updateResult(
376  array $a_res,
377  int $a_item_ref_id,
378  int $a_objective_id,
379  int $a_user_id
380  ) : array {
381  if ($this->loc_settings->getQualifiedTest() == $a_item_ref_id) {
382  // Check for existing test run, and decrease tries, reset final if run exists
383  $active = ilObjTest::isParticipantsLastPassActive(
384  $a_item_ref_id,
385  $a_user_id
386  );
387 
388  if ($active) {
389  if (ilLOTestRun::lookupRunExistsForObjective(
390  ilObject::_lookupObjId($a_item_ref_id),
391  $a_objective_id,
392  $a_user_id
393  )) {
394  if ($a_res['tries'] > 0) {
395  --$a_res['tries'];
396  }
397  $a_res['is_final'] = 0;
398  }
399  }
400  }
401  return $a_res;
402  }*/
403 
412  protected function renderObjective(
413  int $a_objective_id,
414  bool &$a_has_lo_page,
415  ?\ilAccordionGUI $a_accordion = null,
416  ?array $a_lo_result = null
417  ): string {
418  $ilUser = $this->domain->user();
419  $lng = $this->domain->lng();
420 
421  $objective = new \ilCourseObjective($this->container, $a_objective_id);
422 
423  $items = \ilObjectActivation::getItemsByObjective($a_objective_id);
424 
425  // sorting is handled by ilCourseObjectiveMaterials
426  // $items = ilContainerSorting::_getInstance($this->getContainerObject()->getId())->sortSubItems('lobj',$a_objective_id,$items);
427 
428  $objectives_lm_obj = new \ilCourseObjectiveMaterials($a_objective_id);
429 
430  // #13381 - map material assignment to position
431  $sort_map = array();
432  foreach ($objectives_lm_obj->getMaterials() as $item) {
433  $sort_map[$item["lm_ass_id"]] = $item["position"];
434  }
435 
436  $is_manage = $this->container_gui->isActiveAdministrationPanel();
437  $is_order = $this->container_gui->isActiveOrdering();
438 
439  $sort_content = array();
440 
441  $access = $this->domain->access();
442  foreach ($items as $item) {
443 
444  if (!$access->checkAccess('visible', '', $item["ref_id"])) {
445  continue;
446  }
447  /*
448  if ($this->getDetailsLevel($a_objective_id) < self::DETAILS_ALL) {
449  continue;
450  }*/
451 
452  $item_list_gui2 = $this->renderer->getItemRenderer()->getItemGUI($item);
453  $item_list_gui2->enableIcon(true);
454 
455  if ($is_order || $a_accordion) {
456  $item_list_gui2->enableCommands(true, true);
457  $item_list_gui2->enableProperties(false);
458  }
459 
460  $chapters = $objectives_lm_obj->getChapters();
461  if (count($chapters)) {
462  $has_sections = false;
463  foreach ($chapters as $chapter) {
464  if ($chapter['ref_id'] != $item['child']) {
465  continue;
466  }
467  $has_sections = true;
468 
469  $title = $item['title'] .
470  " &rsaquo; " . \ilLMObject::_lookupTitle($chapter['obj_id']) .
471  " (" . $lng->txt('obj_' . $chapter['type']) . ")";
472 
473  $item_list_gui2->setDefaultCommandParameters(array(
474  "obj_id" => $chapter['obj_id'],
475  "focus_id" => $chapter['obj_id'],
476  "focus_return" => $this->container->getRefId()));
477 
478  if ($is_order) {
479  $item_list_gui2->setPositionInputField(
480  "[lobj][" . $a_objective_id . "][" . $chapter['lm_ass_id'] . "]",
481  sprintf('%d', $chapter['position'] * 10)
482  );
483  }
484 
485  $sub_item_html = $item_list_gui2->getListItemHTML(
486  (int) $item['ref_id'],
487  (int) $item['obj_id'],
488  $title,
489  $item['description']
490  );
491 
492  // #13381 - use materials order
493  $sort_key = str_pad(
494  (string) $chapter['position'],
495  5,
496  "0",
497  STR_PAD_LEFT
498  ) . "_" . strtolower($title) . "_" . $chapter['lm_ass_id'];
499  $sort_content[$sort_key] = $sub_item_html;
500  }
501  }
502 
503  $this->rendered_items[$item['child']] = true;
504 
505  if ($lm_ass_id = $objectives_lm_obj->isAssigned((int) $item['ref_id'], true)) {
506  if ($is_order) {
507  $item_list_gui2->setPositionInputField(
508  "[lobj][" . $a_objective_id . "][" . $lm_ass_id . "]",
509  sprintf('%d', $sort_map[$lm_ass_id] * 10)
510  );
511  }
512 
513  $sub_item_html = $item_list_gui2->getListItemHTML(
514  $item['ref_id'],
515  $item['obj_id'],
516  $item['title'],
517  $item['description']
518  );
519 
520  // #13381 - use materials order
521  $sort_key = str_pad((string) $sort_map[$lm_ass_id], 5, "0", STR_PAD_LEFT) . "_" . strtolower($item['title']) . "_" . $lm_ass_id;
522  $sort_content[$sort_key] = $sub_item_html;
523  }
524  }
525 
526  //if ($this->getDetailsLevel($a_objective_id) == self::DETAILS_ALL) {
527  $this->objective_list_gui->enableCommands(false);
528  //} else {
529  // $this->objective_list_gui->enableCommands(true);
530  //}
531 
532  if ($is_order) {
533  $this->objective_list_gui->setPositionInputField(
534  "[lobj][" . $a_objective_id . "][0]",
535  (string) ($objective->__getPosition() * 10)
536  );
537  }
538 
539  ksort($sort_content);
540  if (!$a_accordion) {
541  foreach ($sort_content as $sub_item_html) {
542  $this->objective_list_gui->addSubItemHTML($sub_item_html);
543  }
544 
545  return $this->objective_list_gui->getObjectiveListItemHTML(
546  0,
547  $a_objective_id,
548  $objective->getTitle(),
549  $objective->getDescription(),
550  ($is_manage || $is_order)
551  );
552  } else {
553  $acc_content = $sort_content;
554 
555  $initial_shown = false;
556  $initial_test_ref_id = $this->test_assignments->getTestByObjective($a_objective_id, \ilLOSettings::TYPE_TEST_INITIAL);
557  $initial_test_obj_id = \ilObject::_lookupObjId($initial_test_ref_id);
558 
559  if (
560  $initial_test_obj_id &&
561  $this->loc_settings->hasSeparateInitialTests() &&
562  !\ilObjTestAccess::checkCondition($initial_test_obj_id, \ilConditionHandler::OPERATOR_FINISHED, '', $ilUser->getId())
563  ) {
564  $acc_content[] = $this->renderTest(
565  $this->test_assignments->getTestByObjective($a_objective_id, \ilLOSettings::TYPE_TEST_INITIAL),
566  $a_objective_id,
567  true
568  );
569  $initial_shown = true;
570  } elseif ($this->loc_settings->hasSeparateQualifiedTests()) {
571  $acc_content[] = $this->renderTest(
572  $this->test_assignments->getTestByObjective($a_objective_id, \ilLOSettings::TYPE_TEST_QUALIFIED),
573  $a_objective_id,
574  false
575  );
576  }
577 
578  $co_page = null;
579  if (\ilPageUtil::_existsAndNotEmpty("lobj", $objective->getObjectiveId())) {
580  $a_has_lo_page = true;
581 
582  $page_gui = new \ilLOPageGUI($objective->getObjectiveId());
583 
584  $page_gui->setStyleId(
585  $this->content_style_domain->getEffectiveStyleId()
586  );
587  $page_gui->setPresentationTitle("");
588  $page_gui->setTemplateOutput(false);
589  $page_gui->setHeader("");
590 
591  $co_page = "<div class='ilContObjectiveIntro'>" . $page_gui->showPage() . "</div>";
592  }
593 
594  $a_accordion->addItem(
595  $this->buildAccordionTitle($objective, $a_lo_result),
596  $co_page .
597  $this->buildAccordionContent($acc_content),
598  ($this->request->getObjectiveId() == $objective->getObjectiveId())
599  );
600  }
601  return "";
602  }
603 
604  // Parse learning objective results.
605  protected function parseLOUserResults(): array
606  {
607  $ilUser = $this->domain->user();
608  $initial_status = null;
609 
610  $res = array();
611 
612  $lo_ass = \ilLOTestAssignments::getInstance($this->container->getId());
613 
614  $lur = new \ilLOUserResults($this->container->getId(), $ilUser->getId());
615  foreach ($lur->getCourseResultsForUserPresentation() as $objective_id => $types) {
616  // show either initial or qualified for objective
617  if (isset($types[\ilLOUserResults::TYPE_INITIAL])) {
618  $initial_status = $types[\ilLOUserResults::TYPE_INITIAL]["status"];
619  }
620 
621  // qualified test has priority
622  if (isset($types[\ilLOUserResults::TYPE_QUALIFIED])) {
623  $result = $types[\ilLOUserResults::TYPE_QUALIFIED];
624  $result["type"] = \ilLOUserResults::TYPE_QUALIFIED;
625  $result["initial"] = $types[\ilLOUserResults::TYPE_INITIAL] ?? null;
626  } else {
627  $result = $types[\ilLOUserResults::TYPE_INITIAL];
628  $result["type"] = \ilLOUserResults::TYPE_INITIAL;
629  }
630 
631  $result["initial_status"] = $initial_status;
632 
633  $result["itest"] = $lo_ass->getTestByObjective($objective_id, \ilLOSettings::TYPE_TEST_INITIAL);
634  $result["qtest"] = $lo_ass->getTestByObjective($objective_id, \ilLOSettings::TYPE_TEST_QUALIFIED);
635 
636  $res[$objective_id] = $result;
637  }
638 
639  return $res;
640  }
641 
642 
659  public static function renderProgressMeter(
660  ?int $a_perc_result = null,
661  ?int $a_perc_limit = null,
662  ?int $a_compare_value = null,
663  ?string $a_caption = null,
664  ?string $a_url = null,
665  ?string $a_tt_id = null,
666  ?string $a_tt_txt = null,
667  ?string $a_next_step = null,
668  bool $a_sub = false,
669  int $a_sub_style = 30,
670  string $a_main_text = '',
671  string $a_required_text = ''
672  ): string {
673  global $DIC;
674 
675  $tpl = new \ilTemplate("tpl.objective_progressmeter.html", true, true, "components/ILIAS/Container");
676 
677  $lng = $DIC->language();
678  $lng->loadLanguageModule('crs');
679 
680 
681 
682  if (is_numeric($a_perc_result)) {
683  $uiFactory = $DIC->ui()->factory();
684  $uiRenderer = $DIC->ui()->renderer();
685 
686  $pMeter = $uiFactory->chart()->progressMeter()->standard(
687  100,
688  (int) $a_perc_result,
689  (int) $a_perc_limit,
690  (int) $a_compare_value
691  );
692  $tpl->setVariable('PROGRESS_METER', $uiRenderer->render($pMeter));
693  }
694 
695  if ($a_caption) {
696  if ($a_url) {
697  $button = \ilLinkButton::getInstance();
698  $button->setCaption($a_caption, false);
699  $button->setUrl($a_url);
700 
701  $tpl->setCurrentBlock("statustxt_bl");
702  $tpl->setVariable("TXT_PROGRESS_STATUS", $button->render());
703  } else {
704  $tpl->setCurrentBlock("statustxt_no_link_bl");
705  $tpl->setVariable("TXT_PROGRESS_STATUS_NO_LINK", $a_caption);
706  }
707  $tpl->parseCurrentBlock();
708  }
709 
710  if ($a_next_step) {
711  //$tpl->setCurrentBlock("nstep_bl");
712  $tpl->setVariable("TXT_NEXT_STEP", $a_next_step);
713  //$tpl->parseCurrentBlock();
714  }
715 
716  if ($a_sub) {
717  $tpl->setVariable("SUB_STYLE", ' style="padding-left: ' . $a_sub_style . 'px;"');
718  $tpl->setVariable("SUB_INIT", $a_sub);
719  }
720 
721  return $tpl->get();
722  }
723 
727  public static function getObjectiveResultSummary(
728  bool $a_has_initial_test,
729  int $a_objective_id,
730  array $a_lo_result
731  ): string {
732  global $DIC;
733 
734  if ($a_lo_result === null) {
735  $a_lo_result["type"] = null;
736  }
737  if (!isset($a_lo_result["type"])) {
738  $a_lo_result["type"] = null;
739  }
740 
741  $lng = $DIC->language();
742  $lng->loadLanguageModule('crs');
743 
744  $is_qualified =
745  ($a_lo_result["type"] == \ilLOUserResults::TYPE_QUALIFIED);
746  $is_qualified_initial =
747  (
748  $a_lo_result['type'] == \ilLOUserResults::TYPE_INITIAL &&
749  \ilLOSettings::getInstanceByObjId($a_lo_result['course_id'] ?? 0)->isInitialTestQualifying()
750  );
751  $has_completed = (int) ($a_lo_result["status"] ?? 0) === \ilLOUserResults::STATUS_COMPLETED;
752 
753  $next_step = $progress_txt = $bar_color = $test_url = $initial_sub = null;
754 
755  if (
756  $is_qualified ||
757  $is_qualified_initial) {
758  if ($has_completed) {
759  $next_step = $lng->txt("crs_loc_progress_objective_complete");
760  } else {
761  $next_step = $lng->txt("crs_loc_progress_do_qualifying_again");
762  }
763  } // initial test
764  else {
765  if ($a_lo_result["status"] ?? 0) {
766  $next_step =
767  $has_completed ?
768  $lng->txt("crs_loc_progress_do_qualifying") :
769  $lng->txt("crs_loc_suggested");
770  } else {
771  $next_step = $a_has_initial_test ?
772  $lng->txt("crs_loc_progress_no_result_do_initial") :
773  $lng->txt("crs_loc_progress_no_result_no_initial");
774  }
775  }
776  return $next_step;
777  }
778 
782  public static function buildObjectiveProgressBar(
783  bool $a_has_initial_test,
784  int $a_objective_id,
785  array $a_lo_result,
786  bool $a_list_mode = false,
787  bool $a_sub = false,
788  ?string $a_tt_suffix = null
789  ): string {
790  global $DIC;
791 
792  $lng = $DIC->language();
793  $lng->loadLanguageModule('crs');
794 
795  // tooltip (has to be unique!)
796 
797  $tooltip_id = "crsobjtvusr_" . $a_objective_id . "_" . $a_lo_result["type"] . "_" . ((int) $a_sub);
798  if ($a_tt_suffix !== null) {
799  $tooltip_id .= "_" . $a_tt_suffix;
800  }
801 
802  $tt_txt = sprintf(
803  $lng->txt("crs_loc_tt_info"),
804  $a_lo_result["result_perc"] ?? '0',
805  $a_lo_result["limit_perc"] ?? '0'
806  );
807 
808 
809  $is_qualified = ($a_lo_result["type"] == \ilLOUserResults::TYPE_QUALIFIED);
810  $is_qualified_initial = ($a_lo_result['type'] == \ilLOUserResults::TYPE_INITIAL &&
811  \ilLOSettings::getInstanceByObjId($a_lo_result['course_id'] ?? 0)->isInitialTestQualifying());
812  $has_completed = (($a_lo_result["status"] ?? 0) == \ilLOUserResults::STATUS_COMPLETED);
813 
814  $next_step = $progress_txt = $bar_color = $test_url = $initial_sub = null;
815  $compare_value = null;
816 
817  if ($is_qualified ||
818  $is_qualified_initial) {
819  $progress_txt = $lng->txt("crs_loc_progress_result_qtest");
820  $tt_txt = $lng->txt("crs_loc_tab_qtest") . ": " . $tt_txt;
821 
822  if ($has_completed) {
823  $next_step = $lng->txt("crs_loc_progress_objective_complete");
824  $bar_color = "ilCourseObjectiveProgressBarCompleted";
825 
826  // render 2nd progressbar if there is also an initial test
827  if ($is_qualified &&
828  $a_has_initial_test &&
829  is_array($a_lo_result["initial"])) {
830  $a_lo_result["initial"]["itest"] = $a_lo_result["itest"];
831 
832  // force list mode to get rid of next step
833  #$initial_sub = self::buildObjectiveProgressBar(true, $a_objective_id, $a_lo_result["initial"], true, true, $a_tt_suffix);
834  $compare_value = $a_lo_result['initial']['result_perc'];
835  }
836  } else {
837  $next_step = $lng->txt("crs_loc_progress_do_qualifying_again");
838  $bar_color = "ilCourseObjectiveProgressBarFailed";
839  }
840  }
841  // initial test
842  else {
843  if ($a_lo_result["status"] ?? 0) {
844  $progress_txt = $lng->txt("crs_loc_progress_result_itest");
845  $tt_txt = $lng->txt("crs_loc_tab_itest") . ": " . $tt_txt;
846 
847  $bar_color = "ilCourseObjectiveProgressBarNeutral";
848  $next_step = $has_completed
849  ? $lng->txt("crs_loc_progress_do_qualifying")
850  : $lng->txt("crs_loc_suggested");
851  }
852  // not attempted: no progress bar
853  else {
854  $next_step = $a_has_initial_test
855  ? $lng->txt("crs_loc_progress_no_result_do_initial")
856  : $lng->txt("crs_loc_progress_no_result_no_initial");
857  }
858  }
859 
860  // link to test statistics
861  $relevant_test_id = ($a_lo_result["qtest"] ?? 0)
862  ?: ($a_lo_result["itest"] ?? 0);
863  if ($relevant_test_id) {
864  $test_url = \ilLOUtils::getTestResultLinkForUser($relevant_test_id, $a_lo_result["user_id"] ?? 0);
865  }
866 
867  $main_text = $lng->txt('crs_loc_itest_info');
868  if ($a_lo_result['type'] == \ilLOSettings::TYPE_TEST_QUALIFIED) {
869  $main_text = $lng->txt('crs_loc_qtest_info');
870  }
871 
872 
873 
874  return self::renderProgressMeter(
875  $a_lo_result["result_perc"] ?? null,
876  $a_lo_result["limit_perc"] ?? null,
877  $compare_value,
878  $progress_txt,
879  $test_url,
880  $tooltip_id,
881  $tt_txt,
882  $a_list_mode
883  ? null
884  : $next_step,
885  (bool) $initial_sub,
886  $a_list_mode
887  ? 30
888  : 10,
889  $main_text,
890  $lng->txt('crs_lobj_pm_min_goal')
891  );
892  }
893 
894  protected function buildAccordionTitle(
895  \ilCourseObjective $a_objective,
896  ?array $a_lo_result = null
897  ): string {
898  global $DIC;
899 
900  $renderer = $DIC->ui()->renderer();
901  $ui_factory = $DIC->ui()->factory();
902 
903  $tpl = new \ilTemplate("tpl.objective_accordion_title.html", true, true, "components/ILIAS/Container");
904 
905  if ($a_lo_result) {
906  $tpl->setVariable(
907  "PROGRESS_BAR",
908  self::buildObjectiveProgressBar(
909  $this->loc_settings->worksWithInitialTest(),
910  $a_objective->getObjectiveId(),
911  $a_lo_result
912  )
913  );
914  }
915 
916  $tpl->setVariable("TITLE", $this->lng->txt("crs_loc_learning_objective") . ": " . trim($a_objective->getTitle()));
917  $tpl->setVariable("DESCRIPTION", nl2br(trim($a_objective->getDescription())));
918 
919  $initial_res = null;
920  $initial_lim = null;
921  if ($this->loc_settings->worksWithInitialTest()) {
922  if (array_key_exists('initial', $a_lo_result)) {
923  $initial_res = (int) ($a_lo_result['initial']['result_perc'] ?? 0);
924  $initial_lim = (int) ($a_lo_result['initial']['limit_perc'] ?? 100);
925  }
926  if (
927  ($a_lo_result['type'] ?? \ilLOUserResults::TYPE_UNDEFINED) == \ilLOUserResults::TYPE_INITIAL &&
928  isset($a_lo_result['result_perc'])
929  ) {
930  $initial_res = (int) $a_lo_result['result_perc'];
931  $initial_lim = (int) $a_lo_result['limit_perc'];
932  }
933  }
934 
935  if ($initial_res !== null) {
937  $a_lo_result["itest"],
938  $a_lo_result["user_id"]
939  );
940 
941  if (strlen($link)) {
942  $tpl->setCurrentBlock('i_with_link');
943  $tpl->setVariable(
944  'IBTN',
945  $renderer->render(
946  $ui_factory->button()->shy(
947  $this->lng->txt('crs_objective_result_details'),
948  $link
949  )
950  )
951  );
952  $tpl->parseCurrentBlock();
953  }
954 
955  $tpl->setCurrentBlock('res_initial');
956  $tpl->setVariable(
957  'IRESULT',
958  sprintf(
959  $this->lng->txt('crs_objective_result_summary_initial'),
960  $initial_res . '%',
961  (int) $initial_lim . '%'
962  )
963  );
964  $tpl->parseCurrentBlock();
965  }
966 
967  $qual_res = null;
968  $qual_lim = null;
969 
970  if (($a_lo_result['type'] ?? \ilLOUserResults::TYPE_UNDEFINED) == \ilLOUserResults::TYPE_QUALIFIED) {
971  $qual_res = (int) $a_lo_result['result_perc'];
972  $qual_lim = (int) $a_lo_result['limit_perc'];
973  }
974 
975  if ($qual_res !== null) {
977  $a_lo_result["qtest"],
978  $a_lo_result["user_id"]
979  );
980 
981  if (strlen($link)) {
982  $tpl->setCurrentBlock('q_with_link');
983  $tpl->setVariable(
984  'QBTN',
985  $renderer->render(
986  $ui_factory->button()->shy(
987  $this->lng->txt('crs_objective_result_details'),
988  $link
989  )
990  )
991  );
992  $tpl->parseCurrentBlock();
993  }
994  $tpl->setCurrentBlock('res_qualifying');
995  $tpl->setVariable(
996  'QRESULT',
997  sprintf(
998  $this->lng->txt('crs_objective_result_summary_qualifying'),
999  $qual_res . '%',
1000  (int) $qual_lim . '%'
1001  )
1002  );
1003  $tpl->parseCurrentBlock();
1004  }
1005 
1006  //$this->logger->dump($a_lo_result);
1007 
1008  $summary = self::getObjectiveResultSummary(
1009  $this->loc_settings->worksWithInitialTest(),
1010  $a_objective->getObjectiveId(),
1011  $a_lo_result ?? []
1012  );
1013  if (strlen($summary)) {
1014  $tpl->setCurrentBlock('objective_summary');
1015  $tpl->setVariable('SUMMARY_TXT', $summary);
1016  $tpl->parseCurrentBlock();
1017  }
1018 
1019  // #15510
1020  $tpl->setVariable("ANCHOR_ID", "objtv_acc_" . $a_objective->getObjectiveId());
1021 
1022  return $tpl->get();
1023  }
1024 
1025  protected function buildAccordionContent(array $a_items): string
1026  {
1027  $tpl = new \ilTemplate("tpl.objective_accordion_content.html", true, true, "components/ILIAS/Container");
1028  foreach ($a_items as $item) {
1029  $tpl->setCurrentBlock("items_bl");
1030  $tpl->setVariable("ITEM", $item);
1031  $tpl->parseCurrentBlock();
1032  }
1033  return $tpl->get();
1034  }
1035 
1036  protected function showButton(
1037  string $a_cmd,
1038  string $a_text,
1039  string $a_target = '',
1040  string $a_id = ""
1041  ): void {
1042  $ilToolbar = $this->gui->toolbar();
1043  $ilCtrl = $this->gui->ctrl();
1044 
1045  // #11842
1046  $ilToolbar->addButton(
1047  $a_text,
1048  $ilCtrl->getLinkTarget($this->container_gui, $a_cmd),
1049  $a_target,
1050  null,
1051  '',
1052  $a_id
1053  );
1054  }
1055 }
static hasActiveRun(int $a_container_id, int $a_test_ref_id, int $a_objective_id)
$res
Definition: ltiservices.php:66
ILIAS Container StandardGUIRequest $request
static getObjectiveResultSummary(bool $a_has_initial_test, int $a_objective_id, array $a_lo_result)
Get objective result summary.
static hasResults(int $a_container_id, int $a_user_id)
ILIAS Style Content Object ObjectFacade $content_style_domain
renderer()
static _getObjectiveIds(int $course_id, bool $a_activated_only=false)
static buildObjectiveProgressBar(bool $a_has_initial_test, int $a_objective_id, array $a_lo_result, bool $a_list_mode=false, bool $a_sub=false, ?string $a_tt_suffix=null)
Render progressbar(s) for given objective and result data.
static _lookupObjId(int $ref_id)
static _lookupTitle(int $a_obj_id)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
static renderProgressMeter(?int $a_perc_result=null, ?int $a_perc_limit=null, ?int $a_compare_value=null, ?string $a_caption=null, ?string $a_url=null, ?string $a_tt_id=null, ?string $a_tt_txt=null, ?string $a_next_step=null, bool $a_sub=false, int $a_sub_style=30, string $a_main_text='', string $a_required_text='')
Render progress meter.
static getTestResultLinkForUser(int $a_test_ref_id, int $a_user_id)
static _existsAndNotEmpty(string $a_parent_type, int $a_id, string $a_lang="-")
checks whether page exists and is not empty (may return true on some empty pages) ...
static _lookupTitle(int $obj_id)
__construct()
Constructor setup ILIAS global object public.
Definition: class.ilias.php:76
class ilcourseobjective
global $DIC
Definition: shib_login.php:26
static lookupObjectiveTitle(int $a_objective_id, bool $a_add_description=false)
static getInstanceByObjId(int $a_obj_id)
showButton(string $a_cmd, string $a_text, string $a_target='', string $a_id="")
static getItemsByObjective(int $objective_id)
Get objective items.
global $ilSetting
Definition: privfeed.php:31
buildAccordionTitle(\ilCourseObjective $a_objective, ?array $a_lo_result=null)
renderTest(int $a_test_ref_id, ?int $a_objective_id, bool $a_is_initial=false)
static getInstance(int $a_container_id)
renderObjective(int $a_objective_id, bool &$a_has_lo_page, ?\ilAccordionGUI $a_accordion=null, ?array $a_lo_result=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static checkCondition(int $a_trigger_obj_id, string $a_operator, string $a_value, int $a_usr_id)
check condition for a specific user and object
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...