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