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