ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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 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;
86 protected ilObjUser $user;
88 protected ilTabsGUI $tabs;
91 protected Factory $ui_fac;
92 protected Renderer $ui_ren;
93 protected ServerRequestInterface $request;
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;
135 protected Table\TableManager $table_manager;
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;
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
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;
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;
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;
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;
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;
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 {
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;
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;
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;
981 $tpl = $this->tpl;
982 $ilTabs = $this->tabs;
983 $ilSetting = $this->setting;
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(),
1052 $this->requested_skill_id,
1053 $this->requested_tref_id,
1054 $this->requested_basic_skill_id,
1055 $this->requested_level_id,
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(),
1081 $this->requested_tref_id,
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(),
1213 $this->requested_skill_id,
1214 $this->requested_tref_id,
1215 $this->requested_basic_skill_id,
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
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 }
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
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();
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,
2378 $this->gap_mode,
2379 $this->gap_mode_type,
2380 $this->gap_mode_obj_id
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}
$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:33
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, $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:31
global $ilSetting
Definition: privfeed.php:31
global $DIC
Definition: shib_login.php:26
$url
Definition: shib_logout.php:68
$message
Definition: xapiexit.php:31