x

主要章节

  1. LimeSurvey Cloud 与 LimeSurvey CE 对比
  2. 快速入门指南 - LimeSurvey 3.0+
  3. 软件安装
  4. 如何设计一个不错的调查(向导)
  5. 入门指南
  6. 管理 LimeSurvey
  7. 调查 - 说明
  8. 调查设置
  9. 问卷调查菜单
  10. 调查问卷结构
  11. 问题 - 简介
  12. 题组 - 简介
  13. 调查 - 管理
  14. 调查工具栏选项
  15. 多语言调查
  16. ExpressionScript 引擎 - 快速入门指南
  17. 其他和高级功能
  18. 常规问答
  19. 故障排除
  20. 变通方法
  21. 许可证
  22. 版本更改日志
  23. 插件
 Actions

插件

From LimeSurvey Manual

本页面可能为机器翻译,可能包含错误。 查看英文原文 · 改进此翻译
This page is a translated version of the page Plugins and the translation is 100% complete.

概览

LimeSurvey 能够通过插件添加功能。LimeSurvey 已内置大量核心插件。此外,请查看我们的第三方插件列表,将来也许您可以将自己的插件添加到其中!

插件允许用户自定义其安装的功能,同时仍可从定期的软件更新中获益。

本文档面向为自己或客户扩展 LimeSurvey 的开发人员;最终用户无法从本文档中获得帮助。

插件必须实现 iPlugin 接口。我们建议让您的插件类继承自 PluginBase 类。

插件是围绕事件机制开发的。

插件设置

通过继承,您可以受益于我们已为您实现的插件所需的通用功能。其中之一是 getPluginSettings 函数的实现。该函数必须返回一个描述用户配置选项的数组。

示例插件仅公开了 1 个可配置的设置,即它将显示的消息。

protected $settings = array(
    'logo' => array(
          'type' => 'logo',
          'path' => 'assets/logo.png'
     ),

     'message' => array(
          'type' => 'string',
          'label' => 'Message'
     )
);

该数组以每个设置的名称作为键,其值是包含所需元数据的数组。

支持的类型有:

  • logo
  • int(整数)
  • string(字母数字)
  • text
  • html
  • relevance
  • info
  • password
  • date
  • select

除 type 外,还有许多其他可用的键:

  • label,定义标签
  • default,定义未指定值时显示的值(仅适用于全局设置,不适用于调查设置)
  • current,定义当前值。
  • readOnly:将设置显示为只读
  • htmlOptions,输入部分的 htmlOptions(参见 Yii 手册 [[1]])
  • pluginOptions,用于某些设置(html 或 select):设置小部件选项
  • labelOptions:标签的 htmlOptions
  • controlOptions:标签和输入包装器的 htmlOptions
  • localized:如果为 true,则按语言存储该值。输入以 name[language] 的形式提交,并且 current 必须是以语言编码为索引的数组。
  • language:与 localized 配合使用。可以是单个语言编码,或者 (New in X.Y.Z ) 语言编码数组,以便为每种语言显示一个输入(参见本地化插件设置)

您可以在 exampleSettings 找到使用所有现有设置的插件示例

读取和写入插件设置

您可以直接在插件代码中读取和写入插件设置。

示例:

$mySetting = $this->get('mySetting');
$this->set('mySetting', $mySetting + 1);

如果设置恰好为 null,您可以获取一个默认值:

$mySetting = $this->get('mySetting', null, null, 10);  // 10 is default

特定于调查的插件设置

使用两个事件来创建特定于调查的插件设置:

  • newSurveySettings
  • beforeSurveySettings

为特定调查禁用插件的示例:

    public function init()
    {
        $this->subscribe('beforeSurveySettings');
        $this->subscribe('newSurveySettings');
        // Other events...
    }

    public function beforeSurveySettings()
    {
	    $event = $this->event;
	    $surveyId = intval($event->get('survey'));

        $event->set(
            "surveysettings.{$this->id}",
            [
                'name' => get_class($this),
                'settings' => [
                    'isActive' => [
                        'type' => 'boolean',
                        'label' => 'isActive',
                        'current' => $this->getIsActive($surveyId),
                        'help' => 'Activate plugin for this survey'
                    ],
                ]
            ]
        );
    }

    public function newSurveySettings()
    {
        $event = $this->event;
        foreach ($event->get('settings') as $name => $value)
        {
            $this->set($name, $value, 'Survey', $event->get('survey'), false);
        }
    }

    private function getIsActive(int $sid): bool
    {
        return (bool) $this->get('isActive', 'Survey', $sid, false);
    }

