Плагіни
From LimeSurvey Manual
Огляд
LimeSurvey має можливість розширювати функціональність за допомогою плагінів. LimeSurvey вже містить чимало основних плагінів. Також перегляньте наш список сторонніх плагінів і, можливо, згодом додайте до нього власний плагін!
Плагіни дозволяють користувачам налаштовувати функціональність своєї інсталяції, водночас отримуючи переваги регулярних оновлень програмного забезпечення.
Ця документація призначена для розробників, які розширюють LimeSurvey для власних потреб або для своїх клієнтів; кінцевим користувачам ця документація не допоможе.
Плагіни мають реалізовувати інтерфейс iPlugin. Рекомендуємо успадковувати клас вашого плагіна від класу PluginBase.
Плагіни розробляються на основі механізму подій.
Налаштування плагіна
Успадковуючись, ви отримуєте загальну функціональність, потрібну плагінам, яку ми вже реалізували для вас. Однією з таких функцій є реалізація функції getPluginSettings. Ця функція має повертати масив, що описує параметри конфігурації для користувача.
Приклад плагіна відкриває лише одне налаштування, а саме повідомлення, яке він показуватиме.
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 лише через методи, описані тут. Те саме стосується подій.
Об’єкт API доступний через $this->api, якщо ви успадковуєте клас від PluginBase. В іншому випадку його можна отримати з екземпляра 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()
); ?>
Можливо, вам доведеться створити новий клас рендерера на основі DefaultBaseRenderer, якщо HTML форми відрізняється від інших форм. Також може знадобитися розширити стандартний клас рендерера типами полів, які ще не додані.
Друга зміна полягає в додаванні виклику класу сервісу розширення форм в дії контролера, яка зберігає форму:
$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");
Якщо вказаний рядок не знайдено у файлі локалізації плагіна, функція шукатиме його в основних файлах локалізації. Тому безпечно використовувати такі рядки, як "Скасувати":
$this->gT("Cancel"); // Will be translated even if "Cancel" is not in the plugin locale file
Якщо ви використовуєте подання разом зі своїм плагіном, вам слід використовувати
$plugin->gT("Translate me");
щоб виконувати переклад, специфічний для плагіна, у вашому поданні.
Ви можете використати файл limesurvey.pot як приклад того, як може виглядати pot-файл. Його імпортують у ваш інструмент перекладу.
Інструменти
Одним із інструментів з відкритим кодом для редагування po- та mo-файлів є Poedit.
<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 )
Починаючи з версії 5 LimeSurvey плагін може бути автоматично деактивований у разі помилки 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.
<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 вище вказує на REST API LimeStore, який використовується для всіх розширень, доступних у нашому LimeStore.)
| Тег | Опис |
|---|---|
| stable | "1", якщо це джерело надає лише номери стабільних версій; "0", якщо джерело також надаватиме нестабільні версії, наприклад 0.3.3-beta.
|
| type | Наразі підтримується лише тип rest. Нові типи засобів оновлення (перевірки версій), як-от git, wget тощо, додати легко.
|
| source | URL-адреса, з якої отримують нові версії. |
| manualUpdateUrl | URL-адреса, за якою користувач може перейти, щоб оновити розширення до останньої версії. |
| automaticUpdateUrl | TODO |
Якщо ви не хочете вказувати засіб оновлення, додайте у свій конфігураційний 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
Метод checkAll у плагіні UpdateCheck показує приклад того, як опитати всі розширення на наявність нових версій.
Додавання нових засобів отримання версій
Щоб додати новий власний засіб отримання версій, виконайте це під час ініціалізації Yii:
$service = \Yii::app()->versionFetcherServiceLocator
$service->addVersionFetcherType(
'myNewVersionFetcherType',
function (\SimpleXMLElement $updaterXml) {
return new MyNewVersionFetcher($updaterXml);
}
);
Звісно, клас MyNewVersionFetcher має бути підкласом VersionFetcher.
Щоб використовувати новий засіб отримання версій, налаштуйте тег type в XML засобу оновлення так, щоб він використовував
myNewVersionFetcherType (замість, наприклад, rest).
Додавання нових засобів оновлення розширень
Щоб додати новий власний засіб оновлення розширень, виконайте це під час ініціалізації Yii:
$service = \Yii::app()->extensionUpdaterServiceLocator;
$service->addUpdaterType(
'myNewExtensionUpdater',
function () {
return MyNewExtensionUpdater::createUpdaters();
}
);
Клас MyNewExtensionUpdater має бути підкласом ExtensionUpdater.
Верхній тег type у config.xml ('plugin', 'theme', ...) визначає, які засоби оновлення розширень використовуються для цього розширення. Система поки що не є повністю настроюваною, оскільки потрібно також додати власний ExtensionInstaller, пункти меню тощо. Але теоретично, а можливо, і в майбутньому, таким способом можна буде додати новий тип розширення.
Інсталятор розширень
Бібліотека інсталятора розширень складається з двох абстрактних класів:
- ExtensionInstaller
- FileFetcher
ExtensionInstaller має підкласи для кожного типу розширень, як-от PluginInstaller, QuestionThemeInstaller тощо.
FileFetcher має підкласи для кожного окремого способу отримання файлів. Наразі підтримуються лише завантажені zip-файли, але в майбутньому може з'явитися також засіб отримання з Github або LimeStore.
Посібник
Цей покроковий посібник показує, як створити плагін, який надсилає POST-запит після кожного надсилання відповіді опитування. У ньому описано, як створити та зберегти глобальні налаштування та налаштування для окремого опитування, як зареєструвати події тощо.




