From feb121e20ca503777b3b4b3894ac4816daa221ec Mon Sep 17 00:00:00 2001 From: Keven Clausen Date: Wed, 29 Apr 2026 14:02:29 +0200 Subject: [PATCH 1/3] Feature Metadata --- .../classes/class.ilObjectMetaDataGUI.php | 3 +- ...class.ilObjLearningSequenceSettingsGUI.php | 44 +++++++++- .../class.ilLearningSequenceExporter.php | 27 ++++++ .../class.ilLearningSequenceImporter.php | 27 ++++++ .../classes/class.ilObjLearningSequence.php | 2 + .../class.ilObjLearningSequenceGUI.php | 85 ++++++++++++++++++- components/ILIAS/LearningSequence/module.xml | 1 + 7 files changed, 185 insertions(+), 4 deletions(-) diff --git a/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php b/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php index 3ee6b6716b1b..f42859c75b45 100755 --- a/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php +++ b/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php @@ -321,7 +321,8 @@ protected function isLOMAvailable(): bool 'cmix', 'mep', 'mep:mpg', - 'wiki' + 'wiki', + 'lso' ]) ); } diff --git a/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php b/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php index 16d3fed7f902..8b77db43697c 100755 --- a/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php +++ b/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php @@ -98,7 +98,7 @@ protected function buildForm( protected function buildFormElements( ilObjLearningSequence $lso, ILIAS\UI\Component\Input\Factory $if - ) { + ): array { $txt = fn($id) => $this->lng->txt($id); $settings = $lso->getLSSettings(); $activation = $lso->getLSActivation(); @@ -161,9 +161,38 @@ function ($values) { $this->refinery->always(false) ]) ); + // Metadata + $custom_md = $if->field()->checkbox($this->lng->txt('obj_tool_setting_custom_metadata')) + ->withValue((bool) ilContainer::_lookupContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + '0' + )) + ->withAdditionalTransformation( + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->bool(), + $this->refinery->always(false) + ]) + ); + //Taxonomies + $taxonomies = $if->field()->checkbox($this->lng->txt('obj_tool_setting_taxonomies')) + ->withValue((bool) ilContainer::_lookupContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + '0' + )) + ->withAdditionalTransformation( + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->bool(), + $this->refinery->always(false) + ]) + ); + $section_additional = $if->field()->section( [ - self::PROP_GALLERY => $gallery + self::PROP_GALLERY => $gallery, + ilObjectServiceSettingsGUI::CUSTOM_METADATA => $custom_md, + ilObjectServiceSettingsGUI::TAXONOMIES => $taxonomies ], $txt('obj_features') ); @@ -241,6 +270,17 @@ protected function update(): ?string } $lso->updateActivation($activation); + ilContainer::_writeContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + $values['additional'][ilObjectServiceSettingsGUI::CUSTOM_METADATA] ? '1' : '0' + ); + ilContainer::_writeContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + $values['additional'][ilObjectServiceSettingsGUI::TAXONOMIES] ? '1' : '0' + ); + $status = ilObjLearningSequenceAccess::isOffline($lso->getRefId()); $lso->getObjectProperties()->storePropertyIsOnline( new Online(! $status) diff --git a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php index c9122c7e633d..6da82b0e8347 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php +++ b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php @@ -97,6 +97,33 @@ public function getXmlExportTailDependencies(string $a_entity, string $a_target_ "entity" => "common", "ids" => $a_ids ]; + + // metadata + $md_ids = []; + foreach ($a_ids as $id) { + $md_ids[] = $id . ":0:lso"; + } + $res[] = [ + "component" => "components/ILIAS/MetaData", + "entity" => "md", + "ids" => $md_ids + ]; + + // taxonomies + $tax_ids = []; + foreach ($a_ids as $id) { + $t_ids = ilObjTaxonomy::getUsageOfObject((int) $id); + foreach ($t_ids as $t_id) { + $tax_ids[$t_id] = $t_id; + } + } + if ($tax_ids !== []) { + $res[] = [ + "component" => "components/ILIAS/Taxonomy", + "entity" => "tax", + "ids" => $tax_ids + ]; + } } // container pages diff --git a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php index fdadca6e450c..f0efaf3b7157 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php +++ b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php @@ -59,6 +59,19 @@ public function importXmlRepresentation(string $a_entity, string $a_id, string $ LSOPageType::EXTRO->value . ':' . $a_id, LSOPageType::EXTRO->value . ':' . (string) $this->obj->getId() ); + + $a_mapping->addMapping( + "components/ILIAS/Taxonomy", + "tax_item", + "lso:obj:" . $a_id, + (string) $this->obj->getId() + ); + $a_mapping->addMapping( + "components/ILIAS/Taxonomy", + "tax_item_obj_id", + "lso:obj:" . $a_id, + (string) $this->obj->getId() + ); } public function finalProcessing(ilImportMapping $a_mapping): void @@ -77,6 +90,20 @@ public function finalProcessing(ilImportMapping $a_mapping): void $new_obj_id = $this->obj->getId(); ilPageObject::_writeParentId($pg_type, (int) $new_pg_id, (int) $new_obj_id); } + + // taxonomy usages + $maps = $a_mapping->getMappingsOfEntity("components/ILIAS/LearningSequence", "lso"); + foreach ($maps as $old => $new) { + if ($old !== "new_id" && (int) $old > 0) { + $new_tax_ids = $a_mapping->getMapping("components/ILIAS/Taxonomy", "tax_usage_of_obj", (string) $old); + if ($new_tax_ids !== "") { + $tax_ids = explode(":", (string) $new_tax_ids); + foreach ($tax_ids as $tid) { + ilObjTaxonomy::saveUsage((int) $tid, (int) $new); + } + } + } + } } public function afterContainerImportProcessing(ilImportMapping $mapping): void diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php index 6e5353d5e0c8..24fa189e14d9 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php @@ -111,6 +111,8 @@ public function delete(): bool $this->getStateDB()->deleteFor($this->getRefId()); $this->getActivationDB()->deleteForRefId($this->getRefId()); + ilObjTaxonomy::deleteUsagesOfObject($this->getId()); + $this->raiseEvent(self::E_DELETE); return true; diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php index 85ecdb354eb6..666a0d9cf851 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php @@ -51,9 +51,11 @@ * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjSurveyGUI * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjFileUploadHandlerGUI * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjLearningSequenceEditIntroGUI, ilObjLearningSequenceEditExtroGUI + * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjectMetaDataGUI, ilTaxonomySettingsGUI, ilObjTaxonomyGUI */ -class ilObjLearningSequenceGUI extends ilContainerGUI implements ilCtrlBaseClassInterface +class ilObjLearningSequenceGUI extends ilContainerGUI implements ilCtrlBaseClassInterface, \ILIAS\Taxonomy\Settings\ModifierGUIInterface { + protected \ILIAS\Taxonomy\Service $taxonomy; public const CMD_VIEW = "view"; public const CMD_LEARNER_VIEW = "learnerView"; public const CMD_CONTENT = "manageContent"; @@ -228,6 +230,7 @@ public function __construct() $this->post_wrapper = $DIC->http()->wrapper()->post(); $this->refinery = $DIC->refinery(); $this->content_style = $DIC->contentStyle(); + $this->taxonomy = $DIC->taxonomy(); $this->help->setScreenIdComponent($this->type); $this->lng->loadLanguageModule($this->type); @@ -292,6 +295,7 @@ public function executeCommand(): void } $this->tabs->activateTab(self::TAB_SETTINGS); + $this->setEditTabs(); $this->ctrl->forwardCommand($this->getGUISettings()); break; case "ilobjlearningsequencecontentgui": @@ -350,6 +354,23 @@ public function executeCommand(): void $gui = $this->object->getLocalDI()["gui.learner.lp"]; $this->ctrl->forwardCommand($gui); break; + case "ilobjectmetadatagui": + $this->tabs->activateTab("meta_data"); + $mdgui = new ilObjectMetaDataGUI($this->object); + $this->ctrl->forwardCommand($mdgui); + break; + case "iltaxonomysettingsgui": + case "ilobjtaxonomygui": + $this->tabs->activateTab(self::TAB_SETTINGS); + $this->setEditTabs("taxonomy"); + $tax_gui = $this->taxonomy->gui()->getSettingsGUI( + $this->object->getId(), + $this->lng->txt("cntr_tax_settings_info"), + true, + $this + ); + $this->ctrl->forwardCommand($tax_gui); + break; case "ilobjlearningsequenceeditintrogui": $which_page = LSOPageType::INTRO; $which_tab = self::TAB_EDIT_INTRO; @@ -664,6 +685,40 @@ public function unparticipate(): void $this->ctrl->redirectByClass('ilObjLearningSequenceLearnerGUI', self::CMD_LEARNER_VIEW); } + protected function getSubServices(): array + { + $subs = [ + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + ilObjectServiceSettingsGUI::TAXONOMIES, + ilObjectServiceSettingsGUI::CALENDAR_CONFIGURATION, + ilObjectServiceSettingsGUI::TAG_CLOUD, + ilObjectServiceSettingsGUI::BADGES, + ilObjectServiceSettingsGUI::SKILLS + ]; + + return $subs; + } + + protected function setEditTabs(string $active_tab = "settings_misc"): void + { + $this->tabs->addSubTab( + "settings_misc", + $this->lng->txt("general"), + $this->ctrl->getLinkTargetByClass("ilobjlearningsequencesettingsgui", "settings") + ); + + if (ilContainer::_lookupContainerSetting( + $this->object->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + '0' + )) { + $this->taxonomy->gui()->addSettingsSubTab($this->object->getId()); + } + + $this->tabs->activateTab(self::TAB_SETTINGS); + $this->tabs->activateSubTab($active_tab); + } + protected function getTabs(): void { if ($this->checkAccess("read")) { @@ -689,6 +744,23 @@ protected function getTabs(): void $this->lng->txt(self::TAB_SETTINGS), $this->getLinkTarget(self::CMD_SETTINGS) ); + + // metadata + if (ilContainer::_lookupContainerSetting( + $this->object->getId(), + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + '0' + )) { + $mdgui = new ilObjectMetaDataGUI($this->object); + $mdtab = $mdgui->getTab(); + if ($mdtab) { + $this->tabs->addTab( + "meta_data", + $this->lng->txt("meta_data"), + $mdtab + ); + } + } } if ($this->checkAccess("read")) { @@ -771,6 +843,16 @@ protected function addSubTabsForContent(string $active): void $this->tabs->activateSubTab($active); } + public function getProperties(int $tax_id): array + { + return []; + } + + public function getActions(int $tax_id): array + { + return []; + } + protected function checkAccess(string $which): bool { return $this->access->checkAccess($which, "", $this->ref_id); @@ -878,6 +960,7 @@ function (array $c, ProfileData $v) use ($a_data, $udfs): array { $field_id = $field->getIdentifier(); $c[$v->getId()]['udf_' . $field_id] = (string) $v->getAdditionalFieldByIdentifier($field_id); } + return $c; }, [] ); diff --git a/components/ILIAS/LearningSequence/module.xml b/components/ILIAS/LearningSequence/module.xml index 51840c7d7923..7af63f1e5882 100755 --- a/components/ILIAS/LearningSequence/module.xml +++ b/components/ILIAS/LearningSequence/module.xml @@ -25,6 +25,7 @@ repository="1" group="lso" offline_handling="1" + amet="1" > rolf htlm From 5faf0a3c44d3eff4b160a23999850151cc1b0b47 Mon Sep 17 00:00:00 2001 From: Keven Clausen Date: Tue, 16 Jun 2026 07:43:54 +0200 Subject: [PATCH 2/3] LearningSequence: fully enable LOM metadata support --- ...ss.InitLOMForLearningSequenceMigration.php | 36 +++++++++++++++++++ .../class.ilLearningSequenceImporter.php | 7 ++++ .../classes/class.ilObjLearningSequence.php | 6 ++++ .../class.ilObjLearningSequenceGUI.php | 26 ++++++-------- .../class.ilObjLearningSequenceListGUI.php | 2 -- 5 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php diff --git a/components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php b/components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php new file mode 100644 index 000000000000..569ba1be25d2 --- /dev/null +++ b/components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php @@ -0,0 +1,36 @@ +value . ':' . (string) $this->obj->getId() ); + $a_mapping->addMapping( + 'components/ILIAS/MetaData', + 'md', + $a_id . ':0:lso', + (string) $this->obj->getId() . ':0:lso' + ); + $a_mapping->addMapping( "components/ILIAS/Taxonomy", "tax_item", diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php index 24fa189e14d9..a97c2694a7e2 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php @@ -85,6 +85,8 @@ public function create(): int if (!$id) { return 0; } + + $this->createMetaData(); $this->raiseEvent(self::E_CREATE); return $this->getId(); @@ -95,6 +97,8 @@ public function update(): bool if (!parent::update()) { return false; } + + $this->updateMetaData(); $this->raiseEvent(self::E_UPDATE); return true; @@ -102,6 +106,8 @@ public function update(): bool public function delete(): bool { + $this->deleteMetaData(); + if (!parent::delete()) { return false; } diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php index 666a0d9cf851..6df703000d4d 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php @@ -540,7 +540,9 @@ public function addToNavigationHistory(): void protected function getGUIInfo(): ilInfoScreenGUI { - return new ilInfoScreenGUI($this); + $info = new ilInfoScreenGUI($this); + $info->addMetaDataSections($this->object->getId(), 0, 'lso'); + return $info; } protected function getGUIPermissions(): ilPermissionGUI @@ -746,20 +748,14 @@ protected function getTabs(): void ); // metadata - if (ilContainer::_lookupContainerSetting( - $this->object->getId(), - ilObjectServiceSettingsGUI::CUSTOM_METADATA, - '0' - )) { - $mdgui = new ilObjectMetaDataGUI($this->object); - $mdtab = $mdgui->getTab(); - if ($mdtab) { - $this->tabs->addTab( - "meta_data", - $this->lng->txt("meta_data"), - $mdtab - ); - } + $mdgui = new ilObjectMetaDataGUI($this->object); + $mdtab = $mdgui->getTab(); + if ($mdtab) { + $this->tabs->addTab( + "meta_data", + $this->lng->txt("meta_data"), + $mdtab + ); } } diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php index 345ff97a2806..c47ed4bbfd8c 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php @@ -18,8 +18,6 @@ declare(strict_types=1); -declare(strict_types=1); - class ilObjLearningSequenceListGUI extends ilObjectListGUI { public function __construct() From 1f4acc765253b9c18c66ad69ddcd90382dfba827 Mon Sep 17 00:00:00 2001 From: Keven Clausen Date: Tue, 16 Jun 2026 08:19:31 +0200 Subject: [PATCH 3/3] CS-Fixer --- ...class.ilObjLearningSequenceSettingsGUI.php | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php b/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php index 7248d2ee9e90..820112cf1129 100755 --- a/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php +++ b/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php @@ -241,21 +241,21 @@ protected function update(): ?string $lso = $this->obj; $obj_props = $lso->getObjectProperties(); - ilContainer::_writeContainerSetting( - $lso->getId(), - ilObjectServiceSettingsGUI::CUSTOM_METADATA, - $values['additional'][ilObjectServiceSettingsGUI::CUSTOM_METADATA] ? '1' : '0' - ); - ilContainer::_writeContainerSetting( - $lso->getId(), - ilObjectServiceSettingsGUI::TAXONOMIES, - $values['additional'][ilObjectServiceSettingsGUI::TAXONOMIES] ? '1' : '0' - ); + ilContainer::_writeContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + $values['additional'][ilObjectServiceSettingsGUI::CUSTOM_METADATA] ? '1' : '0' + ); + ilContainer::_writeContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + $values['additional'][ilObjectServiceSettingsGUI::TAXONOMIES] ? '1' : '0' + ); - $status = ilObjLearningSequenceAccess::isOffline($lso->getRefId()); - $lso->getObjectProperties()->storePropertyIsOnline( - new Online(! $status) - ); + $status = ilObjLearningSequenceAccess::isOffline($lso->getRefId()); + $lso->getObjectProperties()->storePropertyIsOnline( + new Online(! $status) + ); $settings = $lso->getLSSettings() ->withMembersGallery($data['additional'][self::PROP_GALLERY]);