<span id="Localized_plugin_settings_ (New in 7.4 )">

本地化插件设置 (New in 7.4 )

若要为同一设置按调查语言分别显示一个输入框,请将 localized 设置为 true,并在 language 中传入语言列表。语言名称会添加到每个输入框的标签中。

    public function beforeSurveySettings()
    {
        $event = $this->event;
        $surveyId = intval($event->get('survey'));
        $survey = Survey::model()->findByPk($surveyId);

        $event->set(
            "surveysettings.{$this->id}",
            [
                'name' => get_class($this),
                'settings' => [
                    'errorText' => [
                        'type' => 'text',
                        'label' => $this->gT('Error text'),
                        'localized' => true,
                        'language' => $survey->getAllLanguages(),
                        // 以语言编码为索引的数组,例如 ['en' => '...', 'de' => '...']
                        'current' => $this->get('errorText', 'Survey', $surveyId, []),
                    ],
                ]
            ]
        );
    }

提交的值是以语言编码为索引的数组,因此上述示例中的 newSurveySettings 函数无需任何修改即可保存它。要读取当前语言的文本:

$errorTexts = $this->get('errorText', 'Survey', $surveyId, []);
$errorText = $errorTexts[App()->getLanguage()] ?? '';

事件

插件订阅事件,并可在事件触发时与 LimeSurvey 交互。有关当前可用事件的列表,请查看插件事件。

API

插件应仅通过 LimeSurvey 的“公共”API 来扩展 LimeSurvey。这意味着直接使用源代码中的类是不好的做法。虽然我们无法强制您不这样做,但每次我们发布小版本更新时,您的插件都可能会失效。

请尽可能仅通过此处描述的方法与 LimeSurvey 交互。事件也是如此。

从 PluginBase 扩展时,可通过 $this->api 使用 API 对象;否则,您可以从传递给插件构造函数的 PluginManager 实例中获取它。

可根据需求向 API 对象添加新函数。

<span id="Form_extension (New in 6 )">

表单扩展 (New in 6 )

简介

表单扩展系统是一种更通用的方式,可用于扩展 LimeSurvey 核心中的表单,而无需为每个表单添加新事件。

它由以下组件构成:

  • 名为 FormExtensionService 的全局模块
  • 一个 输入类 库,插件可将其添加到上述模块的初始化中
  • 一个 小部件,以及自定义渲染器,用于 LimeSurvey 的视图文件中

每个表单由一个 位置字符串 标识,格式如 <form name><dot><tab name>。示例:globalsettings.general 或 globalsettings.security。

采用不含 HTML 的基于类的系统,其目的是让插件作者无需在核心 HTML 更改时去更新 HTML。不过,如有需要,作者仍可使用 RawHtmlInput 类型。

在该系统中无法做到的一点是添加新的表单选项卡。

示例

若要通过插件向表单添加新的输入框,请在 init() 函数中使用以下代码:

TODO: 保存到插件设置中,而不是全局设置

// At top of file
use LimeSurvey\Libraries\FormExtension\Inputs\TextInput;
use LimeSurvey\Libraries\FormExtension\SaveFailedException;

// Inside init()
Yii::app()->formExtensionService->add(
    'globalsettings.general',
    new TextInput([
        'name' => 'myinput',
        'label' => 'Label',
        'disabled' => true,
        'tooltip' => 'Moo moo moo',
        'help' => 'Some help text',
        'save' => function($request, $connection) {
            $value = $request->getPost('myinput');
            if ($value === 'some invalid value') {
                throw new SaveFailedException("Could not save custom input 'myinput'");
            } else {
                SettingGlobal::setSetting('myinput', $value);
            }
        },
        'load' => function () {
            return getGlobalSetting('myinput');
        }
    ])
);

验证

