Complementos - avanzado
From LimeSurvey Manual
Descripción general
LimeSurvey puede ampliar su funcionalidad mediante plugins. LimeSurvey ya incluye un buen número de plugins del núcleo. Además, consulte nuestra lista de plugins de terceros y, quizás en el futuro, añada su propio plugin.
Los complementos permiten a los usuarios personalizar la funcionalidad de su instalación y al mismo tiempo beneficiarse de las actualizaciones periódicas de software.
Esta documentación está destinada a desarrolladores que están ampliando LimeSurvey para su propio uso o para sus clientes; Esta documentación no ayudará a los usuarios finales.
Los complementos deben implementar la interfaz iPlugin. Recomendamos ampliar su clase de complemento desde la clase PluginBase.
Los plugins se desarrollan en torno a un mecanismo de eventos.
Configuración del complemento
Al ampliar, se beneficia de la funcionalidad común requerida por los complementos que ya hemos implementado para usted. Una de estas funciones es la implementación de la función getPluginSettings. Esta función debe devolver una matriz que describa las opciones de configuración para el usuario.
El complemento de ejemplo expone solo 1 configuración configurable, el mensaje que mostrará.
protegted $configuración = matriz(
'logo' => matriz(
'tipo' => 'logotipo',
'ruta' => 'assets/logo.png'
) ,
'mensaje' => matriz(
'tipo' => 'cadena',
'etiqueta' => 'Mensaje'
)
);
La matriz contiene un nombre para cada configuración como clave. Los valores son matrices que contienen los metadatos requeridos.
Los tipos admitidos son:
- logo
- int (número entero)
- cadena (alfanumérica)
- texto
- html
- relevancia
- info
- contraseña
- fecha!
- seleccionar
Además de escribir, hay otras claves disponibles:
- label, define una etiqueta
- default, define un valor que se muestra si no se especifica ninguno (solo para la configuración global, no para la configuración del formulario)
- current, define el valor actual.
- readOnly : muestra la configuración como solo lectura
- htmlOptions, las htmlOptions de la parte de entrada (consulte el manual de Yii [[1]])
- pluginOptions, para algunas configuraciones (html o select) : establece la opción del widget
- labelOptions : htmlOptions de la etiqueta
- controlOptions : htmlOptions del contenedor de la etiqueta y la entrada
- localized : si es true, el valor se guarda por idioma. La entrada se envía como
name[language]ycurrentdebe ser una matriz indexada por código de idioma. - language : se usa junto con localized. Puede ser un único código de idioma o (New in X.Y.Z ) una matriz de códigos de idioma para mostrar una entrada por idioma (consulte Configuración localizada del plugin)
Puede encontrar un ejemplo de complemento utilizando todas las configuraciones reales en exampleSettings
Leer y escribir configuraciones de complemento
Es posible leer y escribir la configuración del complemento directamente desde el código del complemento.
Ejemplo:
$miConfiguración = $this->get('miConfiguración');
$this->set('miConfiguración', $miConfiguración + 1);
Puede obtener un valor predeterminado si la configuración es nula:
$miConfiguración = $this->get('miConfiguración', nulo, nulo, 10); // ¡10 es el valor predeterminado
Configuración del plugin específica del formulario
Se utilizan dos eventos para crear la configuración del plugin específica del formulario:
- newSurveySettings
- beforeSurveySettings
Ejemplo para desactivar un plugin en un formulario concreto:
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 )">
Configuración localizada del plugin (New in 7.4 )
Para mostrar una entrada por cada idioma del formulario para la misma configuración, establezca localized en true y pase la lista de idiomas en language. El nombre del idioma se añade a la etiqueta de cada entrada.
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(),
// Matriz indexada por código de idioma, p. ej. ['en' => '...', 'de' => '...']
'current' => $this->get('errorText', 'Survey', $surveyId, []),
],
]
]
);
}
El valor enviado es una matriz indexada por código de idioma, por lo que la función newSurveySettings del ejemplo anterior lo guarda sin ningún cambio. Para leer el texto del idioma actual:
$errorTexts = $this->get('errorText', 'Survey', $surveyId, []);
$errorText = $errorTexts[App()->getLanguage()] ?? '';
Eventos
Los complementos se suscriben a eventos y pueden interactuar con LimeSurvey cuando se activa el evento. Para obtener una lista de los eventos disponibles actualmente, consulte Eventos complementarios.
API
Los complementos sólo deberían extender LimeSurvey a través de su API "pública". Esto significa que usar directamente las clases que se encuentran en el código fuente es una mala práctica. Aunque no podemos obligarte a no hacerlo, corres el riesgo de tener un complemento roto con cada actualización menor que hacemos.
En la medida de lo posible, interactúe con LimeSurvey solo a través de los métodos descritos aquí. Lo mismo se aplica a los eventos.
El objeto API está disponible a través de $this->api cuando se extiende desde PluginBase; de lo contrario, puede obtenerlo desde la instancia de PluginManager que se pasa al constructor de sus complementos.
Se pueden agregar nuevas funciones al objeto API a pedido.
<span id="Form_extension (New in 6 )">
Extensión de formulario (New in 6 )
Introducción
El sistema de extensión de formularios es una forma más general de ampliar formularios en el núcleo de LimeSurvey sin agregar un nuevo evento para cada formulario.
Consta de los siguientes componentes:
- ¡Un módulo global llamado FormExtensionService
- ¡Una biblioteca de clases de entrada que los complementos pueden agregar a la inicialización del módulo anterior
- Un widget, junto con renderizadores personalizados, que se utilizan en los archivos de vista de LimeSurvey
Cada formulario se identifica mediante una cadena de posición, como<form name><dot><tab name> . Ejemplo: globalsettings.general o globalsettings.security .
El objetivo detrás de un sistema basado en clases sin HTML es liberar a los autores del complemento del trabajo para actualizar el HTML cuando cambia el HTML principal. Aún así, el autor puede utilizar el tipo RawHtmlInput si es necesario.
Una cosa que no puede hacer en este sistema es agregar "nuevas pestañas de formulario".
Ejemplo
Para agregar una nueva entrada a un formulario desde un complemento, use el siguiente código de su función init():
TODO: Guardar en la configuración del complemento en lugar de global
// En la parte superior del archivo
use LimeSurvey\Libraries\FormExtension\Inputs\TextInput;
use LimeSurvey\Libraries\FormExtension\SaveFailedException;
// Dentro de init()
Yii::app()->formExtensionService->add(
'globalsettings.general',
new TextInput([
'name' => 'myinput',
'label' => 'Etiqueta',
'disabled' => true,
'tooltip' => 'Moo moo moo',
'help' => 'Algún texto de ayuda',
'save' => function($solicitud, $conexión) {
$valor = $solicitud->getPost('myinput');
if ($value === 'algún valor no válido') {
throw new SaveFailedException("No se pudo guardar la entrada personalizada 'myinput'");
} else {
ConfiguraciónGlobal::setSetting('myinput', $value);
}
} ,
'load' => function () {
return getGlobalSetting('myinput');
}
])
);
Validación
La validación de la entrada se realiza en la función save (ver ejemplo arriba). Si el valor publicado no es válido, lanza una SaveFailedException y se mostrará al usuario un mensaje flash de advertencia.
Formularios admitidos
Se pueden ampliar las siguientes formas:
- configuración global.general (New in 6.0.0 )
Si desea agregar soporte para otro formulario principal, debe aplicar el siguiente cambio en una solicitud de extracción:
En el archivo de vista, agregue:
!¡NORTE! <?php
use LimeSurvey\Libraries\FormExtension\FormExtensionWidget;
use LimeSurvey\Libraries\FormExtension\Inputs\DefaultBaseRenderer;
?>
... más HTML
<?= FormExtensionWidget::render(
App()-> formExtensionService->getAll('globalsettings.security'),
nuevo DefaultBaseRenderer()
); ?>
Es posible que tengas que crear una nueva clase de renderizador basada en DefaultBaseRenderer , si el formulario HTML es diferente a otros formularios. Es posible que también necesite ampliar la clase de renderizador predeterminada con tipos de entrada que aún no se han agregado.
El segundo cambio que debe hacer es agregar una llamada a la clase de servicio de extensión de formulario en la acción del controlador que guarda el formulario:
$request = App()->request;
Yii::app()->formExtensionService->applySave('globalsettings', $request);
¡Eso es todo!
<span id="Localization_ (New in 3 )">
Localización (New in 3 )
Es posible que los complementos agreguen sus propios archivos locales. El formato de archivo utilizado es .mo, igual que las traducciones principales. Los archivos deben almacenarse en
<plugin root folder>/lugar/<language> /<language> .mes
dónde "<language> " es una palabra de dos letras como "de" o "fr".
Para usar el archivo local específico, use la función del complemento gT:
$this->gT("Un texto de complemento que debe traducirse");
Si la cadena proporcionada no se puede encontrar en el archivo local específico del complemento, la función buscará en los archivos locales principales. Por tanto, es seguro utilizar cadenas como "Cancelar":
$this->gT("Cancelar"); // ¡Se traducirá incluso si "Cancelar" no está en el archivo local del complemento
Si está utilizando vistas junto con su complemento, debe usar
$plugin->gT("Traducirme");
para hacer una traducción específica del complemento en su vista.
Puede utilizar el archivo limesurvey.pot como ejemplo de cómo puede verse un archivo pot. Esto se importa a su herramienta de traducción.
Herramientas
Una herramienta de código abierto para editar archivos po y mo es [2].
<span id="Logging_ (New in 3 )">
Iniciando sesión (New in 3 )
Si desea registrar algo desde su complemento, simplemente escriba
$this->log("Tu mensaje");
El nivel de registro predeterminado es rastreo, pero puede proporcionar otro nivel de registro como segundo argumento opcional:
$this->log("¡Algo salió mal!", CLogger::LEVEL_ERROR);
El archivo de registro se puede encontrar en la carpeta
<limesurvey root folder>/tmp/runtime/plugin.log
El nombre de su complemento se utiliza automáticamente como categoría. Una buena manera de ver solo los errores de su complemento es usar grep (en Linux):
$ cola -f tmp/runtime/plugin.log | grep<your plugin name>
<span id="Logging_plugin_deactivation_due_to_error_ (New in 6.13.3 )">
Registro de la desactivación del plugin por error (New in 6.13.3 )
Desde la versión 5 de LimeSurvey, un plugin puede desactivarse automáticamente si se produce un error de PHP.
Se envió automáticamente un correo electrónico al administrador de LimeSurvey. Puede usar el sistema de registro para generar una alerta para los demás administradores del servidor.
Por ejemplo, para enviar un mensaje de alerta:
// 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
)
Más información sobre cómo configurar el registro en Yii 1: Optional_settings/es#Logging_settings.
<span id="Extension_updates_ (New in 4 )">
Actualizaciones de extensiones (New in 4 )
Desde la versión 4.0.0 de LimeSurvey, existe un sistema para gestionar las actualizaciones de complementos y otras extensiones. Para utilizar este sistema, su archivo de extensión config.xml debe incluir la configuración del actualizador.
<updaters> <updater>
<stable> 1</stable>
<type> descansar</type>
<source> https://comfortupdate.limesurvey.org/index.php?r=limestorerest</source>
<manualUpdateUrl> https://somedownloadlink.com/maybegithub</manualUpdateUrl>
</updater>
</updaters>
(La etiqueta fuente anterior apunta a la API REST de LimeStore, que se utilizará para todas las extensiones disponibles en nuestro LimeStore).
| Etiqueta | Descripción |
|---|---|
| stable | "1" si esta fuente solo proporciona números de versión estables; "0" si la fuente también proporciona versiones inestables, como 0.3.3-beta.
|
| type | Por ahora, solo se admite el tipo rest. Es fácil añadir nuevos tipos de actualizadores (comprobadores de versiones), como git, wget, etc.
|
| source | La URL desde la que obtener nuevas versiones. |
| manualUpdateUrl | URL a la que puede acceder el usuario para actualizar a la última versión de la extensión. |
| automaticUpdateUrl | TODO |
Si no desea proporcionar un actualizador, debe colocar el siguiente texto en su archivo XML de configuración:
<updaters disabled="disabled">
</updaters>
De esta manera, le dice al sistema que deshabilitó intencionalmente el sistema de actualización y que no se olvidó de agregarlo.
El nuevo complemento UpdateCheck, instalado y activado de forma predeterminada, busca nuevas actualizaciones para todas las extensiones instaladas cuando un superadministrador inicia sesión, de forma asincrónica, como máximo una vez cada 24 horas. Si se encuentra alguna versión nueva, se envía una notificación.
Si se encuentra una nueva actualización de seguridad, la notificación se abrirá automáticamente y tendrá el estilo de clase "peligro".
Puede buscar actualizaciones manualmente yendo a la vista del administrador de complementos y haciendo clic en "Verificar actualizaciones". Tenga en cuenta que este botón solo es visible si el complemento UpdateCheck está activado.
Debajo del capó
Esta sección proporciona una breve descripción general de la implementación del actualizador de extensiones.
El actualizador de extensiones es parte de la biblioteca ExtensionInstaller. A continuación se muestra un diagrama UML para las clases relacionadas con el proceso de actualización.
Flujo del programa cuando se inicia Yii:
Yii inicio VersionFetcherServiceLocator->init() ¡Agregue el buscador de versiones REST ExtensionUpdaterServiceLocator->init() Añadir PluginUpdater TODO: ¡Agregue un actualizador para cada tipo de extensión (tema, plantilla de pregunta,...)
Flujo del programa al ejecutar el complemento UpdaterCheck:
Obtenga todos los actualizadores de ExtensionUpdaterServiceLocator ¡Repita cada actualizador Para cada actualizador, recorra los buscadores de versiones configurados por<updater> XML Para cada buscador de versiones, comuníquese con la fuente remota y obtenga información sobre la versión. ¡Componga todas las versiones en una notificación
El método checkAll en el complemento UpdateCheck proporciona un ejemplo de cómo consultar todas las extensiones para obtener nuevas versiones. .
Agregar nuevos buscadores de versiones
Para agregar un nuevo buscador de versiones personalizado, ejecute esto durante la inicialización de Yii:
$service = \Yii::app()->versionFetcherServiceLocator
$service->addVersionFetcherType(
'myNewVersionFetcherType',
function (\SimpleXMLElement $updaterXml) {
return new MyNewVersionFetcher( $updaterXml);
}
);
Por supuesto, la clase MyNewVersionFetcher tiene que ser una subclase VersionFetcher.
Para usar su nuevo buscador de versiones, configure la etiqueta type en el XML del actualizador para usar
myNewVersionFetcherType(en lugar de, por ejemplo,rest).
Agregar nuevos actualizadores de extensiones
Para agregar un nuevo actualizador de extensión personalizado, ejecute esto durante la inicialización de Yii:
$servicio = \Yii::app()->extensionUpdaterServiceLocator;
$servicio->addUpdaterType(
'myNewExtensionUpdater',
function () {
return MyNewExtensionUpdater::createUpdaters() ;
}
);
La clase MyNewExtensionUpdater tiene que ser una subclase ExtensionUpdater.
La etiqueta type superior en config.xml ('complemento', 'tema', ...) controlará qué actualizador de extensión se utiliza para esta extensión. El sistema aún no es completamente personalizable, ya que también es necesario agregar un ExtensionInstaller personalizado, elementos de menú, etc. Pero en teoría, y tal vez en el futuro, debería ser posible agregar un nuevo tipo de extensión de esta manera.
Instalador de extensiones
La biblioteca del instalador de extensiones consta de dos clases abstractas:
- ExtensionInstaller
- FileFetcher
ExtensionInstaller tiene subclases para cada tipo de extensión, como PluginInstaller, QuestionThemeInstaller, etc.
FileFetcher tiene subclases para cada forma diferente de recuperar archivos. Actualmente, solo se admiten archivos zip cargados, pero en el futuro, también podría haber un buscador de Github o LimeStore.
Tutorial
Este tutorial paso a paso muestra cómo crear un plugin que envía una solicitud POST con cada respuesta enviada a un formulario. El tutorial explica cómo crear y guardar la configuración global y la configuración por formulario, cómo registrar eventos y más.




