外掛程式
From LimeSurvey Manual
概述
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 互動。事件也是如此。
當繼承自 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:儲存在外掛程式設定中,而非全域設定
// 檔案開頭
use LimeSurvey\Libraries\FormExtension\Inputs\TextInput;
use LimeSurvey\Libraries\FormExtension\SaveFailedException;
// 在 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 為基礎建立新的 renderer 類別。您也可能需要為預設 renderer 類別擴充尚未新增的輸入類型。
第二項變更是在儲存該表單的控制器動作中,新增對 form extension service 類別的呼叫:
$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 中設定記錄的更多資訊:Optional_settings/zh-hant#Logging_settings。
<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 |
如果您不想提供更新程式,請在您的 config XML 檔案中加入以下內容:
<updaters disabled="disabled">
</updaters>
如此一來,您就是告訴系統您是刻意停用更新系統,而不是忘記新增。
新的外掛程式 UpdateCheck 預設已安裝並啟用,會在超級管理員登入時以非同步方式檢查所有已安裝擴充功能是否有新的更新,每 24 小時最多檢查一次。如果發現任何新版本,系統會推送通知。
如果發現新的安全性更新,通知會自動開啟,並以「danger」樣式顯示。
您可以前往外掛程式管理員頁面,點選「Check updates」來手動檢查更新。請注意,只有在啟用 UpdateCheck 外掛程式時才會顯示此按鈕。
內部運作
本節簡要概述擴充功能更新程式的實作方式。
擴充功能更新程式是 ExtensionInstaller 程式庫的一部分。下方是與更新程序相關之類別的 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 請求。本教學會說明如何建立並儲存全域設定與各問卷設定、如何註冊事件等內容。




