ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
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 
75  protected array $hidden_skills = [];
76  protected string $mode = "";
77  protected string $gap_mode = "";
78  protected int $gap_mode_obj_id = 0;
79  protected string $gap_mode_type = "";
80  protected string $gap_cat_title = "";
81 
82  protected UIServices $ui;
83  protected ilCtrl $ctrl;
84  protected ilLanguage $lng;
85  protected ilHelpGUI $help;
86  protected ilSetting $setting;
87  protected ilObjUser $user;
89  protected ilTabsGUI $tabs;
92  protected Factory $ui_fac;
93  protected Renderer $ui_ren;
97  protected ilTree $tree;
99 
100  protected int $obj_id = 0;
101 
105  protected array $obj_skills = [];
106  protected int $profile_id = 0;
107 
111  protected array $profile_levels = [];
112 
116  protected array $user_profiles = [];
117 
121  protected array $cont_profiles = [];
122  protected bool $use_materials = false;
125  protected Service\SkillPersonalGUIRequest $personal_gui_request;
128  protected Service\SkillTreeService $tree_service;
129  protected Service\SkillInternalManagerService $internal_manager;
130  protected Profile\SkillProfileManager $profile_manager;
131  protected Profile\SkillProfileCompletionManager $profile_completion_manager;
132  protected Personal\PersonalSkillManager $personal_manager;
133  protected Personal\AssignedMaterialManager $assigned_material_manager;
134  protected Personal\SelfEvaluationManager $self_evaluation_manager;
135  protected Resource\SkillResourcesManager $resource_manager;
136  protected Table\TableManager $table_manager;
138  protected string $requested_list_mode = self::LIST_PROFILES;
139  protected int $requested_node_id = 0;
140  protected int $requested_profile_id = 0;
141  protected int $requested_skill_id = 0;
142 
146  protected array $requested_skill_ids = [];
147  protected int $requested_basic_skill_id = 0;
148  protected int $requested_tref_id = 0;
149  protected int $requested_level_id = 0;
150 
152 
158 
162  protected array $requested_wsp_ids = [];
163 
164  protected string $trigger_user_filter = "";
165 
166  public function __construct()
167  {
168  global $DIC;
169 
170  $this->ctrl = $DIC->ctrl();
171  $this->lng = $DIC->language();
172  $this->help = $DIC["ilHelp"];
173  $this->setting = $DIC["ilSetting"];
174  $this->user = $DIC->user();
175  $this->tpl = $DIC["tpl"];
176  $this->tabs = $DIC->tabs();
177  $this->toolbar = $DIC->toolbar();
178  $this->access = $DIC->access();
179  $this->ui_fac = $DIC->ui()->factory();
180  $this->ui_ren = $DIC->ui()->renderer();
181  $this->request = $DIC->http()->request();
182  $this->ui = $DIC->ui();
183  $this->storage = $DIC->resourceStorage();
184  $this->data_fac = new \ILIAS\Data\Factory();
185  $this->tree = $DIC->repositoryTree();
186  $this->obj_definition = $DIC["objDefinition"];
187  $this->personal_gui_request = $DIC->skills()->internal()->gui()->personal_request();
188  $this->tree_repo = $DIC->skills()->internal()->repo()->getTreeRepo();
189  $this->level_repo = $DIC->skills()->internal()->repo()->getLevelRepo();
190  $this->tree_service = $DIC->skills()->tree();
191  $this->internal_manager = $DIC->skills()->internal()->manager();
192  $this->profile_manager = $this->internal_manager->getProfileManager();
193  $this->profile_completion_manager = $this->internal_manager->getProfileCompletionManager();
194  $this->personal_manager = $this->internal_manager->getPersonalSkillManager();
195  $this->assigned_material_manager = $this->internal_manager->getAssignedMaterialManager();
196  $this->self_evaluation_manager = $this->internal_manager->getSelfEvaluationManager();
197  $this->resource_manager = $this->internal_manager->getResourceManager();
198  $this->table_manager = $this->internal_manager->getTableManager();
199  $this->cont_factory_service = $DIC->skills()->internalContainer()->factory();
200 
201  $ilCtrl = $this->ctrl;
202  $ilHelp = $this->help;
203  $lng = $this->lng;
205 
206 
207  $lng->loadLanguageModule('skmg');
208  $ilHelp->setScreenIdComponent("skill");
209 
210  $ilCtrl->saveParameter($this, "skill_id");
211  $ilCtrl->saveParameter($this, "tref_id");
212  $ilCtrl->saveParameter($this, "profile_id");
213  $ilCtrl->saveParameter($this, "list_mode");
214 
215  $this->requested_list_mode = $this->personal_gui_request->getListMode();
216  $this->requested_node_id = $this->personal_gui_request->getNodeId();
217  $this->requested_profile_id = $this->personal_gui_request->getProfileId();
218  $this->requested_skill_id = $this->personal_gui_request->getSkillId();
219  $this->requested_skill_ids = $this->personal_gui_request->getSkillIds();
220  $this->requested_basic_skill_id = $this->personal_gui_request->getBasicSkillId();
221  $this->requested_tref_id = $this->personal_gui_request->getTrefId();
222  $this->requested_level_id = $this->personal_gui_request->getLevelId();
223  $this->requested_wsp_ids = $this->personal_gui_request->getWorkspaceIds();
224  $this->requested_table_assign_materials_action = $this->personal_gui_request->getTableAssignMaterialsAction();
225  $this->requested_table_assign_materials_level_ids = $this->personal_gui_request->getTableAssignMaterialsLevelIds();
226  $this->requested_table_assign_materials_wsp_id = $this->personal_gui_request->getTableAssignMaterialsWorkspaceId();
227 
228  $this->user_profiles = $this->profile_manager->getProfilesOfUser($this->user->getId());
229  $this->cont_profiles = [];
230 
231  $this->use_materials = !$ilSetting->get("disable_personal_workspace");
232 
233  $this->skmg_settings = new ilSkillManagementSettings();
234 
235  $this->filter = new ilPersonalSkillsFilterGUI();
236  }
237 
239  {
240  return $this->filter;
241  }
242 
243  public function setProfileId(int $a_val): void
244  {
245  $this->profile_id = $a_val;
246  }
247 
248  public function getProfileId(): int
249  {
250  return $this->profile_id;
251  }
252 
256  public function setGapAnalysisSelfEvalLevels(array $a_val): void
257  {
258  $this->gap_self_eval_levels = $a_val;
259  }
260 
264  public function getGapAnalysisSelfEvalLevels(): array
265  {
267  }
268 
269  public function setHistoryView(bool $a_val): void
270  {
271  $this->history_view = $a_val;
272  }
273 
274  public function getHistoryView(): bool
275  {
276  return $this->history_view;
277  }
278 
279  public function getNonHistoricGapModeView(): bool
280  {
281  return ($this->mode == "gap" && !$this->history_view);
282  }
283 
284  public function getTriggerObjectsFilter(): array
285  {
287  }
288 
289  public function setTriggerObjectsFilter(array $trigger_objects_filter): void
290  {
291  $this->trigger_objects_filter = $trigger_objects_filter;
292  }
293 
294  public function getTriggerUserFilter(): string
295  {
297  }
298 
302  public function setTriggerUserFilter(string $trigger_user_filter): void
303  {
304  $this->trigger_user_filter = $trigger_user_filter;
305  }
306 
307  public function hideSkill(int $a_skill_id, int $a_tref_id = 0): void
308  {
309  $this->hidden_skills[] = $a_skill_id . ":" . $a_tref_id;
310  }
311 
312  public function getObjectId(): int
313  {
314  return $this->obj_id;
315  }
316 
320  public function getObjectSkills(): array
321  {
322  return $this->obj_skills;
323  }
324 
328  public function setObjectSkills(int $a_obj_id, array $a_skills): void
329  {
330  $this->obj_id = $a_obj_id;
331  $this->obj_skills = $a_skills;
332  }
333 
334  public function setObjectSkillProfiles(
335  int $cont_member_role_id
336  ): void {
337  $this->cont_profiles = $this->profile_manager->getAllProfilesOfRole($cont_member_role_id);
338  }
339 
340  public function executeCommand(): void
341  {
342  $ilCtrl = $this->ctrl;
343  $ilUser = $this->user;
344  $lng = $this->lng;
345  $tpl = $this->tpl;
346 
347  $next_class = $ilCtrl->getNextClass($this);
348 
349 
350  $cmd = $ilCtrl->getCmd("render");
351 
352  //$tpl->setTitle($lng->txt("skills"));
353  //$tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_skmg.svg"));
354 
355  switch ($next_class) {
356  default:
357  $this->$cmd();
358  break;
359  }
360  }
361 
362  public function setTabs(string $a_activate): void
363  {
364  $ilCtrl = $this->ctrl;
365  $lng = $this->lng;
366  $ilTabs = $this->tabs;
367 
368  if (!empty($this->user_profiles)) {
369  $ilCtrl->setParameter($this, "list_mode", self::LIST_PROFILES);
370  $ilTabs->addTab(
371  "profile",
372  $lng->txt("skmg_assigned_profiles"),
373  $ilCtrl->getLinkTarget($this, "render")
374  );
375  }
376 
377  // list skills
378  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
379  $ilTabs->addTab(
380  "list_skills",
381  $lng->txt("skmg_selected_skills"),
382  $ilCtrl->getLinkTarget($this, "render")
383  );
384 
385  $ilCtrl->clearParameterByClass(get_class($this), "list_mode");
386 
387  // assign materials
388 
389  $ilTabs->activateTab($a_activate);
390  }
391 
392  public function setOfflineMode(string $a_file_path): void
393  {
394  $this->offline_mode = $a_file_path;
395  }
396 
397  public function getOfflineMode(): string
398  {
399  return $this->offline_mode;
400  }
401 
402  protected function render(): void
403  {
404  if ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles)) {
405  $this->listSkills();
406  } else {
407  $this->listAllAssignedProfiles();
408  }
409  }
410 
411  public function listSkills(): void
412  {
413  $ilCtrl = $this->ctrl;
414  $ilUser = $this->user;
415  $lng = $this->lng;
416  $main_tpl = $this->tpl;
417  $ilToolbar = $this->toolbar;
418 
419  $tpl = new ilTemplate("tpl.skill_filter.html", true, true, "components/ILIAS/Skill");
420 
421  $this->setTabs("list_skills");
422 
423  // skill selection / add new personal skill
424  $ilToolbar->addFormButton(
425  $lng->txt("skmg_add_skill"),
426  "listSkillsForAdd"
427  );
428  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
429 
430  $filter_toolbar = new ilToolbarGUI();
431  $filter_toolbar->setFormAction($ilCtrl->getFormAction($this));
432  $this->getFilter()->addToToolbar($filter_toolbar, false);
433 
434  $skills = $this->personal_manager->getSelectedUserSkills($ilUser->getId());
435  $html = "";
436  foreach ($skills as $s) {
437  $path = $this->tree_service->getSkillTreePath($s->getSkillNodeId());
438 
439  // check draft
440  foreach ($path as $p) {
441  if ($p["status"] == ilSkillTreeNode::STATUS_DRAFT) {
442  continue(2);
443  }
444  }
445  $html .= $this->getSkillHTML($s->getSkillNodeId(), 0, true);
446  }
447 
448  // list skills
449 
450  if ($html != "") {
451  $filter_toolbar->addFormButton($this->lng->txt("skmg_refresh_view"), "applyFilter");
452  $tpl->setVariable("FILTER", $filter_toolbar->getHTML());
453  $html = $tpl->get() . $html;
454  } else {
455  $box = $this->ui_fac->messageBox()->info($lng->txt("skmg_no_skills_selected_info"));
456  $html = $this->ui_ren->render($box);
457  }
458 
459  $main_tpl->setContent($html);
460  }
461 
462  protected function applyFilter(): void
463  {
464  $this->getFilter()->save();
465  $this->ctrl->setParameter($this, "list_mode", self::LIST_SELECTED);
466  $this->ctrl->redirect($this, "listSkills");
467  }
468 
472  protected function applyFilterAssignedProfiles(): void
473  {
474  $this->getFilter()->save();
475  $this->ctrl->redirect($this, "listAssignedProfile");
476  }
477 
478 
487  public function getSkillHTML(
488  int $a_top_skill_id,
489  int $a_user_id = 0,
490  bool $a_edit = false,
491  int $a_tref_id = 0
492  ): string {
493  $main_tpl = $this->tpl;
494 
495  // user interface plugin slot + default rendering
496  $uip = new ilUIHookProcessor(
497  "components/ILIAS/Skill",
498  "personal_skill_html",
499  array("personal_skills_gui" => $this, "top_skill_id" => $a_top_skill_id, "user_id" => $a_user_id,
500  "edit" => $a_edit, "tref_id" => $a_tref_id)
501  );
502  $skill_html = "";
503  if (!$uip->replaced()) {
504  $skill_html = $this->renderSkillHTML($a_top_skill_id, $a_user_id, $a_edit, $a_tref_id);
505  }
506  $skill_html = $uip->getHTML($skill_html);
507  $main_tpl->addJavaScript("assets/js/SkillEntries.js");
508 
509  return $skill_html;
510  }
511 
512  public function renderSkillHTML(
513  int $a_top_skill_id,
514  int $a_user_id = 0,
515  bool $a_edit = false,
516  int $a_tref_id = 0
517  ): string {
518  $ilCtrl = $this->ctrl;
519  $ilUser = $this->user;
520  $lng = $this->lng;
521 
522  $sub_panels = [];
523 
524  if ($a_user_id == 0) {
525  $user = $ilUser;
526  } else {
527  $user = new ilObjUser($a_user_id);
528  }
529 
530  $tpl = new ilTemplate("tpl.skill_pres.html", true, true, "components/ILIAS/Skill");
531 
532  $vtree = $this->tree_repo->getVirtualTreeForNodeId($a_top_skill_id);
533  $tref_id = $a_tref_id;
534  $skill_id = $a_top_skill_id;
535  if (ilSkillTreeNode::_lookupType($a_top_skill_id) == "sktr") {
536  $tref_id = $a_top_skill_id;
537  $skill_id = ilSkillTemplateReference::_lookupTemplateId($a_top_skill_id);
538  }
539  $b_skills = $vtree->getSubTreeForCSkillId($skill_id . ":" . $tref_id, true);
540 
541  foreach ($b_skills as $bs) {
542  $bs["id"] = (int) $bs["skill_id"];
543  $bs["tref"] = (int) $bs["tref_id"];
544 
545  $path = $this->tree_service->getSkillTreePath($bs["id"], $bs["tref"]);
546 
547  $panel_comps = [];
548 
549 
550  // check draft
551  foreach ($path as $p) {
552  if ($p["status"] == ilSkillTreeNode::STATUS_DRAFT) {
553  continue(2);
554  }
555  }
556  reset($path);
557 
558  $skill = ilSkillTreeNodeFactory::getInstance($bs["id"]);
559  $level_data = $skill->getLevelData();
560 
561 
562  $title = $sep = "";
563  $description = "";
564  $found = false;
565  foreach ($path as $p) {
566  if ($found) {
567  $title .= $sep . $p["title"];
568  $sep = " > ";
569  $description = $p["description"];
570  }
571  if ($a_top_skill_id == $p["child"]) {
572  $found = true;
573  }
574  }
575  if (empty($title)) {
576  $title = $lng->txt("skmg_skill_overview");
577  }
578 
579  // skill description
580  $panel_comps[] = $this->ui_fac->legacy($this->getBasicSkillDescription((string) $description));
581 
582 
583  // skill level description
584  $skl_lvl_desc = $this->getSkillLevelDescription($skill);
585  if (!empty($skl_lvl_desc)) {
586  $acc = new ilAccordionGUI();
587  $acc->setBehaviour(ilAccordionGUI::ALL_CLOSED);
588  $acc->addItem($lng->txt('skmg_skill_levels'), $skl_lvl_desc);
589  $panel_comps[] = $this->ui_fac->legacy($acc->getHTML());
590  }
591  $prof_comp_head_rendered = false;
592  $has_at_least_one_entry = false;
593  if ($this->getProfileId() > 0) {
594  if ($this->getNonHistoricGapModeView()) {
595  if (!empty($self_eval_gap_item_prof = $this->getSelfEvalGapItem($level_data, $bs["tref"]))) {
596  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_SELF));
597  $has_at_least_one_entry = true;
598  }
599  $panel_comps[] = $this->ui_fac->legacy($self_eval_gap_item_prof);
600  } else {
601  // get all self eval entries and render them
602  $self_eval_entries_latest = $this->getLatestEntriesForSkillHTML(
603  $a_top_skill_id,
604  $bs,
605  $skill,
606  $user,
608  $level_data
609  );
610  $self_eval_entries_non_latest = $this->getNonLatestEntriesForSkillHTML(
611  $a_top_skill_id,
612  $bs,
613  $skill,
614  $user,
616  $level_data
617  );
618 
619  if (!empty($self_eval_entries_latest)) {
620  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_SELF));
621  $has_at_least_one_entry = true;
622  }
623  $panel_comps[] = $this->ui_fac->legacy($self_eval_entries_latest);
624  $panel_comps[] = $this->ui_fac->legacy($self_eval_entries_non_latest);
625  }
626 
627  if (!$this->skmg_settings->getHideProfileBeforeSelfEval() ||
628  ilBasicSkill::hasSelfEvaluated($user->getId(), $bs["id"], $bs["tref"])) {
629  if ($this->getFilter()->showTargetLevel()) {
630  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_OTHERS));
631  $prof_comp_head_rendered = true;
632  $panel_comps[] = $this->ui_fac->legacy($this->getProfileTargetItem($this->getProfileId(), $level_data, $bs["tref"]));
633  }
634  }
635  }
636 
637  if ($this->getNonHistoricGapModeView()) {
638  if (!empty($actual_gap_item = $this->getActualGapItem($level_data, $bs["tref"]))) {
639  $panel_comps[] = $this->ui_fac->legacy($actual_gap_item);
640  $has_at_least_one_entry = true;
641  }
642  if ($this->getProfileId() == 0) {
643  if (!empty($self_eval_gap_item_non_prof = $this->getSelfEvalGapItem($level_data, $bs["tref"]))) {
644  $panel_comps[] = $this->ui_fac->legacy($self_eval_gap_item_non_prof);
645  $has_at_least_one_entry = true;
646  }
647  }
648  } else {
649  if ($this->getProfileId() > 0) {
650  // get all non-self eval entries and render them
651  $object_entries_latest = $this->getLatestEntriesForSkillHTML(
652  $a_top_skill_id,
653  $bs,
654  $skill,
655  $user,
657  $level_data
658  );
659  $object_entries_non_latest = $this->getNonLatestEntriesForSkillHTML(
660  $a_top_skill_id,
661  $bs,
662  $skill,
663  $user,
665  $level_data
666  );
667 
668  if (!empty($object_entries_latest) && !$prof_comp_head_rendered) {
669  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_OTHERS));
670  }
671  if (!empty($object_entries_latest)) {
672  $has_at_least_one_entry = true;
673  }
674  $panel_comps[] = $this->ui_fac->legacy($object_entries_latest);
675  $panel_comps[] = $this->ui_fac->legacy($object_entries_non_latest);
676  } else {
677  // get all skill entries and render them
678  $all_entries_latest = $this->getLatestEntriesForSkillHTML(
679  $a_top_skill_id,
680  $bs,
681  $skill,
682  $user,
684  $level_data
685  );
686  $all_entries_non_latest = $this->getNonLatestEntriesForSkillHTML(
687  $a_top_skill_id,
688  $bs,
689  $skill,
690  $user,
692  $level_data
693  );
694 
695  if (!empty($all_entries_latest) && !$prof_comp_head_rendered) {
696  $panel_comps[] = $this->ui_fac->legacy($this->getSkillEntriesHeader(ilBasicSkill::EVAL_BY_OTHERS));
697  }
698  if (!empty($all_entries_latest)) {
699  $has_at_least_one_entry = true;
700  }
701  $panel_comps[] = $this->ui_fac->legacy($all_entries_latest);
702  $panel_comps[] = $this->ui_fac->legacy($all_entries_non_latest);
703  }
704  }
705 
706  if (!$has_at_least_one_entry) {
707  $panel_comps[] = $this->ui_fac->legacy("<br/>" . $lng->txt("skmg_no_skill_entries"));
708  }
709 
710  // suggested resources
711 
712  $sub = $this->ui_fac->panel()->sub($title, $panel_comps);
713  if ($this->getFilter()->showMaterialsRessources() && $this->getProfileId() > 0
714  && $res = $this->getSuggestedResourcesForProfile($level_data, $bs["id"], $bs["tref"], $this->gap_mode_obj_id)) {
715  $sub = $sub->withFurtherInformation($res);
716  } elseif ($this->getFilter()->showMaterialsRessources() && $this->getProfileId() == 0 && !$this->gap_mode_obj_id) {
717  // no profile, just list all resources and only in global view
718  $sugg = $this->getAllSuggestedResources($bs["id"], $bs["tref"]);
719  if ($sugg) {
720  $sub = $sub->withFurtherInformation($sugg);
721  }
722  }
723  if ($a_edit) {
724  $actions = [];
725  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "skill_id", $a_top_skill_id);
726  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "tref_id", $bs["tref"]);
727  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "basic_skill_id", $bs["id"]);
728  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "list_mode", $this->requested_list_mode);
729  if ($this->use_materials) {
730  $actions[] = $this->ui_fac->button()->shy(
731  $lng->txt('skmg_assign_materials'),
732  $ilCtrl->getLinkTargetByClass("ilpersonalskillsgui", "assignMaterials")
733  );
734  }
735  $actions[] = $this->ui_fac->button()->shy(
736  $lng->txt('skmg_self_evaluation'),
737  $ilCtrl->getLinkTargetByClass("ilpersonalskillsgui", "selfEvaluation")
738  );
739  $sub = $sub->withActions($this->ui_fac->dropdown()->standard($actions)->withLabel($lng->txt("actions")));
740  }
741 
742  $sub_panels[] = $sub;
743 
744  // materials
745  if ($this->mode != "gap" && $this->getFilter()->showMaterialsRessources() && $this->use_materials) {
746  $mat = $this->getMaterials($level_data, $bs["tref"], $user->getId());
747  if ($mat) {
748  $sub_panels[] = $mat;
749  }
750  }
751 
752  $tpl->parseCurrentBlock();
753  }
754 
755  $des = $this->getSkillCategoryDescription($skill_id, $tref_id);
756 
757  //put the description of the skill category to the very top of the sub panels
758  $sub_panels = $this->ui_fac->legacy($des . $this->ui_ren->render($sub_panels));
759 
760  $panel = $this->ui_fac->panel()->standard(
761  ilSkillTreeNode::_lookupTitle($skill_id, $tref_id),
762  $sub_panels
763  );
764 
765  if ($a_edit && $this->getProfileId() == 0) {
766  $actions = [];
767 
768  $ilCtrl->setParameterByClass("ilpersonalskillsgui", "skill_id", $a_top_skill_id);
769  $actions[] = $this->ui_fac->button()->shy(
770  $lng->txt('skmg_remove_skill'),
771  $ilCtrl->getLinkTargetByClass("ilpersonalskillsgui", "confirmSkillRemove")
772  );
773 
774  $panel = $panel->withActions($this->ui_fac->dropdown()->standard($actions)->withLabel($lng->txt("actions")));
775  }
776 
777  return $this->ui_ren->render($panel);
778  }
779 
780 
784  public function getMaterialInfo(int $a_wsp_id, int $a_user_id): array
785  {
786  $ws_tree = new ilWorkspaceTree($a_user_id);
787  $ws_access = new ilWorkspaceAccessHandler();
788 
789  $obj_id = $ws_tree->lookupObjectId($a_wsp_id);
790  $caption = ilObject::_lookupTitle($obj_id);
791 
792  if (!$this->getOfflineMode()) {
793  $url = $ws_access->getGotoLink($a_wsp_id, $obj_id);
794  } else {
795  $url = $this->getOfflineMode() . "file_" . $obj_id . "/";
796 
797  // all possible material types for now
798  switch (ilObject::_lookupType($obj_id)) {
799  case "tstv":
800  $obj = new ilObjTestVerification($obj_id, false);
801  $url .= $obj->getOfflineFilename();
802  break;
803 
804  case "excv":
805  $obj = new ilObjExerciseVerification($obj_id, false);
806  $url .= $obj->getOfflineFilename();
807  break;
808 
809  case "crsv":
810  $obj = new ilObjCourseVerification($obj_id, false);
811  $url .= $obj->getOfflineFilename();
812  break;
813 
814  case "cmxv":
815  $obj = new ilObjCmiXapiVerification($obj_id, false);
816  $url .= $obj->getOfflineFilename();
817  break;
818 
819  case "ltiv":
820  $obj = new ilObjLTIConsumerVerification($obj_id, false);
821  $url .= $obj->getOfflineFilename();
822  break;
823 
824  case "scov":
825  $obj = new ilObjSCORMVerification($obj_id, false);
826  $url .= $obj->getOfflineFilename();
827  break;
828 
829  case "file":
830  $file = new ilObjFile($obj_id, false);
831  $url .= $file->getFileName();
832  break;
833  }
834  }
835 
836  return array($caption, $url, $obj_id);
837  }
838 
839  public function addSkill(): void
840  {
841  $ilCtrl = $this->ctrl;
842  $ilUser = $this->user;
843  $lng = $this->lng;
844 
845  $this->personal_manager->addPersonalSkill($ilUser->getId(), $this->requested_node_id);
846 
847  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_object_modified"));
848  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
849  $ilCtrl->redirect($this, "listSkills");
850  }
851 
852  public function confirmSkillRemove(): void
853  {
854  $lng = $this->lng;
855  $tpl = $this->tpl;
856  $ilCtrl = $this->ctrl;
857 
858  if ($this->requested_skill_id > 0) {
859  $this->requested_skill_ids[] = $this->requested_skill_id;
860  }
861  if (empty($this->requested_skill_ids)) {
862  $this->tpl->setOnScreenMessage('info', $lng->txt("no_checkbox"), true);
863  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
864  $ilCtrl->redirect($this, "listSkills");
865  } else {
866  $cgui = new ilConfirmationGUI();
867  $cgui->setFormAction($ilCtrl->getFormAction($this));
868  $cgui->setHeaderText($lng->txt("skmg_really_remove_skills"));
869  $cgui->setCancel($lng->txt("cancel"), "listSkills");
870  $cgui->setConfirm($lng->txt("remove"), "removeSkills");
871 
872  foreach ($this->requested_skill_ids as $i) {
873  $cgui->addItem("id[]", (string) $i, ilSkillTreeNode::_lookupTitle($i));
874  }
875 
876  $tpl->setContent($cgui->getHTML());
877  }
878  }
879 
880  public function removeSkills(): void
881  {
882  $ilCtrl = $this->ctrl;
883  $ilUser = $this->user;
884  $lng = $this->lng;
885 
886  if (!empty($this->requested_skill_ids)) {
887  foreach ($this->requested_skill_ids as $n_id) {
888  $this->personal_manager->removePersonalSkill($ilUser->getId(), $n_id);
889  }
890  }
891 
892  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_object_modified"));
893  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
894  $ilCtrl->redirect($this, "listSkills");
895  }
896 
897 
898  //
899  // Materials assignments
900  //
901 
905  public function assignMaterials(): void
906  {
907  $ilCtrl = $this->ctrl;
908  $lng = $this->lng;
909  $tpl = $this->tpl;
910  $ilToolbar = $this->toolbar;
911  $ilTabs = $this->tabs;
912 
913  $cmd = ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles))
914  ? "render"
915  : "listAssignedProfile";
916  $ilTabs->setBackTarget(
917  $lng->txt("back"),
918  $ilCtrl->getLinkTarget($this, $cmd)
919  );
920 
921  $ilCtrl->saveParameter($this, "skill_id");
922  $ilCtrl->saveParameter($this, "basic_skill_id");
923  $ilCtrl->saveParameter($this, "tref_id");
924 
925  $tpl->setTitle(ilSkillTreeNode::_lookupTitle($this->requested_skill_id));
926  $tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_" .
927  ilSkillTreeNode::_lookupType($this->requested_skill_id) .
928  ".svg"));
929 
930  // basic skill selection
931  $vtree = $this->tree_repo->getVirtualTreeForNodeId($this->requested_skill_id);
932  $tref_id = 0;
933  $skill_id = $this->requested_skill_id;
934  if (ilSkillTreeNode::_lookupType($this->requested_skill_id) == "sktr") {
935  $tref_id = $this->requested_skill_id;
936  $skill_id = ilSkillTemplateReference::_lookupTemplateId($this->requested_skill_id);
937  }
938  $bs = $vtree->getSubTreeForCSkillId($skill_id . ":" . $tref_id, true);
939 
940  $options = [];
941  foreach ($bs as $b) {
942  $options[$b["skill_id"]] = ilSkillTreeNode::_lookupTitle((int) $b["skill_id"]);
943  }
944 
945  $cur_basic_skill_id = ($this->requested_basic_skill_id > 0)
946  ? $this->requested_basic_skill_id
947  : key($options);
948 
949  $ilCtrl->setParameter($this, "basic_skill_id", $cur_basic_skill_id);
950 
951  if (count($options) > 1) {
952  $si = new ilSelectInputGUI($lng->txt("skmg_skill"), "basic_skill_id");
953  $si->setOptions($options);
954  $si->setValue($cur_basic_skill_id);
955  $ilToolbar->addInputItem($si, true);
956  $ilToolbar->addFormButton(
957  $lng->txt("select"),
958  "assignMaterials"
959  );
960 
961  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
962  }
963 
964  $table = $this->table_manager->getAssignMaterialsTable(
965  $this->requested_skill_id,
966  $this->requested_tref_id,
967  $cur_basic_skill_id
968  )->getComponent();
969 
970  $tpl->setContent($this->ui_ren->render($table));
971  }
972 
973 
977  public function assignMaterial(): void
978  {
979  $ilCtrl = $this->ctrl;
980  $ilUser = $this->user;
981  $lng = $this->lng;
982  $tpl = $this->tpl;
983  $ilTabs = $this->tabs;
985  $ui = $this->ui;
986 
987  $message = "";
988  if (!$ilSetting->get("disable_personal_workspace")) {
989  $url = 'ilias.php?baseClass=ilDashboardGUI&amp;cmd=jumpToWorkspace';
990  $mbox = $ui->factory()->messageBox()->info($lng->txt("skmg_ass_materials_from_workspace"))
991  ->withLinks([$ui->factory()->link()->standard(
992  $lng->txt("personal_resources"),
993  $url
994  )]);
995  $message = $ui->renderer()->render($mbox);
996  }
997 
998  if ($this->requested_table_assign_materials_action === "assignMaterials"
999  && !empty($this->requested_table_assign_materials_level_ids)) {
1000  $ilCtrl->setParameter($this, "level_id", $this->requested_table_assign_materials_level_ids[0]);
1001  }
1002  $ilCtrl->saveParameter($this, "skill_id");
1003  $ilCtrl->saveParameter($this, "level_id");
1004  $ilCtrl->saveParameter($this, "tref_id");
1005  $ilCtrl->saveParameter($this, "basic_skill_id");
1006 
1007  $ilTabs->setBackTarget(
1008  $lng->txt("back"),
1009  $ilCtrl->getLinkTarget($this, "assignMaterials")
1010  );
1011 
1012 
1013  $exp = new ilWorkspaceExplorerGUI($ilUser->getId(), $this, "assignMaterial", $this, "");
1014  $exp->setTypeWhiteList(array("blog", "wsrt", "wfld", "file", "tstv", "excv"));
1015  $exp->setSelectableTypes(array("file", "tstv", "excv"));
1016  $exp->setSelectMode("wsp_ids", true);
1017  if ($exp->handleCommand()) {
1018  return;
1019  }
1020 
1021  // fill template
1022  $mtpl = new ilTemplate("tpl.materials_selection.html", true, true, "components/ILIAS/Skill");
1023  $mtpl->setVariable("EXP", $exp->getHTML());
1024 
1025  // toolbars
1026  $tb = new ilToolbarGUI();
1027  $tb->addFormButton(
1028  $lng->txt("select"),
1029  "selectMaterial"
1030  );
1031  $tb->setFormAction($ilCtrl->getFormAction($this));
1032  $tb->setOpenFormTag(true);
1033  $tb->setCloseFormTag(false);
1034  $mtpl->setVariable("TOOLBAR1", $tb->getHTML());
1035  $tb->setOpenFormTag(false);
1036  $tb->setCloseFormTag(true);
1037  $mtpl->setVariable("TOOLBAR2", $tb->getHTML());
1038 
1039  $tpl->setContent($message . $mtpl->get());
1040  }
1041 
1042  public function selectMaterial(): void
1043  {
1044  $ilCtrl = $this->ctrl;
1045  $ilUser = $this->user;
1046  $lng = $this->lng;
1047 
1048 
1049  if (!empty($this->requested_wsp_ids)) {
1050  foreach ($this->requested_wsp_ids as $w) {
1051  $this->assigned_material_manager->assignMaterial(
1052  $ilUser->getId(),
1057  $w
1058  );
1059  }
1060  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_obj_modified"), true);
1061  }
1062 
1063  $ilCtrl->saveParameter($this, "skill_id");
1064  $ilCtrl->saveParameter($this, "level_id");
1065  $ilCtrl->saveParameter($this, "tref_id");
1066  $ilCtrl->saveParameter($this, "basic_skill_id");
1067 
1068  $ilCtrl->redirect($this, "assignMaterials");
1069  }
1070 
1071  public function removeMaterial(): void
1072  {
1073  $ilCtrl = $this->ctrl;
1074  $ilUser = $this->user;
1075  $lng = $this->lng;
1076 
1077  if ($this->requested_table_assign_materials_action === "removeMaterial"
1078  && !empty($this->requested_table_assign_materials_level_ids)
1079  && $this->requested_table_assign_materials_wsp_id !== 0) {
1080  $this->assigned_material_manager->removeAssignedMaterial(
1081  $ilUser->getId(),
1083  (int) $this->requested_table_assign_materials_level_ids[0],
1084  $this->requested_table_assign_materials_wsp_id
1085  );
1086  $this->tpl->setOnScreenMessage('success', $lng->txt("msg_obj_modified"), true);
1087  }
1088  $ilCtrl->redirect($this, "assignMaterials");
1089  }
1090 
1091 
1092  //
1093  // Self evaluation
1094  //
1095 
1096  public function selfEvaluation(): void
1097  {
1098  $ilCtrl = $this->ctrl;
1099  $lng = $this->lng;
1100  $tpl = $this->tpl;
1101  $ilToolbar = $this->toolbar;
1102  $ilTabs = $this->tabs;
1103 
1104  $cmd = ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles))
1105  ? "render"
1106  : "listAssignedProfile";
1107  $ilTabs->setBackTarget(
1108  $lng->txt("back"),
1109  $ilCtrl->getLinkTarget($this, $cmd)
1110  );
1111 
1112  $ilCtrl->saveParameter($this, "skill_id");
1113  $ilCtrl->saveParameter($this, "basic_skill_id");
1114  $ilCtrl->saveParameter($this, "tref_id");
1115 
1116  $tpl->setTitle(ilSkillTreeNode::_lookupTitle($this->requested_skill_id));
1117  $tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_" .
1118  ilSkillTreeNode::_lookupType($this->requested_skill_id) .
1119  ".svg"));
1120 
1121  // basic skill selection
1122  $vtree = $this->tree_repo->getVirtualTreeForNodeId($this->requested_skill_id);
1123  $tref_id = 0;
1124  $skill_id = $this->requested_skill_id;
1125  if (ilSkillTreeNode::_lookupType($this->requested_skill_id) == "sktr") {
1126  $tref_id = $this->requested_skill_id;
1127  $skill_id = ilSkillTemplateReference::_lookupTemplateId($this->requested_skill_id);
1128  }
1129  $bs = $vtree->getSubTreeForCSkillId($skill_id . ":" . $tref_id, true);
1130 
1131 
1132  $options = [];
1133  foreach ($bs as $b) {
1134  $options[$b["skill_id"]] = ilSkillTreeNode::_lookupTitle((int) $b["skill_id"]);
1135  }
1136 
1137  $cur_basic_skill_id = ($this->requested_basic_skill_id > 0)
1138  ? $this->requested_basic_skill_id
1139  : key($options);
1140 
1141  $ilCtrl->setParameter($this, "basic_skill_id", $cur_basic_skill_id);
1142 
1143  if (count($options) > 1) {
1144  $si = new ilSelectInputGUI($lng->txt("skmg_skill"), "basic_skill_id");
1145  $si->setOptions($options);
1146  $si->setValue($cur_basic_skill_id);
1147  $ilToolbar->addInputItem($si, true);
1148  $ilToolbar->addFormButton(
1149  $lng->txt("select"),
1150  "selfEvaluation"
1151  );
1152 
1153  $ilToolbar->setFormAction($ilCtrl->getFormAction($this));
1154  }
1155 
1156  $form = $this->getSelfEvaluationForm($cur_basic_skill_id);
1157  $tpl->setContent($this->ui_ren->render($form));
1158  }
1159 
1160  protected function getSelfEvaluationForm(int $cur_basic_skill_id): Form
1161  {
1162  $top_skill_id = $this->requested_skill_id;
1163  $tref_id = $this->requested_tref_id;
1164  $basic_skill_id = $cur_basic_skill_id;
1165 
1166  $self_eval = $this->ui_fac->input()->field()->radio($this->lng->txt("skmg_self_evaluation"))
1167  ->withRequired(true);
1168 
1169  $current_level_id = $this->self_evaluation_manager->getSelfEvaluation(
1170  $this->user->getId(),
1171  $top_skill_id,
1172  $tref_id,
1173  $basic_skill_id
1174  );
1175  $skill = \ilSkillTreeNodeFactory::getInstance($basic_skill_id);
1176  foreach ($skill->getLevelData() as $level) {
1177  $self_eval = $self_eval->withOption((string) $level["id"], $level["title"], $level["description"]);
1178  if ($current_level_id == $level["id"]) {
1179  $self_eval = $self_eval->withValue($level["id"]);
1180  }
1181  }
1182 
1183  $tree_id = $this->tree_repo->getTreeIdForNodeId($basic_skill_id);
1184  $node_manager = $this->internal_manager->getTreeNodeManager($tree_id);
1185  $section_title = $node_manager->getWrittenPath($basic_skill_id);
1186  $section_inputs = ["self_eval" => $self_eval];
1187  $section = $this->ui_fac->input()->field()->section(
1188  $section_inputs,
1189  $section_title
1190  );
1191 
1192  $form_action = $this->ctrl->getFormAction($this, "saveSelfEvaluation");
1193  return $this->ui_fac->input()->container()->form()->standard($form_action, ["section" => $section]);
1194  }
1195 
1196  public function saveSelfEvaluation(): void
1197  {
1198  $ilCtrl = $this->ctrl;
1199  $ilUser = $this->user;
1200  $lng = $this->lng;
1201 
1202  $ilCtrl->setParameter($this, "basic_skill_id", $this->requested_basic_skill_id);
1203  $form = $this->getSelfEvaluationForm($this->requested_basic_skill_id);
1204  $ilCtrl->clearParameterByClass("ilpersonalskillsgui", "basic_skill_id");
1205  $cmd = ($this->requested_list_mode == self::LIST_SELECTED || empty($this->user_profiles))
1206  ? "render" : "listAssignedProfile";
1207 
1208  if ($this->request->getMethod() === "POST") {
1209  $form = $form->withRequest($this->request);
1210  $data = $form->getData();
1211  if (isset($data["section"]) && is_array($data["section"]) && !empty($data["section"]["self_eval"])) {
1212  $this->self_evaluation_manager->saveSelfEvaluation(
1213  $ilUser->getId(),
1217  (int) $data["section"]["self_eval"]
1218  );
1219  $this->tpl->setOnScreenMessage("success", $lng->txt("msg_obj_modified"), true);
1220  } else {
1221  $this->tpl->setContent($this->ui_ren->render($form));
1222  $this->tpl->setTitle(ilSkillTreeNode::_lookupTitle($this->requested_skill_id));
1223  $this->tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_" .
1224  ilSkillTreeNode::_lookupType($this->requested_skill_id) .
1225  ".svg"));
1226  $this->tabs->clearTargets();
1227  $this->tabs->setBackTarget(
1228  $lng->txt("back"),
1229  $ilCtrl->getLinkTarget($this, $cmd)
1230  );
1231  return;
1232  }
1233  }
1234 
1235  $ilCtrl->redirect($this, $cmd);
1236  }
1237 
1238  public function listSkillsForAdd(): void
1239  {
1240  $ilCtrl = $this->ctrl;
1241  $lng = $this->lng;
1242  $tpl = $this->tpl;
1243  $ilTabs = $this->tabs;
1244 
1245 
1246  $ilCtrl->setParameter($this, "list_mode", self::LIST_SELECTED);
1247  $ilTabs->setBackTarget(
1248  $lng->txt("back"),
1249  $ilCtrl->getLinkTarget($this, "render")
1250  );
1251  $ilCtrl->clearParameterByClass(get_class($this), "list_mode");
1252 
1253  $exp = new ilPersonalSkillExplorerGUI($this, "listSkillsForAdd", $this, "addSkill");
1254  if ($exp->getHasSelectableNodes()) {
1255  if (!$exp->handleCommand()) {
1256  $tpl->setContent($exp->getHTML());
1257  }
1258  $this->tpl->setOnScreenMessage('info', $lng->txt("skmg_select_skill"));
1259  } else {
1260  $this->tpl->setOnScreenMessage('info', $lng->txt("skmg_no_nodes_selectable"));
1261  }
1262  }
1263 
1264  public function showProfiles(): void
1265  {
1266  $this->ctrl->redirectByClass("ilContSkillPresentationGUI", "showProfiles");
1267  }
1268 
1269  public function listAllProfilesForGap(): void
1270  {
1271  if (empty($this->cont_profiles)) {
1272  $this->tpl->setContent($this->showInfoBoxForProfiles());
1273  return;
1274  }
1275 
1276  $prof_list = $this->getProfilesListed($this->cont_profiles, true);
1277 
1278  $html = $this->showInfoBoxForProfiles() . $this->ui_ren->render($prof_list);
1279  $this->tpl->setContent($html);
1280  }
1281 
1282  public function listProfileForGap(): void
1283  {
1284  // needed fix for profiles in gap view, because there is no filter shown (yet)
1285  $this->getFilter()->clear();
1286  $this->tabs->clearTargets();
1287  $this->tabs->setBackTarget(
1288  $this->lng->txt("back"),
1289  $this->ctrl->getLinkTarget($this, "showProfiles")
1290  );
1291  $this->setProfileId($this->requested_profile_id);
1292  $this->tpl->setTitleIcon(ilUtil::getImagePath("standard/icon_skmg.svg"));
1293  $this->tpl->setTitle($this->profile_manager->lookupTitle($this->getProfileId()));
1294 
1295  $this->tpl->setContent($this->getGapAnalysisHTML());
1296  }
1297 
1298  public function listRecordsForGap(): void
1299  {
1300  if (empty($this->getObjectSkills())) {
1301  $this->tpl->setContent($this->showInfoBoxForRecords());
1302  return;
1303  }
1304 
1305  $this->tpl->setContent($this->getGapAnalysisHTML());
1306  }
1307 
1311  protected function getProfilesListed(array $profiles, bool $gap_mode = false): ILIAS\UI\Component\Panel\Listing\Listing
1312  {
1313  $prof_items = [];
1314 
1315  foreach ($profiles as $p) {
1316  $image_id = $p->getImageId();
1317  if ($image_id) {
1318  $identification = $this->storage->manage()->find($image_id);
1319  $src = $this->storage->consume()->src($identification);
1320  $image = $this->ui_fac->image()->responsive($src->getSrc(), $this->lng->txt("skmg_custom_image_alt"));
1321  } else {
1322  $image = $this->ui_fac->image()->responsive(
1323  "./assets/images/logo/ilias_logo_72x72.png",
1324  "ILIAS"
1325  );
1326  }
1327 
1328  $this->ctrl->setParameter($this, "profile_id", $p->getId());
1329  $link = $this->ui_fac->link()->standard(
1330  $p->getTitle(),
1331  $this->ctrl->getLinkTarget($this, $gap_mode ? "listProfileForGap" : "listAssignedProfile")
1332  );
1333  $this->ctrl->setParameter($this, "profile_id", "");
1334 
1335  $chart_value = $this->profile_completion_manager->getProfileProgress($this->user->getId(), $p->getId());
1336  $prof_item = $this->ui_fac->item()->standard($link)
1337  ->withDescription($p->getDescription())
1338  ->withLeadImage($image)
1339  ->withProgress($this->ui_fac->chart()->progressMeter()->standard(100, $chart_value));
1340 
1341  $prof_items[] = $prof_item;
1342  }
1343 
1344  $prof_list = $this->ui_fac->panel()->listing()->standard("", array(
1345  $this->ui_fac->item()->group("", $prof_items)
1346  ));
1347 
1348  return $prof_list;
1349  }
1350 
1351  protected function showInfoBoxForProfiles(): string
1352  {
1353  if (!empty($this->cont_profiles)) {
1354  $link = $this->ui_fac->link()->standard(
1355  $this->lng->txt("skmg_open_all_assigned_profiles"),
1356  $this->ctrl->getLinkTargetByClass(["ilDashboardGUI", "ilAchievementsGUI", "ilPersonalSkillsGUI"])
1357  );
1358  $box = $this->ui_fac->messageBox()->info($this->lng->txt("skmg_cont_profiles_info"))->withLinks([$link]);
1359  } else {
1360  $box = $this->ui_fac->messageBox()->info($this->lng->txt("skmg_cont_profiles_info_empty"));
1361  }
1362 
1363  return $this->ui_ren->render($box);
1364  }
1365 
1366  protected function showInfoBoxForRecords(): string
1367  {
1368  $box = $this->ui_fac->messageBox()->info($this->lng->txt("skmg_cont_records_info_empty"));
1369 
1370  return $this->ui_ren->render($box);
1371  }
1372 
1373  public function setGapAnalysisActualStatusModePerType(string $a_type, string $a_cat_title = ""): void
1374  {
1375  $this->gap_mode = "max_per_type";
1376  $this->gap_mode_type = $a_type;
1377  $this->gap_cat_title = $a_cat_title;
1378  $this->mode = "gap";
1379  }
1380 
1381  public function setGapAnalysisActualStatusModePerObject(int $a_obj_id, string $a_cat_title = ""): void
1382  {
1383  $this->gap_mode = "max_per_object";
1384  $this->gap_mode_obj_id = $a_obj_id;
1385  $this->gap_cat_title = $a_cat_title;
1386  $this->mode = "gap";
1387  }
1388 
1389  public function getGapAnalysisHTML(int $a_user_id = 0, ?array $a_skills = null): string
1390  {
1391  $ilUser = $this->user;
1392  $lng = $this->lng;
1393 
1394  // needed fix for profiles in gap view, because there is no filter shown (yet)
1395  $this->getFilter()->clear();
1396  if ($a_skills == null) {
1397  foreach ($this->getObjectSkills() as $s) {
1398  $a_skills[] = array(
1399  "base_skill_id" => $s->getBaseSkillId(),
1400  "tref_id" => $s->getTrefId()
1401  );
1402  }
1403  }
1404 
1405  // $this->setTabs("list_skills");
1406 
1407  if ($a_user_id == 0) {
1408  $user_id = $ilUser->getId();
1409  } else {
1410  $user_id = $a_user_id;
1411  }
1412 
1413  $skills = [];
1414  if ($this->getProfileId() > 0) {
1415  $this->profile_levels = $this->profile_manager->getSkillLevels($this->getProfileId());
1416  $skills = $this->profile_levels;
1417  } else {
1418  // order skills per virtual skill tree
1419  $vtree = $this->tree_service->getGlobalVirtualSkillTree();
1420  $a_skills = $vtree->getOrderedNodeset($a_skills, "base_skill_id", "tref_id");
1421 
1422  foreach ($a_skills as $s) {
1424  $skills[] = $this->cont_factory_service->containerSkill()->skill(
1425  (int) $s["base_skill_id"],
1426  (int) $s["tref_id"]
1427  );
1428  }
1429  }
1430 
1431  // get actual levels for gap analysis
1432  if ($this->getTriggerUserFilter() !== "") // this must not be the actual max level
1433  {
1434  $this->actual_levels = $this->profile_completion_manager->getLastLevelPerObjectAndTriggerUser(
1435  $user_id,
1436  $skills,
1437  $this->gap_mode_obj_id,
1438  $this->getTriggerUserFilter()
1439  );
1440  } else {
1441  $this->actual_levels = $this->profile_completion_manager->getActualMaxLevels(
1442  $user_id,
1443  $skills,
1444  $this->gap_mode,
1445  $this->gap_mode_type,
1446  $this->gap_mode_obj_id
1447  );
1448  $this->next_level_fuls = $this->profile_completion_manager->getActualNextLevelFulfilments(
1449  $user_id,
1450  $skills,
1451  $this->gap_mode,
1452  $this->gap_mode_type,
1453  $this->gap_mode_obj_id
1454  );
1455  }
1456 
1457  $bc_skills = [];
1458  $html = "";
1459  $not_all_self_evaluated = false;
1460 
1461  foreach ($skills as $s) {
1462  if ($this->skmg_settings->getHideProfileBeforeSelfEval() &&
1463  !ilBasicSkill::hasSelfEvaluated($this->user->getId(), $s->getBaseSkillId(), $s->getTrefId())) {
1464  $not_all_self_evaluated = true;
1465  }
1466 
1467  $path = $this->tree_service->getSkillTreePath($s->getBaseSkillId());
1468 
1469  // check draft
1470  foreach ($path as $p) {
1471  if ($p["status"] == ilSkillTreeNode::STATUS_DRAFT) {
1472  continue(2);
1473  }
1474  }
1475  $bc_skills[] = $s;
1476  $html .= $this->getSkillHTML($s->getBaseSkillId(), $user_id, false, $s->getTrefId());
1477  }
1478 
1479  if ($not_all_self_evaluated) {
1480  $box = $this->ui_fac->messageBox()->info($lng->txt("skmg_skill_needs_self_eval_box"));
1481  $html = $this->ui_ren->render($box) . $html;
1482  }
1483 
1484  // output bar charts
1485  $all_chart_html = $this->getBarChartHTML($bc_skills);
1486 
1487  if (!empty($all_chart_html)) {
1488  $pan = $this->ui_fac->panel()->standard(
1489  $lng->txt("skmg_bar_charts"),
1490  $this->ui_fac->legacy($all_chart_html)
1491  );
1492  $all_chart_html = $this->ui_ren->render($pan);
1493  }
1494 
1495  // list skills
1496 
1497  return $all_chart_html . $html;
1498  }
1499 
1503  protected function getBarChartHTML(array $skills): string
1504  {
1505  $lng = $this->lng;
1506 
1507  // dimension names
1508  $target_dim = $lng->txt("skmg_target_level");
1509  $eval_dim = $lng->txt("skmg_eval_type_1");
1510  if ($this->gap_cat_title != "") {
1511  $eval_dim = $this->gap_cat_title;
1512  } elseif ($this->gap_mode == "max_per_type") {
1513  $eval_dim = $lng->txt("objs_" . $this->gap_mode_type);
1514  } elseif ($this->gap_mode == "max_per_object") {
1515  $eval_dim = ilObject::_lookupTitle($this->gap_mode_obj_id);
1516  }
1517  $self_eval_dim = $lng->txt("skmg_self_evaluation");
1518 
1519  $incl_self_eval = false;
1520  $self_vals = [];
1521  if (!empty($this->getGapAnalysisSelfEvalLevels())) {
1522  $incl_self_eval = true;
1523  $self_vals = $this->getGapAnalysisSelfEvalLevels();
1524  }
1525 
1526  $chart_counter = 0;
1527  $bar_counter = 0;
1528  $tmp_labels = [];
1529  $all_chart_data = [];
1530  $render_eval_dim = false;
1531  foreach ($skills as $l) {
1532  $bs = new ilBasicSkill($l->getBaseSkillId());
1533  $levels = $bs->getLevelData();
1534  // filter out skills with no levels from chart
1535  if (empty($levels)) {
1536  continue;
1537  }
1538 
1539  $cnt = 0;
1540  $points = [];
1541  $tooltips = [];
1542  $labels = [0 => ""];
1543  foreach ($levels as $lv) {
1544  // points and tooltips
1545  $cnt++;
1546  $labels[] = $lv["title"];
1547  if ($this->getProfileId() > 0) {
1548  if ($l->getLevelId() == $lv["id"]) {
1549  $points[$target_dim] = [$cnt - 0.01, $cnt];
1550  $tooltips[$target_dim] = $lv["title"];
1551  } else {
1552  $points[$target_dim] = $points[$target_dim] ?? null;
1553  $tooltips[$target_dim] = $tooltips[$target_dim] ?? null;
1554  }
1555  }
1556  if ($this->actual_levels[$l->getBaseSkillId()][$l->getTrefId()] == $lv["id"]) {
1557  $perc = $this->next_level_fuls[$l->getBaseSkillId()][$l->getTrefId()] ?? 0.0;
1558  $points[$eval_dim] = $cnt + $perc;
1559  $tooltips[$eval_dim] = null;
1560  if ($perc > 0) {
1561  $tooltips[$eval_dim] = $lv["title"] . " + " . $perc * 100 . "%";
1562  }
1563  $render_eval_dim = true;
1564  } else {
1565  $points[$eval_dim] = $points[$eval_dim] ?? null;
1566  $tooltips[$eval_dim] = $tooltips[$eval_dim] ?? null;
1567  if (!is_null($points[$eval_dim])) {
1568  $render_eval_dim = true;
1569  }
1570  }
1571  if ($incl_self_eval) {
1572  if (($self_vals[$l->getBaseSkillId()][$l->getTrefId()] ?? 0) == $lv["id"]) {
1573  $points[$self_eval_dim] = $cnt;
1574  $tooltips[$self_eval_dim] = null;
1575  } else {
1576  $points[$self_eval_dim] = $points[$self_eval_dim] ?? null;
1577  $tooltips[$self_eval_dim] = $tooltips[$self_eval_dim] ?? null;
1578  }
1579  }
1580  }
1581 
1582  // do not show eval dimension if there is no data for it
1583  if (!$render_eval_dim) {
1584  unset($points[$eval_dim]);
1585  unset($tooltips[$eval_dim]);
1586  }
1587 
1588  /*
1589  * create new chart when number and title of the levels of the current skill are not identical with
1590  * the previous skill
1591  */
1592  if (!empty($tmp_labels) && $tmp_labels !== $labels) {
1593  $chart_counter++;
1594  $bar_counter = 0;
1595  }
1596  $tmp_labels = $labels;
1597 
1598  $all_chart_data[$chart_counter][$bar_counter]["item_title"] = ilBasicSkill::_lookupTitle(
1599  $l->getBaseSkillId(),
1600  $l->getTrefId()
1601  );
1602  $all_chart_data[$chart_counter][$bar_counter]["levels"] = $labels;
1603  $all_chart_data[$chart_counter][$bar_counter]["points"] = $points;
1604  $all_chart_data[$chart_counter][$bar_counter]["tooltips"] = $tooltips;
1605 
1606  $bar_counter++;
1607  }
1608 
1609  $all_chart_html = "";
1610  foreach ($all_chart_data as $chart_data) {
1611  $c_dimension = $this->data_fac->dimension()->cardinal($chart_data[0]["levels"]);
1612  $r_dimension = $this->data_fac->dimension()->range($c_dimension);
1613 
1614  // dimensions and bar configs
1615  $ds = [];
1616  $bars = [];
1617 
1618  if ($this->getProfileId() > 0) {
1619  $target_bar = new BarConfig();
1620  $target_bar = $target_bar->withRelativeWidth(1.1);
1621  $target_bar = $target_bar->withColor($this->data_fac->color("#333333"));
1622  $ds[$target_dim] = $r_dimension;
1623  $bars[$target_dim] = $target_bar;
1624  }
1625 
1626  if ($render_eval_dim) {
1627  $eval_bar = new BarConfig();
1628  $eval_bar = $eval_bar->withRelativeWidth(0.5);
1629  $eval_bar = $eval_bar->withColor($this->data_fac->color("#307C88"));
1630  if (ilObject::_lookupType($this->gap_mode_obj_id) == "tst") {
1631  $eval_bar = $eval_bar->withColor($this->data_fac->color("#d38000"));
1632  }
1633  $ds[$eval_dim] = $c_dimension;
1634  $bars[$eval_dim] = $eval_bar;
1635  }
1636 
1637  if ($incl_self_eval) {
1638  $self_eval_bar = new BarConfig();
1639  $self_eval_bar = $self_eval_bar->withRelativeWidth(0.5);
1640  $self_eval_bar = $self_eval_bar->withColor($this->data_fac->color("#557b2e"));
1641  $ds[$self_eval_dim] = $c_dimension;
1642  $bars[$self_eval_dim] = $self_eval_bar;
1643  }
1644 
1645  $dataset = $this->data_fac->dataset($ds);
1646 
1647  $render_chart = false;
1648  foreach ($chart_data as $a) {
1649  if ($render_eval_dim && !isset($a["points"][$eval_dim])) {
1650  $a["points"][$eval_dim] = null;
1651  $a["tooltips"][$eval_dim] = null;
1652  }
1653  $dataset = $dataset->withPoint($a["item_title"], $a["points"]);
1654  $dataset = $dataset->withAlternativeInformation($a["item_title"], $a["tooltips"]);
1655  foreach ($a["points"] as $dim => $p) {
1656  // render chart only if there are bars
1657  if (!is_null($p) && $dim != $target_dim) {
1658  $render_chart = true;
1659  }
1660  }
1661  }
1662 
1663  if ($render_chart) {
1664  $bar_chart = $this->ui_fac->chart()->bar()->horizontal(
1665  "",
1666  $dataset,
1667  $bars
1668  );
1669 
1670  $x_axis = new XAxis();
1671  $x_axis = $x_axis->withMaxValue(count($chart_data[0]["levels"]) - 1);
1673  $bar_chart = $bar_chart->withCustomXAxis($x_axis);
1674  $bar_chart = $bar_chart->withTitleVisible(false);
1675 
1676  $all_chart_html .= $this->ui_ren->render($bar_chart);
1677  }
1678  }
1679 
1680  return $all_chart_html;
1681  }
1682 
1683  public function getMaterials(array $a_levels, int $a_tref_id = 0, int $a_user_id = 0): ?\ILIAS\UI\Component\Panel\Sub
1684  {
1685  $ilUser = $this->user;
1686  $lng = $this->lng;
1687 
1688  if ($a_user_id == 0) {
1689  $a_user_id = $ilUser->getId();
1690  }
1691 
1692  // only render, if materials given
1693  $got_mat = false;
1694  foreach ($a_levels as $v) {
1695  $mat_cnt = $this->assigned_material_manager->countAssignedMaterials(
1696  $a_user_id,
1697  $a_tref_id,
1698  (int) $v["id"]
1699  );
1700  if ($mat_cnt > 0) {
1701  $got_mat = true;
1702  }
1703  }
1704  if (!$got_mat) {
1705  return null;
1706  }
1707 
1708  $item_groups = [];
1709  foreach ($a_levels as $k => $v) {
1710  $got_mat = false;
1711  $items = [];
1712  foreach ($this->assigned_material_manager->getAssignedMaterials(
1713  $a_user_id,
1714  $a_tref_id,
1715  (int) $v["id"]
1716  ) as $item) {
1717  $mat_data = $this->getMaterialInfo($item->getWorkspaceId(), $a_user_id);
1718  $title = $mat_data[0];
1719  $icon = $this->ui_fac->symbol()->icon()->standard(
1720  ilObject::_lookupType($mat_data[2]),
1721  $lng->txt("icon") . " " . $lng->txt(ilObject::_lookupType($mat_data[2]))
1722  );
1723  $link = $this->ui_fac->link()->standard($title, $mat_data[1]);
1724  $items[] = $this->ui_fac->item()->standard($link)->withLeadIcon($icon);
1725  $got_mat = true;
1726  }
1727  if ($got_mat) {
1728  $item_groups[] = $this->ui_fac->item()->group($v["title"], $items);
1729  }
1730  }
1731  $mat_panel = $this->ui_fac->panel()->sub(
1732  $lng->txt("skmg_materials"),
1733  $item_groups
1734  );
1735 
1736  return $mat_panel;
1737  }
1738 
1739  public function getProfileTargetItem(int $a_profile_id, array $a_levels, int $a_tref_id = 0): string
1740  {
1741  $lng = $this->lng;
1742 
1743  $profile_levels = $this->profile_manager->getSkillLevels($a_profile_id);
1744 
1745  $a_activated_levels = [];
1746 
1747  foreach ($a_levels as $k => $v) {
1748  foreach ($profile_levels as $pl) {
1749  if ($pl->getLevelId() == $v["id"] &&
1750  $pl->getBaseSkillId() == $v["skill_id"] &&
1751  $a_tref_id == $pl->getTrefId()) {
1752  $a_activated_levels[] = $pl->getLevelId();
1753  }
1754  }
1755  }
1756 
1757  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "components/ILIAS/Skill");
1758  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_activated_levels));
1759 
1760  $tpl->setVariable("TYPE", $lng->txt("skmg_target_level"));
1761  $tpl->setVariable("TITLE", "");
1762 
1763  return $tpl->get();
1764  }
1765 
1766  public function getActualGapItem(array $a_levels, int $a_tref_id = 0): string
1767  {
1768  $lng = $this->lng;
1769 
1770  $a_activated_levels = [];
1771  foreach ($a_levels as $k => $v) {
1772  if ($this->actual_levels[$v["skill_id"]][$a_tref_id] == $v["id"]) {
1773  $a_activated_levels[] = $v["id"];
1774  }
1775  }
1776 
1777  if (empty($a_activated_levels)) {
1778  return "";
1779  }
1780 
1781  $title = "";
1782  if ($this->gap_cat_title != "") {
1783  $title = $this->gap_cat_title;
1784  } elseif ($this->gap_mode == "max_per_type") {
1785  $title = $lng->txt("objs_" . $this->gap_mode_type);
1786  } elseif ($this->gap_mode == "max_per_object") {
1787  $title = ilObject::_lookupTitle($this->gap_mode_obj_id);
1788  }
1789 
1790  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "components/ILIAS/Skill");
1791  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_activated_levels));
1792 
1793  $type = 1;
1794  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_latest_" . $type));
1795  if ($type > 0) {
1796  $tpl->touchBlock("st" . $type);
1797  $tpl->touchBlock("stb" . $type);
1798  }
1799 
1800  if ($title != $lng->txt("skmg_eval_type_" . $type)) {
1801  $tpl->setVariable("TITLE", $title);
1802  }
1803 
1804  return $tpl->get();
1805  }
1806 
1807  public function getSelfEvalGapItem(array $a_levels, int $a_tref_id = 0): string
1808  {
1809  $lng = $this->lng;
1810 
1811  $self_vals = $this->getGapAnalysisSelfEvalLevels();
1812  if (empty($self_vals)) {
1813  return "";
1814  }
1815 
1816  $a_activated_levels = [];
1817  foreach ($a_levels as $k => $v) {
1818  if (isset($self_vals[$v["skill_id"]][$a_tref_id]) &&
1819  $self_vals[$v["skill_id"]][$a_tref_id] == $v["id"]) {
1820  $a_activated_levels[] = $v["id"];
1821  }
1822  }
1823 
1824  if (empty($a_activated_levels)) {
1825  return "";
1826  }
1827 
1828  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "components/ILIAS/Skill");
1829  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_activated_levels));
1830 
1831  $type = 3;
1832  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_latest_" . $type));
1833  if ($type > 0) {
1834  $tpl->touchBlock("st" . $type);
1835  $tpl->touchBlock("stb" . $type);
1836  }
1837 
1838  return $tpl->get();
1839  }
1840 
1846  public function getScaleBar(array $a_levels, $a_activated_levels): string
1847  {
1848  $vals = [];
1849 
1850  if (!is_array($a_activated_levels)) {
1851  $a_activated_levels = array($a_activated_levels);
1852  }
1853 
1854  foreach ($a_levels as $level) {
1855  $vals[$level["title"]] = (in_array($level["id"], $a_activated_levels));
1856  }
1857  $scale_bar = $this->ui_fac->chart()->scaleBar($vals);
1858 
1859  return $this->ui_ren->render($scale_bar);
1860  }
1861 
1862  public function getEvalItem(array $a_levels, array $a_level_entry, bool $is_latest = false): string
1863  {
1864  $lng = $this->lng;
1865  $ilAccess = $this->access;
1866 
1867  $tpl = new ilTemplate("tpl.skill_eval_item.html", true, true, "components/ILIAS/Skill");
1868  $tpl->setVariable("SCALE_BAR", $this->getScaleBar($a_levels, $a_level_entry["level_id"]));
1869 
1870  $type = Personal\SkillEval::TYPE_APPRAISAL;
1871 
1872  if ($a_level_entry["self_eval"] == 1) {
1873  $type = Personal\SkillEval::TYPE_SELF_EVAL;
1874  }
1875 
1876  if ($a_level_entry["trigger_obj_type"] == "tst") {
1877  $type = Personal\SkillEval::TYPE_MEASUREMENT;
1878  }
1879 
1881  $title = "";
1882  if ($a_level_entry["trigger_obj_id"] > 0) {
1883  if (ilObject::_exists($a_level_entry["trigger_ref_id"], true)) {
1884  $title = ilObject::_lookupTitle($a_level_entry["trigger_obj_id"]);
1885  } elseif (!empty($del_data = ilObjectDataDeletionLog::get($a_level_entry["trigger_obj_id"]))) {
1886  $title = $del_data["title"];
1887  } else {
1888  $title = ($a_level_entry["trigger_title"]) ?? "";
1889  }
1890  }
1891 
1892  if ($a_level_entry["trigger_ref_id"] > 0
1893  && $ilAccess->checkAccess("read", "", $a_level_entry["trigger_ref_id"])) {
1894  $title = "<a href='" . ilLink::_getLink($a_level_entry["trigger_ref_id"]) . "'>" . $title . "</a>";
1895  }
1896 
1897  if ($is_latest) {
1898  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_latest_" . $type));
1899  } else {
1900  $tpl->setVariable("TYPE", $lng->txt("skmg_eval_type_" . $type));
1901  }
1902  if ($type > 0) {
1903  $tpl->touchBlock("st" . $type);
1904  $tpl->touchBlock("stb" . $type);
1905  }
1906  $tpl->setVariable("TITLE", $title);
1907  $tpl->setVariable(
1908  "DATE",
1909  ilDatePresentation::formatDate(new ilDate($a_level_entry["status_date"], IL_CAL_DATETIME))
1910  );
1911 
1913 
1914  return $tpl->get();
1915  }
1916 
1917  protected function getLatestEntriesForSkillHTML(
1918  int $top_skill_id,
1919  array $bs,
1920  ilSkillTreeNode $skill,
1921  ilObjUser $user,
1922  int $eval_type,
1923  array $level_data
1924  ): string {
1925  $lng = $this->lng;
1926 
1927  $tpl = new ilTemplate("tpl.skill_entries_latest.html", true, true, "components/ILIAS/Skill");
1928 
1929  $user_entries = $skill->getAllHistoricLevelEntriesOfUser($bs["tref"], $user->getId(), $eval_type);
1930  $user_entries_filtered = $this->getFilteredEntriesForSkill(
1931  $user_entries,
1932  $top_skill_id,
1933  $bs,
1934  $user
1935  );
1936  if ($eval_type == ilBasicSkill::EVAL_BY_SELF) {
1937  $latest_entries = $this->getSelfEvalEntriesLatestOnly($user_entries_filtered);
1938  } else {
1939  $latest_entries = $this->getAllEntriesLatestOnly($user_entries_filtered);
1940  }
1941 
1942  $latest_entries_html = "";
1943  foreach ($latest_entries as $entry) {
1944  $latest_entries_html .= $this->ui_ren->render(
1945  $this->ui_fac->legacy($this->getEvalItem($level_data, $entry, true))
1946  );
1947  }
1948 
1949  if (!empty($latest_entries_html)) {
1950  $tpl->setVariable("SKILL_ENTRIES", $latest_entries_html);
1951 
1952  if (count($user_entries_filtered) != count($latest_entries)) {
1953  $tpl->setCurrentBlock("all_entries_button");
1954  $show_all_button = $this->ui_fac->button()->standard($lng->txt("skmg_show_all"), "#")
1955  ->withOnLoadCode(function ($id) {
1956  return "$('#$id').on('click', function() {SkillEntries.showNonLatest($id); return false;})";
1957  });
1958  $tpl->setVariable("BUTTON", $this->ui_ren->render($show_all_button));
1959  $tpl->parseCurrentBlock();
1960  }
1961 
1962  return $tpl->get();
1963  }
1964 
1965  return "";
1966  }
1967 
1969  int $top_skill_id,
1970  array $bs,
1971  ilSkillTreeNode $skill,
1972  ilObjUser $user,
1973  int $eval_type,
1974  array $level_data
1975  ): string {
1976  $lng = $this->lng;
1977  $tpl = new ilTemplate("tpl.skill_entries_non_latest.html", true, true, "components/ILIAS/Skill");
1978  $user_entries = $skill->getAllHistoricLevelEntriesOfUser($bs["tref"], $user->getId(), $eval_type);
1979  $user_entries_filtered = $this->getFilteredEntriesForSkill(
1980  $user_entries,
1981  $top_skill_id,
1982  $bs,
1983  $user
1984  );
1985  if ($eval_type == ilBasicSkill::EVAL_BY_SELF) {
1986  $non_latest_entries = $this->getSelfEvalEntriesWithoutLatest($user_entries_filtered);
1987  } else {
1988  $non_latest_entries = $this->getAllEntriesWithoutLatest($user_entries_filtered);
1989  }
1990 
1991  $non_latest_entries_filtered_html = "";
1992  foreach ($non_latest_entries as $entry) {
1993  $non_latest_entries_filtered_html .= $this->ui_ren->render(
1994  $this->ui_fac->legacy($this->getEvalItem($level_data, $entry, false))
1995  );
1996  }
1997 
1998  if (!empty($non_latest_entries_filtered_html)) {
1999  $tpl->setVariable("SKILL_ENTRIES", $non_latest_entries_filtered_html);
2000 
2001  $show_latest_button = $this->ui_fac->button()->standard($lng->txt("skmg_show_latest_entries"), "#")
2002  ->withOnLoadCode(function ($id) {
2003  return "$('#$id').on('click', function() {SkillEntries.hideNonLatest($id); return false;})";
2004  });
2005  $tpl->setVariable("BUTTON", $this->ui_ren->render($show_latest_button));
2006 
2007  return $tpl->get();
2008  }
2009 
2010  return "";
2011  }
2012 
2013  protected function getFilteredEntriesForSkill(
2014  array $entries,
2015  int $top_skill_id,
2016  array $bs,
2017  ilObjUser $user
2018  ): array {
2019  // get date of self evaluation
2020  $se_date = $this->self_evaluation_manager->getSelfEvaluationDate($user->getId(), $top_skill_id, $bs["tref"], $bs["id"]);
2021  $se_rendered = $se_date == "";
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 ($this->getTriggerUserFilter() !== "" && $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($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($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($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
$res
Definition: ltiservices.php:69
setGapAnalysisSelfEvalLevels(array $a_val)
setObjectSkills(int $a_obj_id, array $a_skills)
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ilObjUser $user=null,)
setTriggerUserFilter(string $trigger_user_filter)
$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...
Interface Observer Contains several chained tasks and infos about them.
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
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 _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.
$url
Definition: shib_logout.php:63
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:30
Builds a Color from either hex- or rgb values.
Definition: Factory.php:16
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.
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.
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:66
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)
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:43
applyFilterAssignedProfiles()
Apply filter for profiles view.
ilSkillLevelRepository $level_repo
Class ilObjFile.
global $DIC
Definition: shib_login.php:25
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)
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
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:32
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:24
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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)
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)
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