ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilPersonalSkillsGUI.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
37 
45 {
46  public const LIST_SELECTED = "selected";
47  public const LIST_PROFILES = "";
48 
49  protected string $offline_mode = "";
50 
54  protected array $actual_levels = [];
55 
59  protected array $next_level_fuls = [];
60 
64  protected array $gap_self_eval_levels = [];
65  protected bool $history_view = false;
66 
70  protected array $trigger_objects_filter = [];
71  protected string $intro_text = "";
72 
76  protected array $hidden_skills = [];
77  protected string $mode = "";
78  protected string $gap_mode = "";
79  protected int $gap_mode_obj_id = 0;
80  protected string $gap_mode_type = "";
81  protected string $gap_cat_title = "";
82 
83  protected UIServices $ui;
84  protected ilCtrl $ctrl;
85  protected ilLanguage $lng;
86  protected ilHelpGUI $help;
87  protected ilSetting $setting;
88  protected ilObjUser $user;
90  protected ilTabsGUI $tabs;
93  protected Factory $ui_fac;
94  protected Renderer $ui_ren;
95  protected ServerRequestInterface $request;
98  protected ilTree $tree;
100 
101  protected int $obj_id = 0;
102 
106  protected array $obj_skills = [];
107  protected int $profile_id = 0;
108 
112  protected array $profile_levels = [];
113 
117  protected array $user_profiles = [];
118 
122  protected array $cont_profiles = [];
123  protected bool $use_materials = false;
126  protected Service\SkillPersonalGUIRequest $personal_gui_request;
129  protected Service\SkillTreeService $tree_service;
130  protected Service\SkillInternalManagerService $internal_manager;
131  protected Profile\SkillProfileManager $profile_manager;
132  protected Profile\SkillProfileCompletionManager $profile_completion_manager;
133  protected Personal\PersonalSkillManager $personal_manager;
134  protected Personal\AssignedMaterialManager $assigned_material_manager;
135  protected Personal\SelfEvaluationManager $self_evaluation_manager;
136  protected Resource\SkillResourcesManager $resource_manager;
137  protected Table\TableManager $table_manager;
139  protected string $requested_list_mode = self::LIST_PROFILES;
140  protected int $requested_node_id = 0;
141  protected int $requested_profile_id = 0;
142  protected int $requested_skill_id = 0;
143 
147  protected array $requested_skill_ids = [];
148  protected int $requested_basic_skill_id = 0;
149  protected int $requested_tref_id = 0;
150  protected int $requested_level_id = 0;
151 
153 
159 
163  protected array $requested_wsp_ids = [];
164 
168  protected array $trigger_user_filter = [];
169 
170  public function __construct()
171  {
172  global $DIC;
173 
174  $this->ctrl = $DIC->ctrl();
175  $this->lng = $DIC->language();
176  $this->help = $DIC["ilHelp"];
177  $this->setting = $DIC["ilSetting"];
178  $this->user = $DIC->user();
179  $this->tpl = $DIC["tpl"];
180  $this->tabs = $DIC->tabs();
181  $this->toolbar = $DIC->toolbar();
182  $this->access = $DIC->access();
183  $this->ui_fac = $DIC->ui()->factory();
184  $this->ui_ren = $DIC->ui()->renderer();
185  $this->request = $DIC->http()->request();
186  $this->ui = $DIC->ui();
187  $this->storage = $DIC->resourceStorage();
188  $this->data_fac = new \ILIAS\Data\Factory();
189  $this->tree = $DIC->repositoryTree();
190  $this->obj_definition = $DIC["objDefinition"];
191  $this->personal_gui_request = $DIC->skills()->internal()->gui()->personal_request();
192  $this->tree_repo = $DIC->skills()->internal()->repo()->getTreeRepo();
193  $this->level_repo = $DIC->skills()->internal()->repo()->getLevelRepo();
194  $this->tree_service = $DIC->skills()->tree();
195  $this->internal_manager = $DIC->skills()->internal()->manager();
196  $this->profile_manager = $this->internal_manager->getProfileManager();
197  $this->profile_completion_manager = $this->internal_manager->getProfileCompletionManager();
198  $this->personal_manager = $this->internal_manager->getPersonalSkillManager();
199  $this->assigned_material_manager = $this->internal_manager->getAssignedMaterialManager();
200  $this->self_evaluation_manager = $this->internal_manager->getSelfEvaluationManager();
201  $this->resource_manager = $this->internal_manager->getResourceManager();
202  $this->table_manager = $this->internal_manager->getTableManager();
203  $this->cont_factory_service = $DIC->skills()->internalContainer()->factory();
204 
205  $ilCtrl = $this->ctrl;
206  $ilHelp = $this->help;
207  $lng = $this->lng;
209 
210 
211  $lng->loadLanguageModule('skmg');
212  $ilHelp->setScreenIdComponent("skill");
213 
214  $ilCtrl->saveParameter($this, "skill_id");
215  $ilCtrl->saveParameter($this, "tref_id");
216  $ilCtrl->saveParameter($this, "profile_id");
217  $ilCtrl->saveParameter($this, "list_mode");
218 
219  $this->requested_list_mode = $this->personal_gui_request->getListMode();
220  $this->requested_node_id = $this->personal_gui_request->getNodeId();
221  $this->requested_profile_id = $this->personal_gui_request->getProfileId();
222  $this->requested_skill_id = $this->personal_gui_request->getSkillId();
223  $this->requested_skill_ids = $this->personal_gui_request->getSkillIds();
224  $this->requested_basic_skill_id = $this->personal_gui_request->getBasicSkillId();
225  $this->requested_tref_id = $this->personal_gui_request->getTrefId();
226  $this->requested_level_id = $this->personal_gui_request->getLevelId();
227  $this->requested_wsp_ids = $this->personal_gui_request->getWorkspaceIds();
228  $this->requested_table_assign_materials_action = $this->personal_gui_request->getTableAssignMaterialsAction();
229  $this->requested_table_assign_materials_level_ids = $this->personal_gui_request->getTableAssignMaterialsLevelIds();
230  $this->requested_table_assign_materials_wsp_id = $this->personal_gui_request->getTableAssignMaterialsWorkspaceId();
231 
232  $this->user_profiles = $this->profile_manager->getProfilesOfUser($this->user->getId());
233  $this->cont_profiles = [];
234 
235  $this->use_materials = !$ilSetting->get("disable_personal_workspace");
236 
237  $this->skmg_settings = new ilSkillManagementSettings();
238 
239  $this->filter = new ilPersonalSkillsFilterGUI();
240  }
241 
243  {
244  return $this->filter;
245  }
246 
247  public function setProfileId(int $a_val): void
248  {
249  $this->profile_id = $a_val;
250  }
251 
252  public function getProfileId(): int
253  {
254  return $this->profile_id;
255  }
256 
260  public function setGapAnalysisSelfEvalLevels(array $a_val): void
261  {
262  $this->gap_self_eval_levels = $a_val;
263  }
264 
268  public function getGapAnalysisSelfEvalLevels(): array
269  {
271  }
272 
273  public function setHistoryView(bool $a_val): void
274  {
275  $this->history_view = $a_val;
276  }
277 
278  public function getHistoryView(): bool
279  {
280  return $this->history_view;
281  }
282 
283  public function getNonHistoricGapModeView(): bool
284  {
285  return ($this->mode == "gap" && !$this->history_view);
286  }
287 
288  public function getTriggerObjectsFilter(): array
289  {
291  }
292 
293  public function setTriggerObjectsFilter(array $trigger_objects_filter): void
294  {
295  $this->trigger_objects_filter = $trigger_objects_filter;
296  }
297 
298  public function setIntroText(string $a_val): void
299  {
300  $this->intro_text = $a_val;
301  }
302 
303  public function getIntroText(): string
304  {
305  return $this->intro_text;
306  }
307 
311  public function getTriggerUserFilter(): array
312  {
314  }
315 
319  public function setTriggerUserFilter(array $trigger_user_filter): void
320  {
321  $this->trigger_user_filter = $trigger_user_filter;
322  }
323 
324  public function hideSkill(int $a_skill_id, int $a_tref_id = 0): void
325  {
326  $this->hidden_skills[] = $a_skill_id . ":" . $a_tref_id;
327  }
328 
329  public function getObjectId(): int
330  {
331  return $this->obj_id;
332  }
333 
337  public function getObjectSkills(): array
338  {
339  return $this->obj_skills;
340  }
341 
345  public function setObjectSkills(int $a_obj_id, array $a_skills): void
346  {
347  $this->obj_id = $a_obj_id;
348  $this->obj_skills = $a_skills;
349  }
350 
351  public function setObjectSkillProfiles(
352  int $cont_member_role_id
353  ): void {
354  $this->cont_profiles = $this->profile_manager->getAllProfilesOfRole($cont_member_role_id);
355  }
356 
357  public function executeCommand(): void
358  {
359  $ilCtrl = $this->ctrl;
360  $ilUser = $this->user;
361  $lng = $this->lng;
362  $tpl = $this->tpl;
363 
364  $next_class = $ilCtrl->getNextClass($this);
365 
366 
367  $cmd = $ilCtrl->getCmd("render");
368 
369  //$tpl->setTitle($lng->txt("skills"));
370  //$tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_skmg.svg"));
371 
372  switch ($next_class) {
373  default:
374  $this->$cmd();
375  break;
376  }
377  }
378 
379  public function setTabs(string $a_activate): void
380  {
381  $ilCtrl = $this->ctrl;
382  $lng = $this->lng;
383  $ilTabs = $this->tabs;
384 
385  if (!empty($this->user_profiles)) {
386  $ilCtrl->setParameter($this, "list_mode", self::LIST_PROFILES);
387  $ilTabs->addTab(
388  "profile",
389  $lng->txt("skmg_assigned_profiles"),
390  $ilCtrl->getLinkTarget($this, "render")
391  );
392  }
393 
394  // list skills
395  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
396  $ilTabs->addTab(
397  "list_skills",
398  $lng->txt("skmg_selected_skills"),
399  $ilCtrl->getLinkTarget($this, "render")
400  );
401 
402  $ilCtrl->clearParameterByClass(get_class($this), "list_mode");
403 
404  // assign materials
405 
406  $ilTabs->activateTab($a_activate);
407  }
408 
409  public function setOfflineMode(string $a_file_path): void
410  {
411  $this->offline_mode = $a_file_path;
412  }
413 
414  public function getOfflineMode(): string
415  {
416  return $this->offline_mode;
417  }
418 
419  protected function render(): void
420  {
421  if ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles)) {
422  $this->listSkills();
423  } else {
424  $this->listAllAssignedProfiles();
425  }
426  }
427 
428  public function listSkills(): void
429  {
430  $ilCtrl = $this->ctrl;
431  $ilUser = $this->user;
432  $lng = $this->lng;
433  $main_tpl = $this->tpl;
434  $ilToolbar = $this->toolbar;
435 
436  $tpl = new ilTemplate("tpl.skill_filter.html", true, true, "Services/Skill");
437 
438  $this->setTabs("list_skills");
439 
440  // skill selection / add new personal skill
441  $ilToolbar->addFormButton(
442  $lng->txt("skmg_add_skill"),
443  "listSkillsForAdd"
444  );
445  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
446 
447  $filter_toolbar = new ilToolbarGUI();
448  $filter_toolbar->setFormAction($ilCtrl->getFormAction($this));
449  $this->getFilter()->addToToolbar($filter_toolbar, false);
450 
451  $skills = $this->personal_manager->getSelectedUserSkills($ilUser->getId());
452  $html = "";
453  foreach ($skills as $s) {
454  $path = $this->tree_service->getSkillTreePath($s->getSkillNodeId());
455 
456  // check draft
457  foreach ($path as $p) {
458  if ($p["status"] == ilSkillTreeNode::STATUS_DRAFT) {
459  continue(2);
460  }
461  }
462  $html .= $this->getSkillHTML($s->getSkillNodeId(), 0, true);
463  }
464 
465  // list skills
466 
467  if ($html != "") {
468  $filter_toolbar->addFormButton($this->lng->txt("skmg_refresh_view"), "applyFilter");
469  $tpl->setVariable("FILTER", $filter_toolbar->getHTML());
470  $html = $tpl->get() . $html;
471  } else {
472  $box = $this->ui_fac->messageBox()->info($lng->txt("skmg_no_skills_selected_info"));
473  $html = $this->ui_ren->render($box);
474  }
475 
476  $main_tpl->setContent($html);
477  }
478 
479  protected function applyFilter(): void
480  {
481  $this->getFilter()->save();
482  $this->ctrl->setParameter($this, "list_mode", self::LIST_SELECTED);
483  $this->ctrl->redirect($this, "listSkills");
484  }
485 
489  protected function applyFilterAssignedProfiles(): void
490  {
491  $this->getFilter()->save();
492  $this->ctrl->redirect($this, "listAssignedProfile");
493  }
494 
495 
504  public function getSkillHTML(
505  int $a_top_skill_id,
506  int $a_user_id = 0,
507  bool $a_edit = false,
508  int $a_tref_id = 0
509  ): string {
510  $main_tpl = $this->tpl;
511 
512  // user interface plugin slot + default rendering
513  $uip = new ilUIHookProcessor(
514  "Services/Skill",
515  "personal_skill_html",
516  array("personal_skills_gui" => $this, "top_skill_id" => $a_top_skill_id, "user_id" => $a_user_id,
517  "edit" => $a_edit, "tref_id" => $a_tref_id)
518  );
519  $skill_html = "";
520  if (!$uip->replaced()) {
521  $skill_html = $this->renderSkillHTML($a_top_skill_id, $a_user_id, $a_edit, $a_tref_id);
522  }
523  $skill_html = $uip->getHTML($skill_html);
524  $main_tpl->addJavaScript("./Services/Skill/js/SkillEntries.js");
525 
526  return $skill_html;
527  }
528 
529  public function renderSkillHTML(
530  int $a_top_skill_id,
531  int $a_user_id = 0,
532  bool $a_edit = false,
533  int $a_tref_id = 0
534  ): string {
535  $ilCtrl = $this->ctrl;
536  $ilUser = $this->user;
537  $lng = $this->lng;
538 
539  $sub_panels = [];
540 
541  if ($a_user_id == 0) {
542  $user = $ilUser;
543  } else {
544  $user = new ilObjUser($a_user_id);
545  }
546 
547  $tpl = new ilTemplate("tpl.skill_pres.html", true, true, "Services/Skill");
548 
549  $vtree = $this->tree_repo->getVirtualTreeForNodeId($a_top_skill_id);
550  $tref_id = $a_tref_id;
551  $skill_id = $a_top_skill_id;
552  if (ilSkillTreeNode::_lookupType($a_top_skill_id) == "sktr") {
553  $tref_id = $a_top_skill_id;
554  $skill_id = ilSkillTemplateReference::_lookupTemplateId($a_top_skill_id);
555  }
556  $b_skills = $vtree->getSubTreeForCSkillId($skill_id . ":" . $tref_id, true);
557 
558  foreach ($b_skills as $bs) {
559  $bs["id"] = (int) $bs["skill_id"];
560  $bs["tref"] = (int) $bs["tref_id"];
561 
562  $path = $this->tree_service->getSkillTreePath($bs["id"], $bs["tref"]);
563 
564  $panel_comps = [];
565 
566 
567  // check draft
568  foreach ($path as $p) {
569  if ($p["status"] == ilSkillTreeNode::STATUS_DRAFT) {
570  continue(2);
571  }
572  }
573  reset($path);
574 
575  $skill = ilSkillTreeNodeFactory::getInstance($bs["id"]);
576  $level_data = $skill->getLevelData();
577 
578 
579  $title = $sep = "";
580  $description = "";
581  $found = false;
582  foreach ($path as $p) {
583  if ($found) {
584  $title .= $sep . $p["title"];
585  $sep = " > ";
586  $description = $p["description"];
587  }
588  if ($a_top_skill_id == $p["child"]) {
589  $found = true;
590  }
591  }
592  if (empty($title)) {
593  $title = $lng->txt("skmg_skill_overview");
594  }
595 
596  // skill description
597  $panel_comps[] = $this->ui_fac->legacy($this->getBasicSkillDescription((string) $description));
598 
599 
600  // skill level description
601  $skl_lvl_desc = $this->getSkillLevelDescription($skill);
602  if (!empty($skl_lvl_desc)) {
603  $acc = new ilAccordionGUI();
604  $acc->setBehaviour(ilAccordionGUI::ALL_CLOSED);
605  $acc->addItem($lng->txt('skmg_skill_levels'), $skl_lvl_desc);
606  $panel_comps[] = $this->ui_fac->legacy($acc->getHTML());
607  }
608 
609  $prof_comp_head_rendered = false;
610  $has_at_least_one_entry = false;
611  if ($this->getProfileId() > 0) {
612  if ($this->getNonHistoricGapModeView()) {
613  if (!empty($self_eval_gap_item_prof = $this->getSelfEvalGapItem($level_data, $bs["tref"]))) {
614  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_SELF));
615  $has_at_least_one_entry = true;
616  }
617  $panel_comps[] = $this->ui_fac->legacy($self_eval_gap_item_prof);
618  } else {
619  // get all self eval entries and render them
620  $self_eval_entries_latest = $this->getLatestEntriesForSkillHTML(
621  $a_top_skill_id,
622  $bs,
623  $skill,
624  $user,
626  $level_data
627  );
628  $self_eval_entries_non_latest = $this->getNonLatestEntriesForSkillHTML(
629  $a_top_skill_id,
630  $bs,
631  $skill,
632  $user,
634  $level_data
635  );
636 
637  if (!empty($self_eval_entries_latest)) {
638  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_SELF));
639  $has_at_least_one_entry = true;
640  }
641  $panel_comps[] = $this->ui_fac->legacy($self_eval_entries_latest);
642  $panel_comps[] = $this->ui_fac->legacy($self_eval_entries_non_latest);
643  }
644 
645  if (!$this->skmg_settings->getHideProfileBeforeSelfEval() ||
646  ilBasicSkill::hasSelfEvaluated($user->getId(), $bs["id"], $bs["tref"])) {
647  if ($this->getFilter()->showTargetLevel()) {
648  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_OTHERS));
649  $prof_comp_head_rendered = true;
650  $panel_comps[] = $this->ui_fac->legacy($this->getProfileTargetItem($this->getProfileId(), $level_data, $bs["tref"]));
651  }
652  }
653  }
654 
655  if ($this->getNonHistoricGapModeView()) {
656  if (!empty($actual_gap_item = $this->getActualGapItem($level_data, $bs["tref"]))) {
657  $panel_comps[] = $this->ui_fac->legacy($actual_gap_item);
658  $has_at_least_one_entry = true;
659  }
660  if ($this->getProfileId() == 0) {
661  if (!empty($self_eval_gap_item_non_prof = $this->getSelfEvalGapItem($level_data, $bs["tref"]))) {
662  $panel_comps[] = $this->ui_fac->legacy($self_eval_gap_item_non_prof);
663  $has_at_least_one_entry = true;
664  }
665  }
666  } else {
667  if ($this->getProfileId() > 0) {
668  // get all non-self eval entries and render them
669  $object_entries_latest = $this->getLatestEntriesForSkillHTML(
670  $a_top_skill_id,
671  $bs,
672  $skill,
673  $user,
675  $level_data
676  );
677  $object_entries_non_latest = $this->getNonLatestEntriesForSkillHTML(
678  $a_top_skill_id,
679  $bs,
680  $skill,
681  $user,
683  $level_data
684  );
685 
686  if (!empty($object_entries_latest) && !$prof_comp_head_rendered) {
687  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_OTHERS));
688  }
689  if (!empty($object_entries_latest)) {
690  $has_at_least_one_entry = true;
691  }
692  $panel_comps[] = $this->ui_fac->legacy($object_entries_latest);
693  $panel_comps[] = $this->ui_fac->legacy($object_entries_non_latest);
694  } else {
695  // get all skill entries and render them
696  $all_entries_latest = $this->getLatestEntriesForSkillHTML(
697  $a_top_skill_id,
698  $bs,
699  $skill,
700  $user,
702  $level_data
703  );
704  $all_entries_non_latest = $this->getNonLatestEntriesForSkillHTML(
705  $a_top_skill_id,
706  $bs,
707  $skill,
708  $user,
710  $level_data
711  );
712 
713  if (!empty($all_entries_latest) && !$prof_comp_head_rendered) {
714  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_OTHERS));
715  }
716  if (!empty($all_entries_latest)) {
717  $has_at_least_one_entry = true;
718  }
719  $panel_comps[] = $this->ui_fac->legacy($all_entries_latest);
720  $panel_comps[] = $this->ui_fac->legacy($all_entries_non_latest);
721  }
722  }
723 
724  if (!$has_at_least_one_entry) {
725  $panel_comps[] = $this->ui_fac->legacy("<br/>" . $lng->txt("skmg_no_skill_entries"));
726  }
727 
728  // suggested resources
729 
730  $sub = $this->ui_fac->panel()->sub($title, $panel_comps);
731  if ($this->getFilter()->showMaterialsRessources() && $this->getProfileId() > 0
732  && $res = $this->getSuggestedResourcesForProfile($level_data, $bs["id"], $bs["tref"], $this->gap_mode_obj_id)) {
733  $sub = $sub->withFurtherInformation($res);
734  } elseif ($this->getFilter()->showMaterialsRessources() && $this->getProfileId() == 0 && !$this->gap_mode_obj_id) {
735  // no profile, just list all resources and only in global view
736  $sugg = $this->getAllSuggestedResources($bs["id"], $bs["tref"]);
737  if ($sugg) {
738  $sub = $sub->withFurtherInformation($sugg);
739  }
740  }
741  if ($a_edit) {
742  $actions = [];
743  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "skill_id", $a_top_skill_id);
744  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "tref_id", $bs["tref"]);
745  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "basic_skill_id", $bs["id"]);
746  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "list_mode", $this->requested_list_mode);
747  if ($this->use_materials) {
748  $actions[] = $this->ui_fac->button()->shy(
749  $lng->txt('skmg_assign_materials'),
750  $ilCtrl->getLinkTargetByClass("ilpersonalskillsgui", "assignMaterials")
751  );
752  }
753  $actions[] = $this->ui_fac->button()->shy(
754  $lng->txt('skmg_self_evaluation'),
755  $ilCtrl->getLinkTargetByClass("ilpersonalskillsgui", "selfEvaluation")
756  );
757  $sub = $sub->withActions($this->ui_fac->dropdown()->standard($actions)->withLabel($lng->txt("actions")));
758  }
759 
760  $sub_panels[] = $sub;
761 
762  // materials
763  if ($this->mode != "gap" && $this->getFilter()->showMaterialsRessources() && $this->use_materials) {
764  $mat = $this->getMaterials($level_data, $bs["tref"], $user->getId());
765  if ($mat) {
766  $sub_panels[] = $mat;
767  }
768  }
769 
770  $tpl->parseCurrentBlock();
771  }
772 
773  $des = $this->getSkillCategoryDescription($skill_id, $tref_id);
774 
775  //put the description of the skill category to the very top of the sub panels
776  $sub_panels = $this->ui_fac->legacy($des . $this->ui_ren->render($sub_panels));
777 
778  $panel = $this->ui_fac->panel()->standard(
779  ilSkillTreeNode::_lookupTitle($skill_id, $tref_id),
780  $sub_panels
781  );
782 
783  if ($a_edit && $this->getProfileId() == 0) {
784  $actions = [];
785 
786  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "skill_id", $a_top_skill_id);
787  $actions[] = $this->ui_fac->button()->shy(
788  $lng->txt('skmg_remove_skill'),
789  $ilCtrl->getLinkTargetByClass("ilpersonalskillsgui", "confirmSkillRemove")
790  );
791 
792  $panel = $panel->withActions($this->ui_fac->dropdown()->standard($actions)->withLabel($lng->txt("actions")));
793  }
794 
795  return $this->ui_ren->render($panel);
796  }
797 
798 
802  public function getMaterialInfo(int $a_wsp_id, int $a_user_id): array
803  {
804  $ws_tree = new ilWorkspaceTree($a_user_id);
805  $ws_access = new ilWorkspaceAccessHandler();
806 
807  $obj_id = $ws_tree->lookupObjectId($a_wsp_id);
808  $caption = ilObject::_lookupTitle($obj_id);
809 
810  if (!$this->getOfflineMode()) {
811  $url = $ws_access->getGotoLink($a_wsp_id, $obj_id);
812  } else {
813  $url = $this->getOfflineMode() . "file_" . $obj_id . "/";
814 
815  // all possible material types for now
816  switch (ilObject::_lookupType($obj_id)) {
817  case "tstv":
818  $obj = new ilObjTestVerification($obj_id, false);
819  $url .= $obj->getOfflineFilename();
820  break;
821 
822  case "excv":
823  $obj = new ilObjExerciseVerification($obj_id, false);
824  $url .= $obj->getOfflineFilename();
825  break;
826 
827  case "crsv":
828  $obj = new ilObjCourseVerification($obj_id, false);
829  $url .= $obj->getOfflineFilename();
830  break;
831 
832  case "cmxv":
833  $obj = new ilObjCmiXapiVerification($obj_id, false);
834  $url .= $obj->getOfflineFilename();
835  break;
836 
837  case "ltiv":
838  $obj = new ilObjLTIConsumerVerification($obj_id, false);
839  $url .= $obj->getOfflineFilename();
840  break;
841 
842  case "scov":
843  $obj = new ilObjSCORMVerification($obj_id, false);
844  $url .= $obj->getOfflineFilename();
845  break;
846 
847  case "file":
848  $file = new ilObjFile($obj_id, false);
849  $url .= $file->getFileName();
850  break;
851  }
852  }
853 
854  return array($caption, $url, $obj_id);
855  }
856 
857  public function addSkill(): void
858  {
859  $ilCtrl = $this->ctrl;
860  $ilUser = $this->user;
861  $lng = $this->lng;
862 
863  $this->personal_manager->addPersonalSkill($ilUser->getId(), $this->requested_node_id);
864 
865  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_object_modified"));
866  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
867  $ilCtrl->redirect($this, "listSkills");
868  }
869 
870  public function confirmSkillRemove(): void
871  {
872  $lng = $this->lng;
873  $tpl = $this->tpl;
874  $ilCtrl = $this->ctrl;
875 
876  if ($this->requested_skill_id > 0) {
877  $this->requested_skill_ids[] = $this->requested_skill_id;
878  }
879  if (empty($this->requested_skill_ids)) {
880  $this->tpl->setOnScreenMessage('info', $lng->txt("no_checkbox"), true);
881  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
882  $ilCtrl->redirect($this, "listSkills");
883  } else {
884  $cgui = new ilConfirmationGUI();
885  $cgui->setFormAction($ilCtrl->getFormAction($this));
886  $cgui->setHeaderText($lng->txt("skmg_really_remove_skills"));
887  $cgui->setCancel($lng->txt("cancel"), "listSkills");
888  $cgui->setConfirm($lng->txt("remove"), "removeSkills");
889 
890  foreach ($this->requested_skill_ids as $i) {
891  $cgui->addItem("id[]", (string) $i, ilSkillTreeNode::_lookupTitle($i));
892  }
893 
894  $tpl->setContent($cgui->getHTML());
895  }
896  }
897 
898  public function removeSkills(): void
899  {
900  $ilCtrl = $this->ctrl;
901  $ilUser = $this->user;
902  $lng = $this->lng;
903 
904  if (!empty($this->requested_skill_ids)) {
905  foreach ($this->requested_skill_ids as $n_id) {
906  $this->personal_manager->removePersonalSkill($ilUser->getId(), $n_id);
907  }
908  }
909 
910  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_object_modified"));
911  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
912  $ilCtrl->redirect($this, "listSkills");
913  }
914 
915 
916  //
917  // Materials assignments
918  //
919 
923  public function assignMaterials(): void
924  {
925  $ilCtrl = $this->ctrl;
926  $lng = $this->lng;
927  $tpl = $this->tpl;
928  $ilToolbar = $this->toolbar;
929  $ilTabs = $this->tabs;
930 
931  $cmd = ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles))
932  ? "render"
933  : "listAssignedProfile";
934  $ilTabs->setBackTarget(
935  $lng->txt("back"),
936  $ilCtrl->getLinkTarget($this, $cmd)
937  );
938 
939  $ilCtrl->saveParameter($this, "skill_id");
940  $ilCtrl->saveParameter($this, "basic_skill_id");
941  $ilCtrl->saveParameter($this, "tref_id");
942 
943  $tpl->setTitle(ilSkillTreeNode::_lookupTitle($this->requested_skill_id));
944  $tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_" .
945  ilSkillTreeNode::_lookupType($this->requested_skill_id) .
946  ".svg"));
947 
948  // basic skill selection
949  $vtree = $this->tree_repo->getVirtualTreeForNodeId($this->requested_skill_id);
950  $tref_id = 0;
951  $skill_id = $this->requested_skill_id;
952  if (ilSkillTreeNode::_lookupType($this->requested_skill_id) == "sktr") {
953  $tref_id = $this->requested_skill_id;
954  $skill_id = ilSkillTemplateReference::_lookupTemplateId($this->requested_skill_id);
955  }
956  $bs = $vtree->getSubTreeForCSkillId($skill_id . ":" . $tref_id, true);
957 
958  $options = [];
959  foreach ($bs as $b) {
960  $options[$b["skill_id"]] = ilSkillTreeNode::_lookupTitle((int) $b["skill_id"]);
961  }
962 
963  $cur_basic_skill_id = ($this->requested_basic_skill_id > 0)
964  ? $this->requested_basic_skill_id
965  : key($options);
966 
967  $ilCtrl->setParameter($this, "basic_skill_id", $cur_basic_skill_id);
968 
969  if (count($options) > 1) {
970  $si = new ilSelectInputGUI($lng->txt("skmg_skill"), "basic_skill_id");
971  $si->setOptions($options);
972  $si->setValue($cur_basic_skill_id);
973  $ilToolbar->addInputItem($si, true);
974  $ilToolbar->addFormButton(
975  $lng->txt("select"),
976  "assignMaterials"
977  );
978 
979  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
980  }
981 
982  $table = $this->table_manager->getAssignMaterialsTable(
983  $this->requested_skill_id,
984  $this->requested_tref_id,
985  $cur_basic_skill_id
986  )->getComponent();
987 
988  $tpl->setContent($this->ui_ren->render($table));
989  }
990 
991 
995  public function assignMaterial(): void
996  {
997  $ilCtrl = $this->ctrl;
998  $ilUser = $this->user;
999  $lng = $this->lng;
1000  $tpl = $this->tpl;
1001  $ilTabs = $this->tabs;
1003  $ui = $this->ui;
1004 
1005  $message = "";
1006  if (!$ilSetting->get("disable_personal_workspace")) {
1007  $url = 'ilias.php?baseClass=ilDashboardGUI&amp;cmd=jumpToWorkspace';
1008  $mbox = $ui->factory()->messageBox()->info($lng->txt("skmg_ass_materials_from_workspace"))
1009  ->withLinks([$ui->factory()->link()->standard(
1010  $lng->txt("personal_resources"),
1011  $url
1012  )]);
1013  $message = $ui->renderer()->render($mbox);
1014  }
1015 
1016  if ($this->requested_table_assign_materials_action === "assignMaterials"
1017  && !empty($this->requested_table_assign_materials_level_ids)) {
1018  $ilCtrl->setParameter($this, "level_id", $this->requested_table_assign_materials_level_ids[0]);
1019  }
1020  $ilCtrl->saveParameter($this, "skill_id");
1021  $ilCtrl->saveParameter($this, "level_id");
1022  $ilCtrl->saveParameter($this, "tref_id");
1023  $ilCtrl->saveParameter($this, "basic_skill_id");
1024 
1025  $ilTabs->setBackTarget(
1026  $lng->txt("back"),
1027  $ilCtrl->getLinkTarget($this, "assignMaterials")
1028  );
1029 
1030 
1031  $exp = new ilWorkspaceExplorerGUI($ilUser->getId(), $this, "assignMaterial", $this, "");
1032  $exp->setTypeWhiteList(array("blog", "wsrt", "wfld", "file", "tstv", "excv"));
1033  $exp->setSelectableTypes(array("file", "tstv", "excv"));
1034  $exp->setSelectMode("wsp_ids", true);
1035  if ($exp->handleCommand()) {
1036  return;
1037  }
1038 
1039  // fill template
1040  $mtpl = new ilTemplate("tpl.materials_selection.html", true, true, "Services/Skill");
1041  $mtpl->setVariable("EXP", $exp->getHTML());
1042 
1043  // toolbars
1044  $tb = new ilToolbarGUI();
1045  $tb->addFormButton(
1046  $lng->txt("select"),
1047  "selectMaterial"
1048  );
1049  $tb->setFormAction($ilCtrl->getFormAction($this));
1050  $tb->setOpenFormTag(true);
1051  $tb->setCloseFormTag(false);
1052  $mtpl->setVariable("TOOLBAR1", $tb->getHTML());
1053  $tb->setOpenFormTag(false);
1054  $tb->setCloseFormTag(true);
1055  $mtpl->setVariable("TOOLBAR2", $tb->getHTML());
1056 
1057  $tpl->setContent($message . $mtpl->get());
1058  }
1059 
1060  public function selectMaterial(): void
1061  {
1062  $ilCtrl = $this->ctrl;
1063  $ilUser = $this->user;
1064  $lng = $this->lng;
1065 
1066 
1067  if (!empty($this->requested_wsp_ids)) {
1068  foreach ($this->requested_wsp_ids as $w) {
1069  $this->assigned_material_manager->assignMaterial(
1070  $ilUser->getId(),
1075  $w
1076  );
1077  }
1078  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_obj_modified"), true);
1079  }
1080 
1081  $ilCtrl->saveParameter($this, "skill_id");
1082  $ilCtrl->saveParameter($this, "level_id");
1083  $ilCtrl->saveParameter($this, "tref_id");
1084  $ilCtrl->saveParameter($this, "basic_skill_id");
1085 
1086  $ilCtrl->redirect($this, "assignMaterials");
1087  }
1088 
1089  public function removeMaterial(): void
1090  {
1091  $ilCtrl = $this->ctrl;
1092  $ilUser = $this->user;
1093  $lng = $this->lng;
1094 
1095  if ($this->requested_table_assign_materials_action === "removeMaterial"
1096  && !empty($this->requested_table_assign_materials_level_ids)
1097  && $this->requested_table_assign_materials_wsp_id !== 0) {
1098  $this->assigned_material_manager->removeAssignedMaterial(
1099  $ilUser->getId(),
1101  (int) $this->requested_table_assign_materials_level_ids[0],
1102  $this->requested_table_assign_materials_wsp_id
1103  );
1104  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_obj_modified"), true);
1105  }
1106  $ilCtrl->redirect($this, "assignMaterials");
1107  }
1108 
1109 
1110  //
1111  // Self evaluation
1112  //
1113 
1114  public function selfEvaluation(): void
1115  {
1116  $ilCtrl = $this->ctrl;
1117  $lng = $this->lng;
1118  $tpl = $this->tpl;
1119  $ilToolbar = $this->toolbar;
1120  $ilTabs = $this->tabs;
1121 
1122  $cmd = ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles))
1123  ? "render"
1124  : "listAssignedProfile";
1125  $ilTabs->setBackTarget(
1126  $lng->txt("back"),
1127  $ilCtrl->getLinkTarget($this, $cmd)
1128  );
1129 
1130  $ilCtrl->saveParameter($this, "skill_id");
1131  $ilCtrl->saveParameter($this, "basic_skill_id");
1132  $ilCtrl->saveParameter($this, "tref_id");
1133 
1134  $tpl->setTitle(ilSkillTreeNode::_lookupTitle($this->requested_skill_id));
1135  $tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_" .
1136  ilSkillTreeNode::_lookupType($this->requested_skill_id) .
1137  ".svg"));
1138 
1139  // basic skill selection
1140  $vtree = $this->tree_repo->getVirtualTreeForNodeId($this->requested_skill_id);
1141  $tref_id = 0;
1142  $skill_id = $this->requested_skill_id;
1143  if (ilSkillTreeNode::_lookupType($this->requested_skill_id) == "sktr") {
1144  $tref_id = $this->requested_skill_id;
1145  $skill_id = ilSkillTemplateReference::_lookupTemplateId($this->requested_skill_id);
1146  }
1147  $bs = $vtree->getSubTreeForCSkillId($skill_id . ":" . $tref_id, true);
1148 
1149 
1150  $options = [];
1151  foreach ($bs as $b) {
1152  $options[$b["skill_id"]] = ilSkillTreeNode::_lookupTitle((int) $b["skill_id"]);
1153  }
1154 
1155  $cur_basic_skill_id = ($this->requested_basic_skill_id > 0)
1156  ? $this->requested_basic_skill_id
1157  : key($options);
1158 
1159  $ilCtrl->setParameter($this, "basic_skill_id", $cur_basic_skill_id);
1160 
1161  if (count($options) > 1) {
1162  $si = new ilSelectInputGUI($lng->txt("skmg_skill"), "basic_skill_id");
1163  $si->setOptions($options);
1164  $si->setValue($cur_basic_skill_id);
1165  $ilToolbar->addInputItem($si, true);
1166  $ilToolbar->addFormButton(
1167  $lng->txt("select"),
1168  "selfEvaluation"
1169  );
1170 
1171  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
1172  }
1173 
1174  $form = $this->getSelfEvaluationForm($cur_basic_skill_id);
1175  $tpl->setContent($this->ui_ren->render($form));
1176  }
1177 
1178  protected function getSelfEvaluationForm(int $cur_basic_skill_id): Form
1179  {
1180  $top_skill_id = $this->requested_skill_id;
1181  $tref_id = $this->requested_tref_id;
1182  $basic_skill_id = $cur_basic_skill_id;
1183 
1184  $self_eval = $this->ui_fac->input()->field()->radio($this->lng->txt("skmg_self_evaluation"))
1185  ->withRequired(true);
1186 
1187  $current_level_id = $this->self_evaluation_manager->getSelfEvaluation(
1188  $this->user->getId(),
1189  $top_skill_id,
1190  $tref_id,
1191  $basic_skill_id
1192  );
1193  $skill = \ilSkillTreeNodeFactory::getInstance($basic_skill_id);
1194  foreach ($skill->getLevelData() as $level) {
1195  $self_eval = $self_eval->withOption((string) $level["id"], $level["title"], $level["description"]);
1196  if ($current_level_id == $level["id"]) {
1197  $self_eval = $self_eval->withValue($level["id"]);
1198  }
1199  }
1200 
1201  $tree_id = $this->tree_repo->getTreeIdForNodeId($basic_skill_id);
1202  $node_manager = $this->internal_manager->getTreeNodeManager($tree_id);
1203  $section_title = $node_manager->getWrittenPath($basic_skill_id);
1204  $section_inputs = ["self_eval" => $self_eval];
1205  $section = $this->ui_fac->input()->field()->section(
1206  $section_inputs,
1207  $section_title
1208  );
1209 
1210  $form_action = $this->ctrl->getFormAction($this, "saveSelfEvaluation");
1211  return $this->ui_fac->input()->container()->form()->standard($form_action, ["section" => $section]);
1212  }
1213 
1214  public function saveSelfEvaluation(): void
1215  {
1216  $ilCtrl = $this->ctrl;
1217  $ilUser = $this->user;
1218  $lng = $this->lng;
1219 
1220  $ilCtrl->setParameter($this, "basic_skill_id", $this->requested_basic_skill_id);
1221  $form = $this->getSelfEvaluationForm($this->requested_basic_skill_id);
1222  $ilCtrl->clearParameterByClass("ilpersonalskillsgui", "basic_skill_id");
1223  $cmd = ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles))
1224  ? "render" : "listAssignedProfile";
1225 
1226  if ($this->request->getMethod() === "POST") {
1227  $form = $form->withRequest($this->request);
1228  $data = $form->getData();
1229  if (isset($data["section"]) && is_array($data["section"]) && !empty($data["section"]["self_eval"])) {
1230  $this->self_evaluation_manager->saveSelfEvaluation(
1231  $ilUser->getId(),
1235  (int) $data["section"]["self_eval"]
1236  );
1237  $this->tpl->setOnScreenMessage("success", $lng->txt("msg_obj_modified"), true);
1238  } else {
1239  $this->tpl->setContent($this->ui_ren->render($form));
1240  $this->tpl->setTitle(ilSkillTreeNode::_lookupTitle($this->requested_skill_id));
1241  $this->tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_" .
1242  ilSkillTreeNode::_lookupType($this->requested_skill_id) .
1243  ".svg"));
1244  $this->tabs->clearTargets();
1245  $this->tabs->setBackTarget(
1246  $lng->txt("back"),
1247  $ilCtrl->getLinkTarget($this, $cmd)
1248  );
1249  return;
1250  }
1251  }
1252 
1253  $ilCtrl->redirect($this, $cmd);
1254  }
1255 
1256  public function listSkillsForAdd(): void
1257  {
1258  $ilCtrl = $this->ctrl;
1259  $lng = $this->lng;
1260  $tpl = $this->tpl;
1261  $ilTabs = $this->tabs;
1262 
1263 
1264  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
1265  $ilTabs->setBackTarget(
1266  $lng->txt("back"),
1267  $ilCtrl->getLinkTarget($this, "render")
1268  );
1269  $ilCtrl->clearParameterByClass(get_class($this), "list_mode");
1270 
1271  $exp = new ilPersonalSkillExplorerGUI($this, "listSkillsForAdd", $this, "addSkill");
1272  if ($exp->getHasSelectableNodes()) {
1273  if (!$exp->handleCommand()) {
1274  $tpl->setContent($exp->getHTML());
1275  }
1276  $this->tpl->setOnScreenMessage('info', $lng->txt("skmg_select_skill"));
1277  } else {
1278  $this->tpl->setOnScreenMessage('info', $lng->txt("skmg_no_nodes_selectable"));
1279  }
1280  }
1281 
1282  public function showProfiles(): void
1283  {
1284  $this->ctrl->redirectByClass("ilContSkillPresentationGUI", "showProfiles");
1285  }
1286 
1287  public function listAllProfilesForGap(): void
1288  {
1289  if (empty($this->cont_profiles)) {
1290  $this->tpl->setContent($this->showInfoBoxForProfiles());
1291  return;
1292  }
1293 
1294  $prof_list = $this->getProfilesListed($this->cont_profiles, true);
1295 
1296  $html = $this->showInfoBoxForProfiles() . $this->ui_ren->render($prof_list);
1297  $this->tpl->setContent($html);
1298  }
1299 
1300  public function listProfileForGap(): void
1301  {
1302  // needed fix for profiles in gap view, because there is no filter shown (yet)
1303  $this->getFilter()->clear();
1304  $this->tabs->clearTargets();
1305  $this->tabs->setBackTarget(
1306  $this->lng->txt("back"),
1307  $this->ctrl->getLinkTarget($this, "showProfiles")
1308  );
1309  $this->setProfileId($this->requested_profile_id);
1310  $this->tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_skmg.svg"));
1311  $this->tpl->setTitle($this->profile_manager->lookupTitle($this->getProfileId()));
1312 
1313  $this->tpl->setContent($this->getGapAnalysisHTML());
1314  }
1315 
1316  public function listRecordsForGap(): void
1317  {
1318  if (empty($this->getObjectSkills())) {
1319  $this->tpl->setContent($this->showInfoBoxForRecords());
1320  return;
1321  }
1322 
1323  $this->tpl->setContent($this->getGapAnalysisHTML());
1324  }
1325 
1329  protected function getProfilesListed(array $profiles, bool $gap_mode = false): ILIAS\UI\Component\Panel\Listing\Listing
1330  {
1331  $prof_items = [];
1332 
1333  foreach ($profiles as $p) {
1334  $image_id = $p->getImageId();
1335  if ($image_id) {
1336  $identification = $this->storage->manage()->find($image_id);
1337  $src = $this->storage->consume()->src($identification);
1338  $image = $this->ui_fac->image()->responsive($src->getSrc(), $this->lng->txt("skmg_custom_image_alt"));
1339  } else {
1340  $image = $this->ui_fac->image()->responsive(
1341  "./templates/default/images/logo/ilias_logo_72x72.png",
1342  "ILIAS"
1343  );
1344  }
1345 
1346  $this->ctrl->setParameter($this, "profile_id", $p->getId());
1347  $link = $this->ui_fac->link()->standard(
1348  $p->getTitle(),
1349  $this->ctrl->getLinkTarget($this, $gap_mode ? "listProfileForGap" : "listAssignedProfile")
1350  );
1351  $this->ctrl->setParameter($this, "profile_id", "");
1352 
1353  $chart_value = $this->profile_completion_manager->getProfileProgress($this->user->getId(), $p->getId());
1354  $prof_item = $this->ui_fac->item()->standard($link)
1355  ->withDescription($p->getDescription())
1356  ->withLeadImage($image)
1357  ->withProgress($this->ui_fac->chart()->progressMeter()->standard(100, $chart_value));
1358 
1359  $prof_items[] = $prof_item;
1360  }
1361 
1362  $prof_list = $this->ui_fac->panel()->listing()->standard("", array(
1363  $this->ui_fac->item()->group("", $prof_items)
1364  ));
1365 
1366  return $prof_list;
1367  }
1368 
1369  protected function showInfoBoxForProfiles(): string
1370  {
1371  if (!empty($this->cont_profiles)) {
1372  $link = $this->ui_fac->link()->standard(
1373  $this->lng->txt("skmg_open_all_assigned_profiles"),
1374  $this->ctrl->getLinkTargetByClass(["ilDashboardGUI", "ilAchievementsGUI", "ilPersonalSkillsGUI"])
1375  );
1376  $box = $this->ui_fac->messageBox()->info($this->lng->txt("skmg_cont_profiles_info"))->withLinks([$link]);
1377  } else {
1378  $box = $this->ui_fac->messageBox()->info($this->lng->txt("skmg_cont_profiles_info_empty"));
1379  }
1380 
1381  return $this->ui_ren->render($box);
1382  }
1383 
1384  protected function showInfoBoxForRecords(): string
1385  {
1386  $box = $this->ui_fac->messageBox()->info($this->lng->txt("skmg_cont_records_info_empty"));
1387 
1388  return $this->ui_ren->render($box);
1389  }
1390 
1391  public function setGapAnalysisActualStatusModePerType(string $a_type, string $a_cat_title = ""): void
1392  {
1393  $this->gap_mode = "max_per_type";
1394  $this->gap_mode_type = $a_type;
1395  $this->gap_cat_title = $a_cat_title;
1396  $this->mode = "gap";
1397  }
1398 
1399  public function setGapAnalysisActualStatusModePerObject(int $a_obj_id, string $a_cat_title = ""): void
1400  {
1401  $this->gap_mode = "max_per_object";
1402  $this->gap_mode_obj_id = $a_obj_id;
1403  $this->gap_cat_title = $a_cat_title;
1404  $this->mode = "gap";
1405  }
1406 
1407  public function getGapAnalysisHTML(int $a_user_id = 0, ?array $a_skills = null): string
1408  {
1409  $ilUser = $this->user;
1410  $lng = $this->lng;
1411 
1412  // needed fix for profiles in gap view, because there is no filter shown (yet)
1413  $this->getFilter()->clear();
1414 
1415  if ($a_skills == null) {
1416  foreach ($this->getObjectSkills() as $s) {
1417  $a_skills[] = array(
1418  "base_skill_id" => $s->getBaseSkillId(),
1419  "tref_id" => $s->getTrefId()
1420  );
1421  }
1422  }
1423 
1424  $intro_html = "";
1425  if ($this->getIntroText() != "") {
1426  $pan = ilPanelGUI::getInstance();
1427  $pan->setPanelStyle(ilPanelGUI::PANEL_STYLE_PRIMARY);
1428  $pan->setBody($this->getIntroText());
1429  $intro_html = $pan->getHTML();
1430  }
1431 
1432  // $this->setTabs("list_skills");
1433 
1434  if ($a_user_id == 0) {
1435  $user_id = $ilUser->getId();
1436  } else {
1437  $user_id = $a_user_id;
1438  }
1439 
1440  $skills = [];
1441  if ($this->getProfileId() > 0) {
1442  $this->profile_levels = $this->profile_manager->getSkillLevels($this->getProfileId());
1443  $skills = $this->profile_levels;
1444  } else {
1445  // order skills per virtual skill tree
1446  $vtree = $this->tree_service->getGlobalVirtualSkillTree();
1447  $a_skills = $vtree->getOrderedNodeset($a_skills, "base_skill_id", "tref_id");
1448 
1449  foreach ($a_skills as $s) {
1451  $skills[] = $this->cont_factory_service->containerSkill()->skill(
1452  (int) $s["base_skill_id"],
1453  (int) $s["tref_id"]
1454  );
1455  }
1456  }
1457 
1458  // get actual levels for gap analysis
1459  $this->actual_levels = $this->profile_completion_manager->getActualMaxLevels(
1460  $user_id,
1461  $skills,
1462  $this->gap_mode,
1463  $this->gap_mode_type,
1464  $this->gap_mode_obj_id
1465  );
1466  $this->next_level_fuls = $this->profile_completion_manager->getActualNextLevelFulfilments(
1467  $user_id,
1468  $skills,
1469  $this->gap_mode,
1470  $this->gap_mode_type,
1471  $this->gap_mode_obj_id
1472  );
1473 
1474  $bc_skills = [];
1475  $html = "";
1476  $not_all_self_evaluated = false;
1477 
1478  foreach ($skills as $s) {
1479  if ($this->skmg_settings->getHideProfileBeforeSelfEval() &&
1480  !ilBasicSkill::hasSelfEvaluated($this->user->getId(), $s->getBaseSkillId(), $s->getTrefId())) {
1481  $not_all_self_evaluated = true;
1482  }
1483 
1484  $path = $this->tree_service->getSkillTreePath($s->getBaseSkillId());
1485 
1486  // check draft
1487  foreach ($path as $p) {
1488  if ($p["status"] == ilSkillTreeNode::STATUS_DRAFT) {
1489  continue(2);
1490  }
1491  }
1492  $bc_skills[] = $s;
1493  $html .= $this->getSkillHTML($s->getBaseSkillId(), $user_id, false, $s->getTrefId());
1494  }
1495 
1496  if ($not_all_self_evaluated) {
1497  $box = $this->ui_fac->messageBox()->info($lng->txt("skmg_skill_needs_self_eval_box"));
1498  $html = $this->ui_ren->render($box) . $html;
1499  }
1500 
1501  // output bar charts
1502  $all_chart_html = $this->getBarChartHTML($bc_skills);
1503 
1504  if (!empty($all_chart_html)) {
1505  $pan = ilPanelGUI::getInstance();
1506  $pan->setPanelStyle(ilPanelGUI::PANEL_STYLE_PRIMARY);
1507  $pan->setBody($all_chart_html);
1508  $all_chart_html = $pan->getHTML();
1509  }
1510 
1511  // list skills
1512 
1513  return $intro_html . $all_chart_html . $html;
1514  }
1515 
1519  protected function getBarChartHTML(array $skills): string
1520  {
1521  $lng = $this->lng;
1522 
1523  // dimension names
1524  $target_dim = $lng->txt("skmg_target_level");
1525  $eval_dim = $lng->txt("skmg_eval_type_1");
1526  if ($this->gap_cat_title != "") {
1527  $eval_dim = $this->gap_cat_title;
1528  } elseif ($this->gap_mode == "max_per_type") {
1529  $eval_dim = $lng->txt("objs_" . $this->gap_mode_type);
1530  } elseif ($this->gap_mode == "max_per_object") {
1531  $eval_dim = ilObject::_lookupTitle($this->gap_mode_obj_id);
1532  }
1533  $self_eval_dim = $lng->txt("skmg_self_evaluation");
1534 
1535  $incl_self_eval = false;
1536  $self_vals = [];
1537  if (!empty($this->getGapAnalysisSelfEvalLevels())) {
1538  $incl_self_eval = true;
1539  $self_vals = $this->getGapAnalysisSelfEvalLevels();
1540  }
1541 
1542  $chart_counter = 0;
1543  $bar_counter = 0;
1544  $tmp_labels = [];
1545  $all_chart_data = [];
1546  $render_eval_dim = false;
1547  foreach ($skills as $l) {
1548  $bs = new ilBasicSkill($l->getBaseSkillId());
1549  $levels = $bs->getLevelData();
1550  // filter out skills with no levels from chart
1551  if (empty($levels)) {
1552  continue;
1553  }
1554 
1555  $cnt = 0;
1556  $points = [];
1557  $tooltips = [];
1558  $labels = [0 => ""];
1559  foreach ($levels as $lv) {
1560  // points and tooltips
1561  $cnt++;
1562  $labels[] = $lv["title"];
1563  if ($this->getProfileId() > 0) {
1564  if ($l->getLevelId() == $lv["id"]) {
1565  $points[$target_dim] = [$cnt - 0.01, $cnt];
1566  $tooltips[$target_dim] = $lv["title"];
1567  } else {
1568  $points[$target_dim] = $points[$target_dim] ?? null;
1569  $tooltips[$target_dim] = $tooltips[$target_dim] ?? null;
1570  }
1571  }
1572  if ($this->actual_levels[$l->getBaseSkillId()][$l->getTrefId()] == $lv["id"]) {
1573  $perc = $this->next_level_fuls[$l->getBaseSkillId()][$l->getTrefId()];
1574  $points[$eval_dim] = $cnt + $perc;
1575  $tooltips[$eval_dim] = null;
1576  if ($perc > 0) {
1577  $tooltips[$eval_dim] = $lv["title"] . " + " . $perc * 100 . "%";
1578  }
1579  $render_eval_dim = true;
1580  } else {
1581  $points[$eval_dim] = $points[$eval_dim] ?? null;
1582  $tooltips[$eval_dim] = $tooltips[$eval_dim] ?? null;
1583  if (!is_null($points[$eval_dim])) {
1584  $render_eval_dim = true;
1585  }
1586  }
1587  if ($incl_self_eval) {
1588  if (($self_vals[$l->getBaseSkillId()][$l->getTrefId()] ?? 0) == $lv["id"]) {
1589  $points[$self_eval_dim] = $cnt;
1590  $tooltips[$self_eval_dim] = null;
1591  } else {
1592  $points[$self_eval_dim] = $points[$self_eval_dim] ?? null;
1593  $tooltips[$self_eval_dim] = $tooltips[$self_eval_dim] ?? null;
1594  }
1595  }
1596  }
1597 
1598  // do not show eval dimension if there is no data for it
1599  if (!$render_eval_dim) {
1600  unset($points[$eval_dim]);
1601  unset($tooltips[$eval_dim]);
1602  }
1603 
1604  /*
1605  * create new chart when number and title of the levels of the current skill are not identical with
1606  * the previous skill
1607  */
1608  if (!empty($tmp_labels) && $tmp_labels !== $labels) {
1609  $chart_counter++;
1610  $bar_counter = 0;
1611  }
1612  $tmp_labels = $labels;
1613 
1614  $all_chart_data[$chart_counter][$bar_counter]["item_title"] = ilBasicSkill::_lookupTitle(
1615  $l->getBaseSkillId(),
1616  $l->getTrefId()
1617  );
1618  $all_chart_data[$chart_counter][$bar_counter]["levels"] = $labels;
1619  $all_chart_data[$chart_counter][$bar_counter]["points"] = $points;
1620  $all_chart_data[$chart_counter][$bar_counter]["tooltips"] = $tooltips;
1621 
1622  $bar_counter++;
1623  }
1624 
1625  $all_chart_html = "";
1626  foreach ($all_chart_data as $chart_data) {
1627  $c_dimension = $this->data_fac->dimension()->cardinal($chart_data[0]["levels"]);
1628  $r_dimension = $this->data_fac->dimension()->range($c_dimension);
1629 
1630  // dimensions and bar configs
1631  $ds = [];
1632  $bars = [];
1633 
1634  if ($this->getProfileId() > 0) {
1635  $target_bar = new BarConfig();
1636  $target_bar = $target_bar->withRelativeWidth(1.1);
1637  $target_bar = $target_bar->withColor($this->data_fac->color("#333333"));
1638  $ds[$target_dim] = $r_dimension;
1639  $bars[$target_dim] = $target_bar;
1640  }
1641 
1642  if ($render_eval_dim) {
1643  $eval_bar = new BarConfig();
1644  $eval_bar = $eval_bar->withRelativeWidth(0.5);
1645  $eval_bar = $eval_bar->withColor($this->data_fac->color("#307C88"));
1646  if (ilObject::_lookupType($this->gap_mode_obj_id) == "tst") {
1647  $eval_bar = $eval_bar->withColor($this->data_fac->color("#d38000"));
1648  }
1649  $ds[$eval_dim] = $c_dimension;
1650  $bars[$eval_dim] = $eval_bar;
1651  }
1652 
1653  if ($incl_self_eval) {
1654  $self_eval_bar = new BarConfig();
1655  $self_eval_bar = $self_eval_bar->withRelativeWidth(0.5);
1656  $self_eval_bar = $self_eval_bar->withColor($this->data_fac->color("#557b2e"));
1657  $ds[$self_eval_dim] = $c_dimension;
1658  $bars[$self_eval_dim] = $self_eval_bar;
1659  }
1660 
1661  $dataset = $this->data_fac->dataset($ds);
1662 
1663  $render_chart = false;
1664  foreach ($chart_data as $a) {
1665  if ($render_eval_dim && !isset($a["points"][$eval_dim])) {
1666  $a["points"][$eval_dim] = null;
1667  $a["tooltips"][$eval_dim] = null;
1668  }
1669  $dataset = $dataset->withPoint($a["item_title"], $a["points"]);
1670  $dataset = $dataset->withAlternativeInformation($a["item_title"], $a["tooltips"]);
1671  foreach ($a["points"] as $dim => $p) {
1672  // render chart only if there are bars
1673  if (!is_null($p) && $dim != $target_dim) {
1674  $render_chart = true;
1675  }
1676  }
1677  }
1678 
1679  if ($render_chart) {
1680  $bar_chart = $this->ui_fac->chart()->bar()->horizontal(
1681  "",
1682  $dataset,
1683  $bars
1684  );
1685 
1686  $x_axis = new XAxis();
1687  $x_axis = $x_axis->withMaxValue(count($chart_data[0]["levels"]) - 1);
1689  $bar_chart = $bar_chart->withCustomXAxis($x_axis);
1690  $bar_chart = $bar_chart->withTitleVisible(false);
1691 
1692  $all_chart_html .= $this->ui_ren->render($bar_chart);
1693  }
1694  }
1695 
1696  return $all_chart_html;
1697  }
1698 
1699  public function getMaterials(array $a_levels, int $a_tref_id = 0, int $a_user_id = 0): ?\ILIAS\UI\Component\Panel\Sub
1700  {
1701  $ilUser = $this->user;
1702  $lng = $this->lng;
1703 
1704  if ($a_user_id == 0) {
1705  $a_user_id = $ilUser->getId();
1706  }
1707 
1708  // only render, if materials given
1709  $got_mat = false;
1710  foreach ($a_levels as $v) {
1711  $mat_cnt = $this->assigned_material_manager->countAssignedMaterials(
1712  $a_user_id,
1713  $a_tref_id,
1714  (int) $v["id"]
1715  );
1716  if ($mat_cnt > 0) {
1717  $got_mat = true;
1718  }
1719  }
1720  if (!$got_mat) {
1721  return null;
1722  }
1723 
1724  $item_groups = [];
1725  foreach ($a_levels as $k => $v) {
1726  $got_mat = false;
1727  $items = [];
1728  foreach ($this->assigned_material_manager->getAssignedMaterials(
1729  $a_user_id,
1730  $a_tref_id,
1731  (int) $v["id"]
1732  ) as $item) {
1733  $mat_data = $this->getMaterialInfo($item->getWorkspaceId(), $a_user_id);
1734  $title = $mat_data[0];
1735  $icon = $this->ui_fac->symbol()->icon()->standard(
1736  ilObject::_lookupType($mat_data[2]),
1737  $lng->txt("icon") . " " . $lng->txt(ilObject::_lookupType($mat_data[2]))
1738  );
1739  $link = $this->ui_fac->link()->standard($title, $mat_data[1]);
1740  $items[] = $this->ui_fac->item()->standard($link)->withLeadIcon($icon);
1741  $got_mat = true;
1742  }
1743  if ($got_mat) {
1744  $item_groups[] = $this->ui_fac->item()->group($v["title"], $items);
1745  }
1746  }
1747  $mat_panel = $this->ui_fac->panel()->sub(
1748  $lng->txt("skmg_materials"),
1749  $item_groups
1750  );
1751 
1752  return $mat_panel;
1753  }
1754 
1755  public function getProfileTargetItem(int $a_profile_id, array $a_levels, int $a_tref_id = 0): string
1756  {
1757  $lng = $this->lng;
1758 
1759  $profile_levels = $this->profile_manager->getSkillLevels($a_profile_id);
1760 
1761  $a_activated_levels = [];
1762 
1763  foreach ($a_levels as $k => $v) {
1764  foreach ($profile_levels as $pl) {
1765  if ($pl->getLevelId() == $v["id"] &&
1766  $pl->getBaseSkillId() == $v["skill_id"] &&
1767  $a_tref_id == $pl->getTrefId()) {
1768  $a_activated_levels[] = $pl->getLevelId();
1769  }
1770  }
1771  }
1772 
1773  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "Services/Skill");
1774  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_activated_levels));
1775 
1776  $tpl->setVariable("TYPE", $lng->txt("skmg_target_level"));
1777  $tpl->setVariable("TITLE", "");
1778 
1779  return $tpl->get();
1780  }
1781 
1782  public function getActualGapItem(array $a_levels, int $a_tref_id = 0): string
1783  {
1784  $lng = $this->lng;
1785 
1786  $a_activated_levels = [];
1787  foreach ($a_levels as $k => $v) {
1788  if ($this->actual_levels[$v["skill_id"]][$a_tref_id] == $v["id"]) {
1789  $a_activated_levels[] = $v["id"];
1790  }
1791  }
1792 
1793  if (empty($a_activated_levels)) {
1794  return "";
1795  }
1796 
1797  $title = "";
1798  if ($this->gap_cat_title != "") {
1799  $title = $this->gap_cat_title;
1800  } elseif ($this->gap_mode == "max_per_type") {
1801  $title = $lng->txt("objs_" . $this->gap_mode_type);
1802  } elseif ($this->gap_mode == "max_per_object") {
1803  $title = ilObject::_lookupTitle($this->gap_mode_obj_id);
1804  }
1805 
1806  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "Services/Skill");
1807  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_activated_levels));
1808 
1809  $type = 1;
1810  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_latest_" . $type));
1811  if ($type > 0) {
1812  $tpl->touchBlock("st" . $type);
1813  $tpl->touchBlock("stb" . $type);
1814  }
1815 
1816  if ($title != $lng->txt("skmg_eval_type_" . $type)) {
1817  $tpl->setVariable("TITLE", $title);
1818  }
1819 
1820  return $tpl->get();
1821  }
1822 
1823  public function getSelfEvalGapItem(array $a_levels, int $a_tref_id = 0): string
1824  {
1825  $lng = $this->lng;
1826 
1827  $self_vals = $this->getGapAnalysisSelfEvalLevels();
1828  if (empty($self_vals)) {
1829  return "";
1830  }
1831 
1832  $a_activated_levels = [];
1833  foreach ($a_levels as $k => $v) {
1834  if (isset($self_vals[$v["skill_id"]][$a_tref_id]) &&
1835  $self_vals[$v["skill_id"]][$a_tref_id] == $v["id"]) {
1836  $a_activated_levels[] = $v["id"];
1837  }
1838  }
1839 
1840  if (empty($a_activated_levels)) {
1841  return "";
1842  }
1843 
1844  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "Services/Skill");
1845  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_activated_levels));
1846 
1847  $type = 3;
1848  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_latest_" . $type));
1849  if ($type > 0) {
1850  $tpl->touchBlock("st" . $type);
1851  $tpl->touchBlock("stb" . $type);
1852  }
1853 
1854  return $tpl->get();
1855  }
1856 
1862  public function getScaleBar(array $a_levels, $a_activated_levels): string
1863  {
1864  $vals = [];
1865 
1866  if (!is_array($a_activated_levels)) {
1867  $a_activated_levels = array($a_activated_levels);
1868  }
1869 
1870  foreach ($a_levels as $level) {
1871  $vals[$level["title"]] = (in_array($level["id"], $a_activated_levels));
1872  }
1873  $scale_bar = $this->ui_fac->chart()->scaleBar($vals);
1874 
1875  return $this->ui_ren->render($scale_bar);
1876  }
1877 
1878  public function getEvalItem(array $a_levels, array $a_level_entry, bool $is_latest = false): string
1879  {
1880  $lng = $this->lng;
1881  $ilAccess = $this->access;
1882 
1883  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "Services/Skill");
1884  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_level_entry["level_id"]));
1885 
1886  $type = Personal\SkillEval::TYPE_APPRAISAL;
1887 
1888  if ($a_level_entry["self_eval"] == 1) {
1889  $type = Personal\SkillEval::TYPE_SELF_EVAL;
1890  }
1891 
1892  if ($a_level_entry["trigger_obj_type"] == "tst") {
1893  $type = Personal\SkillEval::TYPE_MEASUREMENT;
1894  }
1895 
1897  $title = "";
1898  if ($a_level_entry["trigger_obj_id"] > 0) {
1899  if (ilObject::_exists($a_level_entry["trigger_ref_id"], true)) {
1900  $title = ilObject::_lookupTitle($a_level_entry["trigger_obj_id"]);
1901  } elseif (!empty($del_data = ilObjectDataDeletionLog::get($a_level_entry["trigger_obj_id"]))) {
1902  $title = $del_data["title"];
1903  } else {
1904  $title = ($a_level_entry["trigger_title"]) ?? "";
1905  }
1906  }
1907 
1908  if ($a_level_entry["trigger_ref_id"] > 0
1909  && $ilAccess->checkAccess("read", "", $a_level_entry["trigger_ref_id"])) {
1910  $title = "<a href='" . ilLink::_getLink($a_level_entry["trigger_ref_id"]) . "'>" . $title . "</a>";
1911  }
1912 
1913  if ($is_latest) {
1914  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_latest_" . $type));
1915  } else {
1916  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_" . $type));
1917  }
1918  if ($type > 0) {
1919  $tpl->touchBlock("st" . $type);
1920  $tpl->touchBlock("stb" . $type);
1921  }
1922  $tpl->setVariable("TITLE", $title);
1923  $tpl->setVariable(
1924  "DATE",
1925  ilDatePresentation::formatDate(new ilDate($a_level_entry["status_date"], IL_CAL_DATETIME))
1926  );
1927 
1929 
1930  return $tpl->get();
1931  }
1932 
1933  protected function getLatestEntriesForSkillHTML(
1934  int $top_skill_id,
1935  array $bs,
1936  ilSkillTreeNode $skill,
1937  ilObjUser $user,
1938  int $eval_type,
1939  array $level_data
1940  ): string {
1941  $lng = $this->lng;
1942 
1943  $tpl = new ilTemplate("tpl.skill_entries_latest.html", true, true, "Services/Skill");
1944 
1945  $user_entries = $skill->getAllHistoricLevelEntriesOfUser($bs["tref"], $user->getId(), $eval_type);
1946  $user_entries_filtered = $this->getFilteredEntriesForSkill(
1947  $user_entries,
1948  $top_skill_id,
1949  $bs,
1950  $user
1951  );
1952  if ($eval_type == ilBasicSkill::EVAL_BY_SELF) {
1953  $latest_entries = $this->getSelfEvalEntriesLatestOnly($user_entries_filtered);
1954  } else {
1955  $latest_entries = $this->getAllEntriesLatestOnly($user_entries_filtered);
1956  }
1957 
1958  $latest_entries_html = "";
1959  foreach ($latest_entries as $entry) {
1960  $latest_entries_html .= $this->ui_ren->render(
1961  $this->ui_fac->legacy($this->getEvalItem($level_data, $entry, true))
1962  );
1963  }
1964 
1965  if (!empty($latest_entries_html)) {
1966  $tpl->setVariable("SKILL_ENTRIES", $latest_entries_html);
1967 
1968  if (count($user_entries_filtered) != count($latest_entries)) {
1969  $tpl->setCurrentBlock("all_entries_button");
1970  $show_all_button = $this->ui_fac->button()->standard($lng->txt("skmg_show_all"), "#")
1971  ->withOnLoadCode(function ($id) {
1972  return "$('#$id').on('click', function() {SkillEntries.showNonLatest($id); return false;})";
1973  });
1974  $tpl->setVariable("BUTTON", $this->ui_ren->render($show_all_button));
1975  $tpl->parseCurrentBlock();
1976  }
1977 
1978  return $tpl->get();
1979  }
1980 
1981  return "";
1982  }
1983 
1985  int $top_skill_id,
1986  array $bs,
1987  ilSkillTreeNode $skill,
1988  ilObjUser $user,
1989  int $eval_type,
1990  array $level_data
1991  ): string {
1992  $lng = $this->lng;
1993 
1994  $tpl = new ilTemplate("tpl.skill_entries_non_latest.html", true, true, "Services/Skill");
1995 
1996  $user_entries = $skill->getAllHistoricLevelEntriesOfUser($bs["tref"], $user->getId(), $eval_type);
1997  $user_entries_filtered = $this->getFilteredEntriesForSkill(
1998  $user_entries,
1999  $top_skill_id,
2000  $bs,
2001  $user
2002  );
2003  if ($eval_type == ilBasicSkill::EVAL_BY_SELF) {
2004  $non_latest_entries = $this->getSelfEvalEntriesWithoutLatest($user_entries_filtered);
2005  } else {
2006  $non_latest_entries = $this->getAllEntriesWithoutLatest($user_entries_filtered);
2007  }
2008 
2009  $non_latest_entries_filtered_html = "";
2010  foreach ($non_latest_entries as $entry) {
2011  $non_latest_entries_filtered_html .= $this->ui_ren->render(
2012  $this->ui_fac->legacy($this->getEvalItem($level_data, $entry, false))
2013  );
2014  }
2015 
2016  if (!empty($non_latest_entries_filtered_html)) {
2017  $tpl->setVariable("SKILL_ENTRIES", $non_latest_entries_filtered_html);
2018 
2019  $show_latest_button = $this->ui_fac->button()->standard($lng->txt("skmg_show_latest_entries"), "#")
2020  ->withOnLoadCode(function ($id) {
2021  return "$('#$id').on('click', function() {SkillEntries.hideNonLatest($id); return false;})";
2022  });
2023  $tpl->setVariable("BUTTON", $this->ui_ren->render($show_latest_button));
2024 
2025  return $tpl->get();
2026  }
2027 
2028  return "";
2029  }
2030 
2031  protected function getFilteredEntriesForSkill(
2032  array $entries,
2033  int $top_skill_id,
2034  array $bs,
2035  ilObjUser $user
2036  ): array {
2037  // get date of self evaluation
2038  $se_date = $this->self_evaluation_manager->getSelfEvaluationDate($user->getId(), $top_skill_id, $bs["tref"], $bs["id"]);
2039  $se_rendered = $se_date == "";
2040 
2041  $filtered_entries = [];
2042  foreach ($entries as $level_entry) {
2043  if (count($this->getTriggerObjectsFilter()) && !in_array($level_entry['trigger_obj_id'], $this->getTriggerObjectsFilter())) {
2044  continue;
2045  }
2046  if (count($this->getTriggerUserFilter()) && !in_array($level_entry['trigger_user_id'], $this->getTriggerUserFilter())) {
2047  continue;
2048  }
2049 
2050  // render the self evaluation at the correct position within the list of object triggered entries
2051  if ($se_date > $level_entry["status_date"] && !$se_rendered) {
2052  $se_rendered = true;
2053  }
2054  if ($this->getFilter()->isInRange($level_entry)) {
2055  $filtered_entries[] = $level_entry;
2056  }
2057  }
2058 
2059  return $filtered_entries;
2060  }
2061 
2062  protected function getSelfEvalEntriesLatestOnly(array $entries): array
2063  {
2064  if (!empty($entries)) {
2065  $last_entry[] = $entries[0];
2066  return $last_entry;
2067  }
2068 
2069  return [];
2070  }
2071 
2072  protected function getSelfEvalEntriesWithoutLatest(array $entries): array
2073  {
2074  if (count($entries) > 1) {
2075  array_shift($entries);
2076  return $entries;
2077  }
2078 
2079  return [];
2080  }
2081 
2082  protected function getAllEntriesLatestOnly(array $entries): array
2083  {
2084  $first_self_added = false;
2085  $first_measurement_added = false;
2086  $first_appraisal_added = false;
2087  $latest_entries = [];
2088  foreach ($entries as $entry) {
2089  if (!$first_self_added && $entry["self_eval"] == 1) {
2090  $latest_entries[] = $entry;
2091  $first_self_added = true;
2092  continue;
2093  }
2094  if (!$first_measurement_added && $entry["trigger_obj_type"] == "tst") {
2095  $latest_entries[] = $entry;
2096  $first_measurement_added = true;
2097  continue;
2098  }
2099  if (!$first_appraisal_added && $entry["self_eval"] != 1 && $entry["trigger_obj_type"] != "tst") {
2100  $latest_entries[] = $entry;
2101  $first_appraisal_added = true;
2102  }
2103  }
2104 
2105  return $latest_entries;
2106  }
2107 
2108  protected function getAllEntriesWithoutLatest(array $entries): array
2109  {
2110  $first_self_filtered = false;
2111  $first_measurement_filtered = false;
2112  $first_appraisal_filtered = false;
2113  $non_latest_entries = [];
2114  foreach ($entries as $entry) {
2115  if (!$first_self_filtered && $entry["self_eval"] == 1) {
2116  $first_self_filtered = true;
2117  continue;
2118  }
2119  if (!$first_measurement_filtered && $entry["trigger_obj_type"] == "tst") {
2120  $first_measurement_filtered = true;
2121  continue;
2122  }
2123  if (!$first_appraisal_filtered && $entry["self_eval"] != 1 && $entry["trigger_obj_type"] != "tst") {
2124  $first_appraisal_filtered = true;
2125  continue;
2126  }
2127  $non_latest_entries[] = $entry;
2128  }
2129 
2130  return $non_latest_entries;
2131  }
2132 
2133  protected function getSkillEntriesHeader(int $eval_type): string
2134  {
2135  $tpl = new ilTemplate("tpl.skill_entries_header.html", true, true, "Services/Skill");
2136 
2137  if ($eval_type == ilBasicSkill::EVAL_BY_SELF) {
2138  $tpl->setVariable("HEADING", $this->lng->txt("skmg_self_evaluation"));
2139  $tpl->setCurrentBlock("header_byline");
2140  $tpl->setVariable("BYLINE", $this->lng->txt("skmg_self_evaluation_byline"));
2141  $tpl->parseCurrentBlock();
2142  } else {
2143  if ($this->getProfileId() > 0) {
2144  $tpl->setVariable("HEADING", $this->lng->txt("skmg_skill_profile_records"));
2145  }
2146  }
2147 
2148  return $tpl->get();
2149  }
2150 
2151  protected function getSkillCategoryDescription(int $skill_id, int $tref_id): string
2152  {
2153  $tpl = new ilTemplate("tpl.skill_description_category.html", true, true, "Services/Skill");
2154 
2155  //if (ilSkillTreeNode::_lookupType($skill_id) == "scat") {
2156  $des = ilSkillTreeNode::_lookupDescription($skill_id);
2157  if (!empty($des)) {
2158  $tpl->setCurrentBlock("description_category");
2159  $tpl->setVariable("DESCRIPTION_CATEGORY", $des);
2160  $tpl->parseCurrentBlock();
2161  }
2162  //}
2163 
2164  return $tpl->get();
2165  }
2166 
2167  protected function getBasicSkillDescription(string $description): string
2168  {
2169  $tpl = new ilTemplate("tpl.skill_description_basic.html", true, true, "Services/Skill");
2170 
2171  if (!empty($description)) {
2172  $tpl->setCurrentBlock("description_basic");
2173  $tpl->setVariable("DESCRIPTION_BASIC", $description);
2174  $tpl->parseCurrentBlock();
2175  }
2176 
2177  return $tpl->get();
2178  }
2179 
2180  public function getSkillLevelDescription(ilSkillTreeNode $skill): string
2181  {
2182  $level_data = $skill->getLevelData();
2183  $tpl = new ilTemplate("tpl.skill_desc.html", true, true, "Services/Skill");
2184 
2185  $desc_exists = false;
2186  foreach ($level_data as $l) {
2187  if ($l["description"] != "") {
2188  $desc_exists = true;
2189  }
2190  }
2191  reset($level_data);
2192  if ($desc_exists) {
2193  foreach ($level_data as $l) {
2194  $tpl->setCurrentBlock("level");
2195  $tpl->setVariable("LEVEL_VAL", $l["title"]);
2196  $tpl->setVariable("LEVEL_DESC", nl2br($l["description"]));
2197  $tpl->parseCurrentBlock();
2198  }
2199  }
2200 
2201  return $tpl->get();
2202  }
2203 
2205  array $a_levels,
2206  int $a_base_skill,
2207  int $a_tref_id,
2208  int $gap_mode_obj_id = 0
2209  ): ?\ILIAS\UI\Component\Panel\Secondary\Secondary {
2210  $lng = $this->lng;
2211 
2212  $gap_mode_obj_type = ilObject::_lookupType($gap_mode_obj_id);
2213  if ($gap_mode_obj_id > 0 && !$this->obj_definition->isContainer($gap_mode_obj_type)) {
2214  return null;
2215  }
2216 
2217  // note for self-evaluation
2218  if ($this->skmg_settings->getHideProfileBeforeSelfEval() &&
2219  !ilBasicSkill::hasSelfEvaluated($this->user->getId(), $a_base_skill, $a_tref_id)) {
2220  $sec_panel_content = $this->ui_fac->legacy($lng->txt("skmg_skill_needs_self_eval"));
2221  $sec_panel = $this->ui_fac->panel()->secondary()->legacy("", $sec_panel_content);
2222  return $sec_panel;
2223  }
2224 
2225  // suggested resources
2226  if ($this->resource_manager->isLevelTooLow($a_tref_id, $a_levels, $this->profile_levels, $this->actual_levels)) {
2227  $imp_resources = $this->resource_manager->getSuggestedResources(
2228  $a_base_skill,
2229  $a_tref_id,
2230  $a_levels,
2231  $this->profile_levels
2232  );
2233  $info = $this->ui_fac->item()->standard($lng->txt("skmg_recommended_learning_material_info"));
2234  $item_groups[] = $this->ui_fac->item()->group("", [$info]);
2235 
2236  $at_least_one_item = false;
2237  $highlighted_level = false;
2238 
2239  $sub_objects = [];
2240  $is_container = false;
2241  if ($gap_mode_obj_id > 0 && $this->obj_definition->isContainer($gap_mode_obj_type)) {
2242  $is_container = true;
2243  $sub_objects = $this->tree->getSubTree(
2244  $this->tree->getNodeData((int) current(\ilObject::_getAllReferences($gap_mode_obj_id))),
2245  false
2246  );
2247  }
2248 
2249  foreach ($imp_resources as $order_level_id => $resources) {
2250  $level_id = (int) substr(strrchr($order_level_id, '_'), 1);
2251  // do not show level if already reached
2252  if ($level_id <= $this->actual_levels[$a_base_skill][$a_tref_id]) {
2253  continue;
2254  }
2255  if ($level_id === $this->resource_manager->determineCurrentTargetLevel($a_levels, $this->profile_levels)) {
2256  $highlighted_level = true;
2257  }
2258  $level_title = $this->level_repo->lookupLevelTitle($level_id);
2259  $items = [];
2260  foreach ($resources as $r) {
2261  $ref_id = $r->getRepoRefId();
2262  // in containers: filter resources only by objects in sub tree
2263  if ($is_container && !in_array($ref_id, $sub_objects)) {
2264  continue;
2265  }
2266  $obj_id = ilObject::_lookupObjId($ref_id);
2267  $title = ilObject::_lookupTitle($obj_id);
2268  $icon = $this->ui_fac->symbol()->icon()->standard(
2269  ilObject::_lookupType($obj_id),
2270  $lng->txt("icon") . " " . $lng->txt(ilObject::_lookupType($obj_id))
2271  );
2272  $link = $this->ui_fac->link()->standard($title, ilLink::_getLink($ref_id));
2273  $items[] = $this->ui_fac->item()->standard($link)->withLeadIcon($icon);
2274  $at_least_one_item = true;
2275  }
2276  $item_groups[] = $this->ui_fac->item()->group(
2277  $highlighted_level
2278  ? "<strong>" . $level_title . " (" . $lng->txt("skmg_target_level") . ")</strong>"
2279  : $level_title,
2280  $items
2281  );
2282  }
2283  if ($at_least_one_item) {
2284  switch ($gap_mode_obj_type) {
2285  case "crs":
2286  $sec_panel_title = $lng->txt("skmg_recommended_learning_material_crs");
2287  break;
2288  case "grp":
2289  $sec_panel_title = $lng->txt("skmg_recommended_learning_material_grp");
2290  break;
2291  default:
2292  $sec_panel_title = $lng->txt("skmg_recommended_learning_material_global");
2293  }
2294 
2295  $sec_panel = $this->ui_fac->panel()->secondary()->listing(
2296  $sec_panel_title,
2297  $item_groups
2298  );
2299  } else {
2300  $sec_panel_content = $this->ui_fac->legacy($lng->txt("skmg_skill_needs_impr_no_res"));
2301  $sec_panel = $this->ui_fac->panel()->secondary()->legacy("", $sec_panel_content);
2302  }
2303  } else {
2304  $sec_panel_content = $this->ui_fac->legacy($lng->txt("skmg_skill_no_needs_impr_info"));
2305  $sec_panel = $this->ui_fac->panel()->secondary()->legacy($lng->txt("skmg_skill_no_needs_impr"), $sec_panel_content);
2306  }
2307 
2308  return $sec_panel;
2309  }
2310 
2311  public function getAllSuggestedResources(
2312  int $a_base_skill,
2313  int $a_tref_id
2314  ): ?\ILIAS\UI\Component\Panel\Secondary\Secondary {
2315  $lng = $this->lng;
2316 
2317  $res = $this->resource_manager->getResources($a_base_skill, $a_tref_id);
2318  $any = false;
2319  $item_groups = [];
2320  foreach ($res as $level) {
2321  $available = false;
2322  $cl = 0;
2323  $items = [];
2324  foreach ($level as $r) {
2325  if ($r->getImparting()) {
2326  $ref_id = $r->getRepoRefId();
2327  $obj_id = ilObject::_lookupObjId($ref_id);
2328  $title = ilObject::_lookupTitle($obj_id);
2329  $icon = $this->ui_fac->symbol()->icon()->standard(
2330  ilObject::_lookupType($obj_id),
2331  $lng->txt("icon") . " " . $lng->txt(ilObject::_lookupType($obj_id))
2332  );
2333  $link = $this->ui_fac->link()->standard($title, ilLink::_getLink($ref_id));
2334  $items[] = $this->ui_fac->item()->standard($link)->withLeadIcon($icon);
2335  $available = true;
2336  $any = true;
2337  $cl = $r->getLevelId();
2338  }
2339  }
2340  if ($available) {
2341  $item_groups[] = $this->ui_fac->item()->group(ilBasicSkill::lookupLevelTitle($cl), $items);
2342  }
2343  }
2344  if ($any) {
2345  $sec_panel = $this->ui_fac->panel()->secondary()->listing(
2346  $lng->txt("skmg_suggested_resources"),
2347  $item_groups
2348  );
2349  return $sec_panel;
2350  }
2351 
2352  return null;
2353  }
2354 
2355  public function listAllAssignedProfiles(): void
2356  {
2357  if (empty($this->user_profiles)) {
2358  $this->ctrl->redirect($this, "listSkills");
2359  }
2360 
2361  $this->setTabs("profile");
2362 
2363  $prof_list = $this->getProfilesListed($this->user_profiles);
2364 
2365  $this->tpl->setContent($this->ui_ren->render($prof_list));
2366  }
2367 
2368  public function listAssignedProfile(): void
2369  {
2370  $ilCtrl = $this->ctrl;
2371  $lng = $this->lng;
2372 
2373  $main_tpl = $this->tpl;
2374 
2375  $tpl = new ilTemplate("tpl.skill_filter.html", true, true, "Services/Skill");
2376 
2377  $this->tabs->clearTargets();
2378  $this->tabs->setBackTarget(
2379  $this->lng->txt("back"),
2380  $ilCtrl->getLinkTarget($this, "listallassignedprofiles")
2381  );
2382  $this->setProfileId($this->requested_profile_id);
2383 
2384  $main_tpl->setTitle($this->profile_manager->lookupTitle($this->getProfileId()));
2385 
2386  $filter_toolbar = new ilToolbarGUI();
2387  $filter_toolbar->setFormAction($ilCtrl->getFormAction($this));
2388  $this->getFilter()->addToToolbar($filter_toolbar, true);
2389 
2390  $skills = [];
2391  if ($this->getProfileId() > 0) {
2392  $this->profile_levels = $this->profile_manager->getSkillLevels($this->getProfileId());
2393  $skills = $this->profile_levels;
2394  }
2395 
2396  $this->actual_levels = $this->profile_completion_manager->getActualMaxLevels(
2397  $this->user->getId(),
2398  $skills,
2402  );
2403 
2404  // render
2405  $html = "";
2406  $not_all_self_evaluated = false;
2407  foreach ($skills as $s) {
2408  if ($this->skmg_settings->getHideProfileBeforeSelfEval() &&
2409  !ilBasicSkill::hasSelfEvaluated($this->user->getId(), $s->getBaseSkillId(), $s->getTrefId())) {
2410  $not_all_self_evaluated = true;
2411  }
2412 
2413  // todo draft check
2414  $html .= $this->getSkillHTML($s->getBaseSkillId(), 0, true, $s->getTrefId());
2415  }
2416 
2417  if ($html != "") {
2418  $filter_toolbar->addFormButton($this->lng->txt("skmg_refresh_view"), "applyFilterAssignedProfiles");
2419 
2420  $tpl->setVariable("FILTER", $filter_toolbar->getHTML());
2421 
2422  $html = $tpl->get() . $html;
2423  }
2424 
2425  if ($not_all_self_evaluated) {
2426  $box = $this->ui_fac->messageBox()->info($lng->txt("skmg_skill_needs_self_eval_box"));
2427  $html = $this->ui_ren->render($box) . $html;
2428  }
2429 
2430  $main_tpl->setContent($html);
2431  }
2432 }
setGapAnalysisActualStatusModePerObject(int $a_obj_id, string $a_cat_title="")
Profile SkillProfileCompletionManager $profile_completion_manager
getSkillCategoryDescription(int $skill_id, int $tref_id)
setOfflineMode(string $a_file_path)
getProfilesListed(array $profiles, bool $gap_mode=false)
ilObjectDefinition $obj_definition
An entity that renders components to a string output.
Definition: Renderer.php:30
$res
Definition: ltiservices.php:69
setGapAnalysisSelfEvalLevels(array $a_val)
setObjectSkills(int $a_obj_id, array $a_skills)
$resources
Definition: ltiservices.php:68
This describes commonalities between all forms.
Definition: Form.php:32
const IL_CAL_DATETIME
getEvalItem(array $a_levels, array $a_level_entry, bool $is_latest=false)
This class represents a selection list property in a property form.
getMaterials(array $a_levels, int $a_tref_id=0, int $a_user_id=0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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...
Personal PersonalSkillManager $personal_manager
hideSkill(int $a_skill_id, int $a_tref_id=0)
touchBlock(string $block)
overwrites ITX::touchBlock.
Table TableManager $table_manager
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Profile SkillProfileManager $profile_manager
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const PANEL_STYLE_PRIMARY
Class ChatMainBarProvider .
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
ServerRequestInterface $request
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setTypeWhiteList(array $a_val)
Set type white list.
static _getAllReferences(int $id)
get all reference ids for object ID
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
Help GUI class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Resource SkillResourcesManager $resource_manager
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
static _lookupTitle(int $a_obj_id, int $a_tref_id=0)
Explorer for selecting a personal skill.
get(string $part=self::DEFAULT_BLOCK)
Renders the given block and returns the html string.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
loadLanguageModule(string $a_module)
Load language module.
getMaterialInfo(int $a_wsp_id, int $a_user_id)
Get material file name and goto url.
setOptions(array $a_options)
static lookupLevelTitle(int $a_id)
setVariable(string $variable, $value='')
Sets the given variable to the given value.
Service SkillPersonalGUIRequest $personal_gui_request
renderSkillHTML(int $a_top_skill_id, int $a_user_id=0, bool $a_edit=false, int $a_tref_id=0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupType(int $a_obj_id)
getProfileTargetItem(int $a_profile_id, array $a_levels, int $a_tref_id=0)
setTitleIcon(string $a_icon_path, string $a_icon_desc="")
set title icon
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setGapAnalysisActualStatusModePerType(string $a_type, string $a_cat_title="")
$path
Definition: ltiservices.php:32
static _lookupDescription(int $a_obj_id)
static _lookupObjId(int $ref_id)
static hasSelfEvaluated(int $a_user_id, int $a_skill_id, int $a_tref_id)
getSkillLevelDescription(ilSkillTreeNode $skill)
ilSkillManagementSettings $skmg_settings
getSkillHTML(int $a_top_skill_id, int $a_user_id=0, bool $a_edit=false, int $a_tref_id=0)
Get skill presentation HTML.
global $DIC
Definition: feed.php:28
Service SkillTreeService $tree_service
assignMaterial()
Assign materials to skill level.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Personal skills GUI class.
parses the objects.xml it handles the xml-description of all ilias objects
setTriggerObjectsFilter(array $trigger_objects_filter)
Provides fluid interface to RBAC services.
Definition: UIServices.php:23
Personal SelfEvaluationManager $self_evaluation_manager
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
getSelfEvalGapItem(array $a_levels, int $a_tref_id=0)
$ref_id
Definition: ltiauth.php:67
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _lookupTitle(int $obj_id)
setContent(string $a_html)
Sets content for standard template.
getActualGapItem(array $a_levels, int $a_tref_id=0)
setTriggerUserFilter(array $trigger_user_filter)
ilPersonalSkillsFilterGUI $filter
renderer()
Get a renderer for UI components.
Definition: UIServices.php:43
applyFilterAssignedProfiles()
Apply filter for profiles view.
ilSkillLevelRepository $level_repo
Class ilObjFile.
setBackTarget(string $a_title, string $a_target, string $a_frame="")
Explorer for selecting a personal workspace item.
$url
Definition: ltiregstart.php:35
getLevelData(int $a_id=0)
setTitle(string $a_title, bool $hidden=false)
Sets title in standard template.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Service SkillInternalManagerService $internal_manager
setCurrentBlock(string $part=self::DEFAULT_BLOCK)
Sets the template to the given block.
ilGlobalTemplateInterface $tpl
static getInstance()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Personal AssignedMaterialManager $assigned_material_manager
getSelfEvaluationForm(int $cur_basic_skill_id)
getNonLatestEntriesForSkillHTML(int $top_skill_id, array $bs, ilSkillTreeNode $skill, ilObjUser $user, int $eval_type, array $level_data)
assignMaterials()
Assign materials to skill levels.
global $ilSetting
Definition: privfeed.php:18
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
getBasicSkillDescription(string $description)
getFilteredEntriesForSkill(array $entries, int $top_skill_id, array $bs, ilObjUser $user)
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
getSuggestedResourcesForProfile(array $a_levels, int $a_base_skill, int $a_tref_id, int $gap_mode_obj_id=0)
setObjectSkillProfiles(int $cont_member_role_id)
$message
Definition: xapiexit.php:32
factory()
Get the factory that crafts UI components.
Definition: UIServices.php:35
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
filter(string $filter_id, $class_path, string $cmd, bool $activated=true, bool $expanded=true)
getAllSuggestedResources(int $a_base_skill, int $a_tref_id)
parseCurrentBlock(string $block_name=self::DEFAULT_BLOCK)
Parses the given block.
ContainerSkills SkillInternalFactoryService $cont_factory_service
static _lookupType(int $id, bool $reference=false)
static setUseRelativeDates(bool $a_status)
set use relative dates
Basic Skill.
getSelfEvalEntriesWithoutLatest(array $entries)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getLatestEntriesForSkillHTML(int $top_skill_id, array $bs, ilSkillTreeNode $skill, ilObjUser $user, int $eval_type, array $level_data)
ilSkillTreeRepository $tree_repo
getSelfEvalEntriesLatestOnly(array $entries)
getScaleBar(array $a_levels, $a_activated_levels)
getAllEntriesWithoutLatest(array $entries)
addTab(string $a_id, string $a_text, string $a_link, string $a_frame="")
Add a Tab.
$r