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