3

我目前正在为 ILIAS 编写一个插件。插件本身并不复杂,但它包含几个问题,而我认为我们可以让它变得更简单。

情况如下:我们在用户定义的元数据部分添加了一个全局高级元数据字段,带有双射标识符。该字段在名为 course 的存储库中被激活。我们已经使用基于ilUIHookPluginGUI.

代码是......好吧......自己看看。

首先,我们在插件的 ConfigGUI 设置中保存新元数据字段的 ID:

$field_settings = new ilSetting("foo");
$field_id_value = $field_settings->set("field_id",$_POST["field_id"]);

在我们扩展的类中,ilUIHookPluginGUI我们正在加载设置,如下所示,我们有字段的 ID:

$field_settings = new ilSetting("foo");
$field_id_value = $field_settings->get("field_id");

现在有趣的部分。有了这个ID和对象的ref_id(好吧,我们也加载对象来获取ObjId)我们可以加载课程设置的元数据字段的值:

$object = \ilObjectFactory::getInstanceByRefId($_GET[ 'ref_id' ]);
$obj_id = $object->getId();

$result = $DIC->database()->query("SELECT value FROM adv_md_values_text WHERE obj_id = '".$obj_id."' AND field_id = '".$field_id_value."'");
$value = $DIC->database()->fetchAssoc($result);
$is_active = $value['value'];

问题是......有没有更简单的方法来实现我的结果?

最好的,劳拉

4

1 回答 1

1

好问题。首先,请注意,我认为 ILIAS 中的高级元数据服务缺乏清晰的自述文件,该自述文件与接口为您的任务提供的接口挂钩。前段时间,我也不得不处理这项服务并遇到类似的问题。希望您的问题有助于更好地记录这一点,我自己也期待其他建议,因为我知道我的也不是很好。如果您有任何资源,我们将非常感谢您帮助推动引入良好的服务自述文件并推动服务使用具有清晰界面的存储库模式。

关于可以改进的问题:我在代码行中看到了三个主要问题:

  1. 在插件的配置中存储一个 ID。对于非技术人员,您的插件将无法配置。但是,对于您来说,这也容易出错,请考虑从测试安装到生产的导出导入内容。
  2. 通过查询而不是服务访问值。
  3. 在代码中使用新的静态函数使其无法测试。

第 1 步 让我们从第一个开始。请注意,如果不引入一个新问题(新查询),我是无法解决这个问题的。坏我知道。我希望有一个更好的解决方案,经过快速研究我没有找到。您存储 id,因为字段标题不是安全唯一的,对吗?这是正确的,但是,您可以考虑存储 field_title、record_title 和(可能)范围的三元组。请注意,您可能不需要范围,因为您想全局使用它。一个函数返回你和包含 field_id 和 record_id 的数组可能如下所示:

function getFieldAndRecordIdByFieldTitles($field_title, $record_title, $scope_title){
        $query = "select field.field_id,field.record_id from adv_mdf_definition as field
            INNER JOIN adv_md_record as record ON record.record_id = field.record_id
            INNER JOIN adv_md_record_scope as scope ON scope.record_id = field.record_id
            INNER JOIN object_reference as ref ON scope.ref_id = ref.ref_id
            INNER JOIN object_data as scope_data ON ref.obj_id = scope_data.obj_id
            WHERE field.title='$field_title' AND record.title='$record_title' AND scope_data.title = '$scope_title'";

        $set = $this->dic()->database()->query($query);
        if($row = $this->dic()->database()->fetchAssoc($set))
        {
            return array_values($row);
        }
    }

然后像这样获取您的值:

list($field_id,$record_id) = getFieldAndRecordIdByFieldTitles("my_field", "my_record", "my_scope");

请注意,我知道我在这里引入了一个新查询。抱歉,这是我能想到的最好的了。我相信你在那里找到了一个更好的解决方案,如果你的研究有点,让我们知道是否成功。但是,我们将在下一步中删除一个。

第 2 步 使用无证服务,从高级元数据中获取价值。由于您现在有了记录 id 和字段 id,您可以像这样:

$record_values = new ilAdvancedMDValues($record_id, $obj_id);
$record_values->read();
$ADTGroup = $ilAdvancedMDValues->getADTGroup();
$ADT = $ilADTGroup->getElement($field_id);
$value = $ADT->getText(); 
/**if you have text, others are possible, such as:              
        switch (true) {
            case ($ADT instanceof ilADTText):
                break;
            case ($ADT instanceof ilADTDate):
                $value = $ADT->getDate();
                break;
            case ($ADT instanceof ilADTExternalLink):
                $... = $ADT->getUrl();
                $... = $ADT->getTitle();
                break;
            case ($ADT instanceof ilADTInternalLink):
                $... = $ADT->setTargetRefId($value);
        }
**/

请注意,ADT 也未记录在案。可能有更好的方法来从中获得价值。

第 3 步 将您的静态和新的包装到一些可注入的依赖项中。我通常使用臃肿的构造函数模式来做到这一点。看起来像这样:

public function __construct(InjectedSettings $mySettings = null)
{
    if (!$mySettings) //Case in the default scenario
    {
        $this->mySettings = new InjectedSettings();
    } else //used e.g. for unit tests, where you can stuff the constructor with a mock
    {
        $this->mySettings = $mySettings;
    }
    $this->mySettings->doSometing();
}

请注意,这不是真正的 dep。注入,你仍然使用新的,但我认为使用 dep 是一个非常可行的修复。至少为 ilias 中的测试上下文注入。

这有帮助吗?我希望会有其他(更好的答案)。

于 2019-01-16T08:42:55.560 回答