输入的验证在 save 函数中完成(见上例)。如果提交的值无效,请抛出 SaveFailedException,系统将向用户显示警告闪现消息。

支持的表单

以下表单可以扩展:

  • globalsettings.general (New in 6.0.0 )

如果您想为其他核心表单添加支持,需要在拉取请求(pull request)中应用以下更改:

在视图文件中添加:

<?php
use LimeSurvey\Libraries\FormExtension\FormExtensionWidget;
use LimeSurvey\Libraries\FormExtension\Inputs\DefaultBaseRenderer;
?>
... more HTML
<?= FormExtensionWidget::render(
    App()->formExtensionService->getAll('globalsettings.security'),
    new DefaultBaseRenderer()
); ?>

如果该表单的 HTML 与其他表单不同,您可能需要基于 DefaultBaseRenderer 创建一个新的渲染器类。您可能还需要为默认渲染器类扩展尚未添加的输入类型。

第二项更改是在保存该表单的控制器操作中,添加对表单扩展服务类的调用:

$request = App()->request;
Yii::app()->formExtensionService->applySave('globalsettings', $request);

完成!

<span id="Localization_ (New in 3 )">

本地化 (New in 3 )

插件可以添加自己的语言区域文件。所用文件格式为 .mo,与核心翻译相同。这些文件必须存放在:

<plugin root folder>/locale/<language>/<language>.mo

其中 "<language>" 是由两个字母组成的语言代码,例如 "de" 或 "fr"。

要使用特定的语言区域文件,请使用插件函数 gT:

$this->gT("A plugin text that needs to be translated");

如果在插件专用的语言区域文件中找不到给定的字符串,该函数会在核心语言区域文件中查找。因此可以放心使用诸如 "Cancel"(取消)之类的字符串:

$this->gT("Cancel");  // Will be translated even if "Cancel" is not in the plugin locale file

如果您的插件同时使用了视图,则应使用:

$plugin->gT("Translate me");

以便在视图中进行插件专用的翻译。

您可以将 limesurvey.pot 文件作为 pot 文件的示例。该文件会被导入到您的翻译工具中。

工具

Poedit 是一款用于编辑 po 和 mo 文件的开源工具。

<span id="Logging_ (New in 3 )">

日志记录 (New in 3 )

如果您想从插件中记录日志,只需编写:

$this->log("Your message");

默认的日志级别为 trace,但您可以通过可选的第二个参数指定其他日志级别:

$this->log("Something went wrong!", CLogger::LEVEL_ERROR);

日志文件位于以下文件夹中:

<limesurvey root folder>/tmp/runtime/plugin.log

您的插件名称会自动用作类别。若只想查看来自您插件的错误,可以使用 grep(在 Linux 上):

 $ tail -f tmp/runtime/plugin.log | grep <your plugin name>

<span id="Logging_plugin_deactivation_due_to_error_ (New in 6.13.3 )">

记录因错误而停用插件的日志 (New in 6.13.3 )

自 LimeSurvey 5 版起:发生 PHP 错误时,插件可以被自动停用。

系统会自动向 LimeSurvey 管理员发送一封电子邮件。您可以利用日志系统向其他服务器管理员生成警报。

例如:发送警报消息

                // Plugin error happen, plugin was disable : send email using CLogRoute
                'pluginError' => array(
                    'class' => 'CEmailLogRoute', // https://www.yiiframework.com/doc/api/1.1/CEmailLogRoute
                    'categories' => 'application.model.plugin.setLoadError', // A plugin was disable
                    'subject' => '[ERROR] Plugin deactivated',
                    'emails' => ['webmaster@example.org'],
                    'sentFrom' => 'noreply@example.org',
                    'enabled' => 1, // enabled here
                )

有关在 Yii 1 中配置日志记录的更多信息:可选设置。

<span id="Extension_updates_ (New in 4 )">

扩展更新 (New in 4 )

自 LimeSurvey 4.0.0 版起,系统提供了处理插件及其他扩展更新的机制。要使用此机制,您的扩展 config.xml 文件需要包含更新程序配置。

<updaters>
    <updater>
        <stable>1</stable>
        <type>rest</type>
        <source>https://comfortupdate.limesurvey.org/index.php?r=limestorerest</source>
        <manualUpdateUrl>https://somedownloadlink.com/maybegithub</manualUpdateUrl>
    </updater>
</updaters>

(上面的 source 标签指向 LimeStore REST API,LimeStore 中提供的所有扩展都将使用该接口。)

更新程序标签说明
标签 描述
stable 如果此来源只提供稳定版本号,则为 "1";如果此来源还会提供不稳定版本(例如 0.3.3-beta),则为 "0"。
type 目前仅支持 rest 类型。添加新的更新程序类型(版本检查器)很容易,例如 git、wget 等。
source 用于获取新版本的 URL。
manualUpdateUrl 用户可以访问该 URL 来更新扩展的最新版本。
automaticUpdateUrl TODO

如果您不想提供更新程序,应在配置 XML 文件中加入以下文本:

<updaters disabled="disabled">
</updaters>

这样,您就是在告诉系统,您有意禁用了更新系统,而不是忘记添加它。

新的插件 UpdateCheck(默认已安装并启用)会在超级管理员登录时异步检查所有已安装扩展的新更新,每 24 小时最多检查一次。如果发现任何新版本,系统会推送一条通知。

可用更新

如果发现新的安全更新,通知将自动打开,并以 "danger" 样式显示。

可用的安全更新

您可以进入插件管理器查看页面并点击 "Check updates",手动检查更新。请注意,只有在 UpdateCheck 插件已启用时,此按钮才可见。

手动检查更新

内部实现

本节简要概述扩展更新程序的实现。

扩展更新程序是 ExtensionInstaller 库的一部分。下面是与更新过程相关的类的 UML 图。

扩展更新程序 UML 图

Yii 启动时的程序流程:

 Yii init
   VersionFetcherServiceLocator->init()
     Add REST version fetcher
   ExtensionUpdaterServiceLocator->init()
     Add PluginUpdater
     TODO: Add an updater for each extension type (theme, question template, ...)

运行 UpdaterCheck 插件时的程序流程:

 Get all updaters from ExtensionUpdaterServiceLocator
 Loop each updater
   For each updater, loop through version fetchers configured by <updater> XML
     For each version fetcher, contact remote source and get version information
 Compose all versions into a notification

UpdateCheck 插件中的 checkAll 方法提供了如何查询所有扩展的新版本的示例。

添加新的版本获取器

要添加新的自定义版本获取器,请在 Yii 初始化期间运行以下代码:

$service = \Yii::app()->versionFetcherServiceLocator
$service->addVersionFetcherType(
  'myNewVersionFetcherType',
  function (\SimpleXMLElement $updaterXml) {
    return new MyNewVersionFetcher($updaterXml);
  }
);

当然,类 MyNewVersionFetcher 必须是 VersionFetcher 的子类。

要使用您的新版本获取器,请在更新程序 XML 中将 type 标签配置为使用 myNewVersionFetcherType(而不是例如 rest)。

添加新的扩展更新程序

要添加新的自定义扩展更新程序,请在 Yii 初始化期间运行以下代码:

$service = \Yii::app()->extensionUpdaterServiceLocator;
$service->addUpdaterType(
  'myNewExtensionUpdater',
  function () {
    return MyNewExtensionUpdater::createUpdaters();
  }
);

类 MyNewExtensionUpdater 必须是 ExtensionUpdater 的子类。

config.xml 中顶层的 type 标签('plugin'、'theme' 等)将控制该扩展使用哪种扩展更新程序。该系统目前还不能完全自定义,因为您还需要添加自定义的 ExtensionInstaller、菜单项等。但理论上,也许在未来,可以通过这种方式添加新的扩展类型。

扩展安装程序

扩展安装程序库由两个抽象类组成:

  • ExtensionInstaller
  • FileFetcher

ExtensionInstaller 会为每种扩展类型创建子类,例如 PluginInstaller、QuestionThemeInstaller 等。

FileFetcher 会为每种不同的文件获取方式创建子类。目前仅支持上传的 zip 文件,但将来也可能会有 Github 或 LimeStore 获取器。

教程

这篇分步教程演示了如何创建一个插件,在每次提交调查反馈时发送 POST 请求。该教程介绍了如何创建并保存全局设置和各调查的设置、如何注册事件等内容。