http://lists.elastix.org/pipermail/desarrollo/attachments/20120410/5582b6ad/attachment-0002.pdf

Anuncio
-
Manual para Desarrolladores
Departamento de Desarrollo Elastix
1
-
VERSIONAMIENTO
Versión Versión de
Elastix
1
2.3.0
Fecha
Elaborado por
Detalles
16-Ene-2012
Ing. Alberto Santos
Documentación Inicial
Departamento de Desarrollo Elastix
2
-
Manual para Desarrolladores
El presente manual servirá de guía para desarrolladores que pretenden usar el
Framework Elastix para la creación de nuevos módulos.
En este manual se explicará como se puede crear un módulo Elastix, Fundamentos
Básicos del Framework Elastix, y cómo llegar a convertir nuestro nuevo módulo en un
Addon de Elastix.
Creación de un nuevo módulo Elastix
Para la creación de un nuevo módulo de Elastix usaremos el addon “Developer”,
por lo que necesitaremos instalarlo.
Instalación del Addon Developer
1. Ingresamos a la interfaz Elastix como usuario administrador y vamos a la
pestaña de “Addons”, una vez que termine de cargar los addons disponibles
buscamos el que diga “Developer”.
Identificación del addon “Developer”.
2. Ya identificado el addon damos click en el botón “Install” respectivo.
3. Luego de esto se inicia el proceso de instalación del addon, por lo que se
debe esperar unos minutos hasta que finalice la instalación.
Departamento de Desarrollo Elastix
3
-
Finalización de la instalación del addon “Developer”.
4. Luego de esto salimos de la interfaz y volvemos a ingresar como
administrador. Debemos ver una nueva pestaña de menú con el nombre
“Developer”.
Utilizando el Elastix Developer
El addon Developer nos permitirá crear de manera transparente para nosotros el
esqueleto inicial de código necesario para elaborar un módulo de Elastix, lo que
puede constituir un ahorro de horas en muchos casos.
El addon para desarrolladores tiene tres submenús pero el que nos interesa se
llama “Constructor de Módulos” o “Build Module” y es el primer submenú.
La función del constructor de módulos es generar el esqueleto de código del nuevo
módulo que estamos creando, para que luego podamos continuar con el desarrollo
extendiendo este código inicial.
Al crear un modulo desde aquí, se generará lo siguiente:
•
•
•
El menú (o los menús) dentro de la interfaz Web de Elastix. Es decir que ya
no tendremos que modificar manualmente la base de datos menu.db.
El código esqueleto, el cual se encontrará dentro de una carpeta cuyo
nombre será igual al ID del módulo. Esta carpeta será ubicada a su vez
dentro de la carpeta /var/www/html/modules que es donde residen
todos los módulos de Elastix. Es decir que ya no tenemos que crear
manualmente esta carpeta!
Pantallas prototipo. Estas pantallas pueden ser de tres tipos: formulario,
reporte y enmarcado.
Departamento de Desarrollo Elastix
4
Veamos ahora cómo luce el constructor de módulos.
El constructor de módulos incluido en el addon Developer
Como podemos observar, el constructor de módulos se encuentra dividido en tres
partes:
•
•
•
Información General.
Localización.
Descripción del módulo.
Información General
Esta sección nos permite definir el nombre e identificador único del módulo, así
como también los datos de la persona que crea el modulo para comentarlas en las
cabeceras de cada archivo de programación en PHP. También nos permite
configurar el nivel de accesibilidad que tendrá el módulo a través del parámetro
“Permisos de Grupo”.
Sección de información general dentro del constructor de módulos
Localización
En esta sección se configura el lugar, dentro del menú, donde vamos a ubicar el
nuevo módulo. Por omisión esta sección luce como la siguiente figura.
Sección donde se configura la ubicación del módulo
Departamento de Desarrollo Elastix
5
Si decimos que el módulo es de nivel 3 entonces aparecerán automáticamente
nuevos campos para ingresar los identificadores de los menús padres de nivel 1 y
nivel 2.
Aparecen nuevos campos si se dice que el módulo será de nivel 3
Para clarificar el significado de los campos mostrados en esta sección veamos la
siguiente tabla.
Nombre campo
Nivel del Módulo
Existe Padre Nivel 1?
Nombre Padre Nivel 1
Id Padre Nivel 1
Existe Padre Nivel 2?
Descripción
Aquí definimos el nivel de jerarquía del
modulo.
Aquí definimos si vamos a colocar el nuevo
módulo bajo un menú de nivel 1 existente o
se tendrá que crear uno nuevo. Para colocar
el nuevo módulo bajo un menú previamente
existente escogemos “Sí” y de manera
automática se desplegará un listado con los
módulos de nivel 1 existentes.
Si escogemos “No” crearemos un nuevo
menú de nivel 1 sobre la marcha. Por esta
razón aparecerán dos campos adicionales
para especificar el nombre y el
identificador.
Definimos el nombre del módulo padre. La
primera letra con mayúscula.
Definimos el identificador del módulo
padre. Todo con minúsculas y no se
permiten espacios.
Esta opción aparecerá si escogimos un nivel
3 en el campo “Nivel del Módulo”.
De manera similar a lo que ocurre con el
campo “Existe Padre Nivel 1”, si se escoge
“No” aparecerán dos campos más.
Nombre Padre Nivel 2
Id Padre Nivel 1
Departamento de Desarrollo Elastix
Definimos el nombre del módulo padre de
nivel 2. La primera letra con mayúscula.
Definimos el identificador del módulo padre
de nivel 2. Todo con minúsculas y no se
permiten espacios.
6
Descripción del módulo
Esta última sección es la más interesante pues es aquí donde se crea el contenido
mismo del módulo.
A continuación se explica qué significan los tres tipos de módulos que se pueden
crear.
•
•
•
Formulario: Sirve para recolectar datos del usuario. El constructor de
módulos cuenta con soporte para los tipos de campos HTML más comunes
como son: texto, selección, fecha, área de texto, casilla de verificación,
radio, contraseña, oculto y archivo.
Reporte: Un reporte muestra datos organizados en forma de una tabla
donde se incluyen automáticamente algunos controles útiles como botones
para navegación. Luego de generar el código necesario con el constructor
de módulos ya es más sencillo enlazar el reporte con una base de datos
para mostrar información útil.
Enmarcado: Embebe un URL arbitrario en la pantalla. Muy útil cuando
queremos integrar aplicaciones externas en la interfaz Web de Elastix. Un
ejemplo de esto es la integración de vtigerCRM.
Creación de una pantalla tipo Formulario
Con los botones ">>", "<<" podemos añadir o quitar los campos a insertar en
nuestro formulario.
Al guardar los datos establecidos para el nuevo módulo se creará el siguiente árbol
de directorios (exceptuando para los módulos tipo enmarcado, en cuyo caso el
módulo será simplemente un link al URL proporcionado) en la ruta
documentRoot/modules donde documentRoot es /var/www/html para Elastix.
Como podrá notar un modulo tiene la misma
arquitectura general del framework, arquitectura web
MVC2 por ende se define a esto como un MVC2
dentro de otro MVC2 una definición de recursividad de
grado 2.
En que nos ayuda esto, es que podemos de forma
inmediata hacer similitud que las carpetas tienen las
siguientes relaciones:
•
themes es la capa vista.
•
index.php es la capa control.
•
libs es la capa modelo.
Departamento de Desarrollo Elastix
7
-
Breve descripción de cada carpeta que se crea dentro del módulo
configs
Por default esta carpeta se crea con un archivo denominado “default.conf.php”,
este archivo debe contener las configuraciones básicas del módulo.
Almacena dentro de este archivo variables de configuración que serán muy
usadas a lo largo del módulo, por ejemplo DSN
A continuación se mostrarán dos DSNs usados en Elastix:
•
•
Sqlite3: “sqlite3:///$arrConf[elastix_dbdir]/base.db”
Mysql: se puede usar la función “generarDSNSistema” la cual ya nos
devuelve el string de conexión. A continuación se detallará un poco esta
función que la podemos encontrar en /var/www/html/libs/misc.lib.php
/**
* Función para construir un DSN para conectarse a varias bases de datos
* frecuentemente utilizadas en Elastix. Para cada base de datos reconocida, se
* busca la clave en /etc/elastix.conf o en /etc/amportal.conf según corresponda.
*
* @param string $sNombreUsuario Nombre de usuario para interrogar
* @param string $sNombreDB
Nombre de base de datos para DNS
* @param string $ruta_base
Ruta base para inclusión de librerías
*
* @return mixed NULL si no se reconoce usuario, o el DNS con clave resuelta
*/
function generarDSNSistema($sNombreUsuario, $sNombreDB, $ruta_base='')
help
Dentro de esta carpeta encontraremos un archivo llamado “id_modulo.hlp”. Este es
el archivo que se encarga de mostrar la ayuda embebida del módulo.
Es recomendable que una vez que hayas terminado tu módulo por completo,
elabores la ayuda embebida que no es otra cosa que una especie de manual
de usuario, indicando las diferentes opciones que ofrece este módulo. Es
recomendable que sea escrita en inglés.
Departamento de Desarrollo Elastix
8
A continuación se mostrará un ejemplo muy sencillo de como puede lucir el código
dentro de este archivo. Esta ayuda sólo mostrará el título del módulo seguido de
una breve descripción y una imagen que se encuentra en la ruta indicada.
<html>
<header>
<link rel="stylesheet" href="/themes/{$THEMENAME}/styles.css">
<link rel="stylesheet" href="/themes/{$THEMENAME}/help.css">
</header>
<body>
<h1>{$node_name}</h1>
<p align="Justify">This is the embedded help for my module.</p>
<div><img src="../modules/{$node_id}/images/image.png" border="0"></div>
<div>Figure 1</div><br/>
</body>
</html>
images
Dentro de esta carpeta se guardarán todas las imágenes propias del módulo, por
ejemplo ícono, imagenes usadas para la ayuda embebida, etc.
lang
Como ya sabemos el Framework Elastix soporta traducción de idiomas!! Pues bien,
como es de suponer dentro de esta carpeta se almacenan las traducciones para
nuestro módulo. Cada traducción para cada idioma se almacena en un archivo
diferente, de acuerdo a la siguiente tabla:
Departamento de Desarrollo Elastix
9
Archivo
bg.lang
br.lang
ca.lang
cn.lang
da.lang
de.lang
en.lang
el.lang
es.lang
fa.lang
fr.lang
it.lang
hu.lang
hr.lang
pl.lang
ro.lang
ru.lang
sl.lang
sv.lang
ko.lang
ja.lang
sr.lang
Idioma
Búlgaro
Portugués
Catalán
Chino Simplificado
Danés
Alemán
Inglés
Griego
Español
Persa
Francés
Italiano
Húngaro
Croata
Polaco
Rumano
Ruso
Esloveno
Sueco
Coreano
Japonés
Serbio
Se recomienda que se creen al menos dos archivos de traducciones, uno con
el idioma nativo del desarrollador y otro en inglés
Por lo tanto, si queremos hacer la traducción de nuestro módulo al español
tenemos que crear un archivo dentro de esta carpeta llamado es.lang. Este archivo
básciamente consiste de un sólo arreglo, en el cual la clave es la palabra a traducir
y el valor es la clave traducida. Por ejemplo:
<?php
global $arrLangModule;
$arrLangModule=array(
"Module" => "Módulo",
"This is a test module" => "Este es un módulo prueba”,
);
?>
Departamento de Desarrollo Elastix
10
-
Es recomendable que las claves en nuestro arreglo de traducciones sean
en inglés
libs
Como ya se mencionó anteriormente esta es nuestra capa de modelo. Dentro de
esta carpeta habrá una librería que es la que se encargará de hacer consultas a
bases de datos, modificar arhivos, etc.
Todos los querys que se realicen deben de ser parametrizados, esto evitará la
inyección de código SQL arbitrario a nuestra base. Más adelante se explicará
con mayor detalle como hacerlo.
Recuerda que nuestro servicio de apache corre usando el usuario “asterisk”, por
ende sólo tendremos acceso a archivos y carpetas a los cuales “asterisk” tenga
acceso. No podrás leer o escribir sobre un archivo o carpeta por ejemplo que tenga
solo permisos para “root”.
No hagas uso de comandos de consola que necesitan de privilegios “root”.
esto puede conllevar a que nuestro script o librería se convierta en un
potencial hueco de seguridad.
Pero y que pasa si es que nuestro script o librería necesita obligadamente usar
comandos que requieren privilegios de “root”? Es ahí donde entra en acción
nuestro script elastix-helper.
Uso de elastix-helper
elastix-helper es un script ubicado en /usr/bin el cual permite ejecutar scripts
privilegiados
que
se
encuentran
dentro
de
la
carpeta
“/usr/share/elastix/privileged”. Es aquí donde ubicaremos a nuestro script
que realizará tareas que necesiten privilegios de “root”, este script debe ser
propietario “root” y pertenecer al grupo “root” además tener permisos 755.
Para poder usarlo debemos ejecutar lo siguiente en la función que
deseemos de nuestra librería.
exec("/usr/bin/elastix-helper script_privileged parameter", $output, $ret);
•
script_privileged es el nombre del script privilegiado ubicado en la
ruta ya mencionada anteriormente.
Departamento de Desarrollo Elastix
11
parameter es el parámetro que se le pasará al script script_privileged,
se le puede pasar más de un parámetro, simplemente se los separa
con espacios, así como también pueden no pasarse parámetros.
Si el valor de $ret es 0 quiere decir que no hubieron problemas.
•
themes
Esta carpeta es la capa de vista. Al interior de esta carpeta encontraremos otra
carpeta llamada “default” la cual contendrá todas las vistas que podrá tener el
módulo. Por ejemplo, un módulo puede contener como vista principal una grilla, por
lo que se necesitará una vista (un archivo tpl) que contendrá los filtros para la grilla
(en caso de haberlos, caso contrario no se necesitaría un archivo tpl), y también
podría ser que al presionar un botón se muestre un formulario, por lo que
necesitaríamos otro archivo tpl que contendrá los campos del formulario. A
continuación mostraremos una plantilla típica de una vista para tpl y otra para un
formulario.
Plantilla típica de un módulo con vista grilla
<table width="99%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr class="letra12">
<td width="12%" align="left"><input class="button" type="submit"
name="new" value="{$New}"></td>
<td width="10%" align="left">  </td>
<td width="10%" align="right">
{$filter_type.LABEL}:  {$filter_type.INPUT}  
{$filter_txt.INPUT}
<input class="button" type="submit" name="show" value="{$SHOW}" />
</td>
</tr>
</table>
Como se puede observar en este módulo de grilla se consta con un botón “New” y
con un filtrado.
Plantilla típica de un módulo con vista formulario
<table width="99%" border="0" cellspacing="0" cellpadding="4" align="center">
<tr class="letra12">
<td align="left"><input class="button" type="submit" name="save"
value="{$SAVE}"></td>
</tr>
</table>
<br />
<div class="tabForm" style="font-size: 16px; height: auto;" width="100%">
<table style="font-size: 16px;" width="100%" cellspacing="0" cellpadding="8">
<tr class="letra12">
<td align="left" width="130px"><b>{$manufacturer.LABEL}: </b></td>
Departamento de Desarrollo Elastix
12
<td align="left">{$manufacturer.INPUT}</td>
</tr>
</table>
</div>
Para este formulario se consta con un botón “Save” y con un campo al cual se le
denominó “manufacturer”.
Estas son plantillas básicas, en realidad uno lo puede hacer tan complejo como
uno quiera.
Si es que queremos incluir javascripts en nuetro módulo, simplemente debemos
crear una carpeta llamada “js” dentro de themes/default y colocar ahi los javascripts
que queramos (deben tener extensión .js), así mismo si queremos incluir css hay
que crear una carpeta llamada “css” dentro de themes/default y colocar ahi los css
que queramos (deben tener extensión .css), el framework se encargará de incluir
estos archivos automáticamente.
index.php
El index.php del módulo representa la capa de control, el framework se encarga de
redirigir la petición a este archivo llamando a la función “_moduleContent”. Este
archivo es el que se encarga de comunicar con la capa de vista y de modelo.
Si es que hemos usado el developer para la creación del módulo, podremos
observar que este archivo ya viene escrito con una plantilla por default, y sobre
esta plantilla podemos hacer las modificaciones que queramos de acuerdo a la
necesidad de nuestro módulo.
Usando el Framework Elastix
Bien, hasta ahora ya tenemos creado nuestro módulo con una configuración básica
pero todavía no tenemos un claro conocimiento de las diferentes facilidades y
librerías que nos ofrece el framework Elastix.
A continuación se detallarán algunas librerías y clases con sus funciones más
importantes. Todas estas librerías se encuentran debajo de /var/www/html/libs
Librería misc.lib.php
En esta librería encontraremos funciones de diversos tipos, no es necesaria
incluirla en el módulo ya que el framework Elastix se encarga de esa tarea.
Listaremos las funciones de mayor relevancia y las que probablemente más
necesitaremos usar.
Departamento de Desarrollo Elastix
13
-
•
function _tr($s)
Esta función es la que utilizamos para realizar la traducción de algún texto.
Recibe como parámetro un string que es el texto a traducir. La función
trabaja de la siguiente manera: Busca el string pasado como parámetro en
las claves del arreglo de lenguajes del framework y del módulo (archivo
.lang dentro de la carpeta lang del módulo, escogerá el archivo
correspondiente al lenguaje que este configurado en el servidor Elastix), en
caso de encontrarla la función devuelve el valor del arreglo para esa clave,
caso contrario devuelve el mismo string pasado como parámetro.
Ejemplo:
Si tenemos seleccionado español como lenguaje y queremos la traducción
de “Hi this is my first module” que ya lo tenemos previamente definido en el
archivo en.lang simplemente hacemos lo siguiente:
$translate = _tr(“Hi this is my first module”);
•
function getParameter($parameter)
Esta función la utilizaremos cuando queremos obtener un parámetro que ha
sido enviado por POST or por GET. Busca el parámetro en el arreglo
$_POST, en caso de existir devuelve $_POST[$parameter], de no existir, lo
busca en el arreglo $_GET, si existe devuelve $_GET[$parameter], si no
existe en $_POST ni en $_GET esta función devuelve NULL.
Ejemplo:
Supongamos que tenemos un módulo con un botón que dice guardar y el
nombre del botón es “save” y queremos saber si ese botón fue presionado,
tendríamos que hacer lo siguiente:
if(getParameter(“save”))
De esta manera entrará en el if si es que el botón de guardar fue presionado.
•
function obtenerClaveCyrusAdmin($ruta_base='')
Esta función devuelve la clave de “admin” para el Cyrus. El parámetro
$ruta_base debe ser pasado como “/var/www/html/” si es que llamamos a
esta función fuera de esa ruta. Esta función parsea el archivo
/etc/elastix.conf y busca la palabra clave cyrususerpwd, en caso de
encontrarla devuelve su valor, caso contrario devuelve “palosanto” que es la
clave por omisión.
Departamento de Desarrollo Elastix
14
-
•
function obtenerClaveAMIAdmin($ruta_base='')
Esta función retorna la clave para AMI (Asterisk Manager Interface) del
usuario admin. El parámetro $ruta_base debe ser pasado como
“/var/www/html/” si es que llamamos a esta función fuera de esa ruta. Esta
función busca la clave en el archivo /etc/elastix.conf, si se encuentra la
palabra clave “amiadminpwd” se retorna el valor de esa clave, caso contrario
se retorna “elastix456” que es la clave AMI por default en Elastix.
•
function generarDSNSistema($sNombreUsuario, $sNombreDB,
$ruta_base='')
Ya nos habíamos topado antes en este manual con esta función. Pero
afianzaremos más lo que se dijo acerca de esta útil función. Como ya lo
habíamos mencionado antes esta función retorna el DSN (Data Source
Name) para una conexión con el motor de bases de datos mysql.
El parámetro $ruta_base debe ser pasado como “/var/www/html/” si es que
llamamos a esta función fuera de esa ruta.
El parámetro $sNombreUsuario es el usuario con el cual nos conectaremos
a mysql, puede ser “root” o “asteriskuser”.
El parámetro $sNombreDB es el nombre de la base de datos mysql a la cual
nos vamos a conectar.
•
function writeLOG($logFILE, $log)
Esta función permite escribir en un log. El parámetro $logFILE es el nombre
del archivo log, éste se ubicará debajo de /var/log/elastix. El parámetro $log
es el texto que se escribirá en el log. Si es que el archivo $logFILE no existe
lo crea, y si ya existe, añade al final del archivo el texto $log. Una vez más
recuerda que el servicio httpd que usa Elastix tiene como usuario a “asterisk”
por lo tanto sólo podrá escribir sobre archivos a los cuales “asterisk” tenga
permiso, en el caso de que $logFILE no exista, no hay problema ya que
“asterisk” es propietario de la carpeta /var/log/elastix por lo que podrá crear
archivos ahí sin inconvenientes.
Ejemplo:
Si queremos escribir “Ha ingresado al módulo de prueba” en un log llamado
“miModulo.log” tendríamos que hacer lo siguiente:
writeLOG(“miModulo.log”,”Ha ingresado al módulo de prueba”);
De esta forma se creará el log “miModulo.log” (de no existir) conteniendo lo
Departamento de Desarrollo Elastix
15
siguiente:
[Jan 19 14:48:11] Ha ingresado al módulo de prueba
La fecha a la izquierda es la fecha del servidor al momento de escribir el
mensaje en el log.
Clase paloSantoDB.class.php
Esta clase se encarga de crear un objeto con la conexión a una base de datos. El
objetivo de esta clase es encapsular o abstraerse del proceso de conexión a la
base de datos, de tal forma que el desarrollador simplemente tenga que instanciar
esta clase y pueda realizar los querys que desee. Esta clase tampoco es necesario
incluirla en nuestro módulo, ya que el framework Elastix se encarga de ello.
Para instanciar la clase se le debe pasar el DSN de la base de datos.
Ejemplo:
Supongamos que queremos instanciar una clase de paloDB en nuestro módulo
para crear una conexión a la base de datos mysql llamada “miBase” a la cual sólo
tiene acceso el usuario “root”. Tendríamos que hacer lo siguiente:
$dsn = generarDSNSistema(“root”,”miBase”);
$pDB = new paloDB($dsn);
Una vez instanciada esta clase recuerda pasarla por referencia a las funciones que
desees, esto será muy importante sobre todo cuando trabajemos con
transacciones.
A continuación se detallarán algunas de sus funciones.
•
function genQuery($query, $param = NULL)
Procedimiento para ejecutar una sentencia SQL que no devuelve filas ni
resultados, en caso de error se asigna a la variable de clase $this->errMsg.
Sólo es usado para hacer manipulación de los datos de la base.
El parámetro $query es el string que contiene al query que se va a ejecutar.
El parámetro $param es un arreglo que sólamente es pasado a esta función
cuando se realizan querys parametrizados, recuerda que es aconsejable que
todo query sea parametrizado, sobre todo cuando existen variables que son
ingresadas al servidor por el cliente.
Ejemplo:
Supongamos que queremos insertar en la tabla “miTabla” un nuevo registro
Departamento de Desarrollo Elastix
16
con los campos “campo1” y “campo2” con los valores $value1 y $value2
respectivamente que llegan al servidor mediante el cliente. Tendríamos que
realizar lo siguiente (supongamos que ya tenemos instanciada la clase con
el DSN a la base correspondiente en la variable $pDB).
$query = “INSERT INTO miTabla (campo1,campo2) VALUES (?,?)”;
$arrParam = array($value1, $value2);
$result = $pDB->genQuery($query,$arrParam);
if($result == FALSE)
echo _tr(“Query Error”).” ”.$pDB->errMsg;
else
echo _tr(“Query successfully executed”);
Es muy importante el orden que se coloca en el arreglo $arrParam ya que de
acuerdo a ese orden se van asignando los valores en el query.
•
function fetchTable($query, $arr_colnames = FALSE, $param = NULL)
Procedimiento que recupera todas las filas resultado de una petición SQL
que devuelve una o más filas.
Los parámetros $query y $param tienen los mismós propósitos que los
descritos en la función anterior.
El parámetro $arr_colnames será FALSE si deseamos que cada tupla tenga
como índice un número incremental, si es TRUE cada tupla tendrá como
índice el nombre de la columna.
Ejemplo:
Supongamos que deseamos imprimir en pantalla los valores de la columna
“campo1” de la tabla “miTabla” cuando el “campo2” tiene como valor
$value2, así mismo asumamos que ya contamos con el objeto $pDB.
$query = “SELECT campo1 FROM miTabla WHERE campo2=?”;
$arrParam = array($value2);
$result = $pDB->fetchTable($query,TRUE,$arrParam);
if($result === FALSE)
echo _tr(“Query Error”).” ”.$pDB->errMsg;
else{
if(count($result) > 0){
foreach($result as $value){
echo $value[“campo1”].”<br />”;
}
}
else
echo _tr(“There is no data for the criteria search”);
Departamento de Desarrollo Elastix
17
}
Siempre que usemos las funciones fetchTable o getFirstRowQuery
descrita más adelante, debemos comparar el valor devuelto de estas
funciones con una triple igualdad ===, recuerda que estas funciones
pueden devolver también arreglos vacíos que son evaluados como
FALSE también, usando === no solo comparamos por valor sino por
tipo de dato también.
•
function getFirstRowQuery($query, $arr_colnames = FALSE, $param =
NULL)
Procedimiento para recuperar una sola fila del query que devuelve una o
más filas. Devuelve una fila con campos si el query devuelve al menos una
fila, caso contrario devuelve un arreglo vacío o FALSE en caso de error.
Los parametros $query, $arr_colnames y $param tienen los mismos
propósitos que los descritos en la función fetchTable.
Ejemplo:
Supongamos que queremos imprimir en pantalla la cantidad de registros en
la tabla “miTabla” cuyo “campo1” tiene como valor $value1
$query = “SELECT COUNT(*) FROM miTabla WHERE campo1=?”;
$arrParam = array($value1);
$result = $pDB-> getFirstRowQuery($query,FALSE,$arrParam);
if($result === FALSE)
echo _tr(“Query Error”).” ”.$pDB->errMsg;
else
echo $result[0];
•
function beginTransaction()
Procedimiento para iniciar una transacción. Recuerda una transacción es
usada, cuando deseamos que en caso de que ocurra algún evento
inesperado o no deseado regrese la base a su estado anterior.
•
function rollBack()
Procedimiento de rollBack para una transacción.
Departamento de Desarrollo Elastix
18
-
•
function commit()
Procedimiento de commit para una transacción.
Ejemplo:
Supongamos que queremos crear una función que inserte en la tabla
“miTabla1” (la cual tiene como id el campo “id” que es autoincremental) los
valores $value1 y $value2 en los campos “campo1” y “campo2”
respectivamente (no puede haber otro registro que tenga exactamente los
mismos valores tanto en “campo1” como en “campo2”), luego de esto
deseamos insertar en la tabla “miTabla2” el id del registro recién ingresado
en la tabla “miTabla1” en el campo “id_miTabla1” y en el campo “fecha” la
fecha actual.
function insertRegister($value1, $value2, &$pDB, &$errMsg)
{
$pDB->beginTransaction();
$query1 = “INSERT INTO miTabla1 (campo1,campo2) VALUES (?,?)”;
$arrParam1 = array($value1, $value2);
$result1 = $pDB->genQuery($query1,$arrParam1);
if($result1 == FALSE){
$pDB-> rollBack();
$errMsg = $pDB->errMsg;
return FALSE;
}
else{
$query2 = “INSERT INTO miTabla2 (id_miTabla1,fecha)
VALUES((SELECT id FROM miTabla1 WHERE
campo1=? AND campo2=?),?)”;
$arrParam2 = array($value1,$value2,date('Y-m-d H:i:s'));
$result2 = $pDB->genQuery($query2,$arrParam2);
if($result2 == FALSE){
$pDB->rollBack();
$errMsg = $pDB->errMsg;
return FALSE;
}
else{
$pDB->commit();
return TRUE;
}
}
}
Departamento de Desarrollo Elastix
19
Observemos que el objeto $pDB fue pasado por referencia a la función, lo
cual es necesario para que la transacción tenga el comportamiento deseado.
Clase paloSantoACL.class.php
Esta clase se encarga de administrar los controles de acceso para los diferentes
tipos de usuarios. El framework Elastix la incluye automáticamente.
Para instanciar la clase se debe pasar el string DSN para la conexión a la base de
datos “acl.db” o también se le puede pasar un objeto que sea una instancia de la
clase paloDB que se le haya pasado el DSN para “acl.db”.
La variable $arrConf['elastix_dsn']['acl'] contiene ya el DSN para “acl.db”, esta
variable es creada por el framework. Por lo tanto si queremos instanciar a esta
clase dentro de nuestro módulo haríamos lo siguiente:
global $arrConf;
$pACL = new paloACL($arrConf['elastix_dsn']['acl']);
Esta clase es algo delicada y podría llegar a comprometer el sistema si es mal
usada. Es recomendable que se use sólamente las funciones descritas a
continuación y dejar a los módulos de Elastix por default que se encarguen de las
demás tareas de administración de usuarios.
•
function getUserExtension($username)
Procedimiento para obtener la extensión de un usuario mediante su
username. Como ya es de imaginarse, el parámetro $username es el
nombre del usuario al cual deseamos obtener su extensión asociada.
Ejemplo:
Supongamos que queremos obtener la extensión asociada al usuario
logoneado.
//El usuario logoneado se almacena en la
$_SESSION[“elastix_user”]
$username = $_SESSION[“elastix_user”];
$extension = $pACL->getUserExtension($username);
•
variable
de
sesión
function isUserAdministratorGroup($username)
Procedimiento para saber si un usuario pertenece al grupo “administrador”.
Así mismo el parámetro $username es el nombre del usuario al cual
deseamos saber si pertenece o no al grupo “administrador”.
Departamento de Desarrollo Elastix
20
Ejemplo:
Si deseamos que nuestro módulo haga ciertas tareas si el usuario
logoneado es del grupo “administrador” y otras si es que no, podríamos
hacer lo siguiente:
$username = $_SESSION[“elastix_user”];
if($pACL->isUserAdministratorGroup($username)){
//Do some task for administrators
}
else{
//Do some task for non administrators
}
Clase paloSantoConfig.class.php
Esta clase es muy útil sobre todo para parsear archivos de configuración,
permitiéndonos leer o escribir sobre los mismos.
Esta clase si es necesario incluirla en nuestro módulo en caso de requerir de ella.
include_once “libs/paloSantoConfig.class.php”;
Esta clase tiene el siguiente constructor:
function paloConfig($directorio, $archivo, $separador="", $separador_regexp="",
$usuario_proceso=NULL)
Donde $directorio es la ruta donde se encuentra el archivo, $archivo es el archivo a
parsear, $separador es el string que separa la palabra clave con su valor,
$separador_regexp es una expresión regular para interpretarla como separador,
$usuario_proceso es el usuario que inicia el proceso. Como se puede observar solo
$directorio y $archivo son parámetros requeridos, el resto son opcionales y tienen
valores por omisión.
Supongamos tenemos el archivo de configuración /etc/miModulo.conf el cual
contiene lo siguiente:
user = usuario
password = 12345
email = [email protected]
privileges = all
Ahora vamos a instanciar a la clase paloConfig para parsear este archivo.
$pConfig = new paloConfig(“/etc”,”miModulo.conf”,” = ”,”\s*=\s*”);
Departamento de Desarrollo Elastix
21
De esta forma iremos a parsear el archivo “/etc/miModulo.conf” el cual tiene como
separador el signo “=” y puede o no estar acompañado de espacios en blanco a los
lados.
Ahora detallaremos las principales funciones de la clase paloConfig.
•
function leer_configuracion($bComentarios=true)
Este procedimiento inicia la lectura del archivo almacenándola en un arreglo
asociativo que se devuelve como respuesta. Si el parámetro $bComentarios
es FALSE entonces sólo se encontrará en el arreglo los valores que no son
comentarios, y el arreglo de vuelta tendrá como ínidices las palabras claves
del archivo, pero si es TRUE entonces en el arreglo devuelto se encontrará
tanto comentarios como valores de configuración, y los índices de éste
serán numéricos.
•
function escribir_configuracion($arr_reemplazos, $overwrite=FALSE)
Este procedimiento sirve para escribir en el archivo de configuración. El
parámetro $arr_reemplazos es un arreglo que contiene los cambios a
realizar, donde el índice del arreglo representa la palabra clave a modificar
en el archivo, si es que en el archivo se encuentra la palabra clave entonces
la modifica y si es que no la encuentra la agrega. Si el parámetro $overwrite
es FALSE entonces se harán los cambios contenidos en $arr_reemplazos
pero se mantendrá intacto el resto del archivo, pero si es TRUE entonces el
archivo será sobreescrito por $arr_reemplazos
•
function privado_get_valor($lista, $clave)
Procedimiento que devuelve el valor de una palabra clave del archivo. El
parámetro $lista es el arreglo que contiene el archivo de configuración. El
parámetro $clave es la palabra clave a buscar en el archivo.
Ejemplo:
Supongamos que tenemos el archivo /etc/miModulo.conf con la misma
información que ya se describió más arriba, y queremos hacer lo siguiente:
si “password” es igual a “12345” entonces la cambiamos a “new12345”.
include_once “libs/paloSantoConfig.class.php”;
$pConfig = new paloConfig(“/etc”,”miModulo.conf”,” = ”,”\s*=\s*”);
$content = $pConfig->leer_configuracion(FALSE);
$password = $pConfig->privado_get_valor($content,”password”);
if($password == “12345”){
$arrReplaces = array(“password” => “new12345”);
$pConfig->escribir_configuracion($arrReplaces);
}
Departamento de Desarrollo Elastix
22
Clase paloSantoForm.class.php
Esta clase nos sirve para manejar de una manera sencilla los módulos tipo
formulario. Es necesaria incluirla en nuestro módulo en caso de desear usarla.
El constructor de esta clase tiene la siguiente forma:
function paloForm(&$smarty, $arrFormElements)
Donde $smarty es una instancia de smarty, (la cual es pasada a la función
_moduleContent de nuestro módulo) y $arrFormElements es un arreglo de
arreglos que contiene los elementos del formulario. En el arreglo principal, los
índices representan el id del elemento y en el arreglo secundario debe siempre
existir un índice llamado “INPUT_TYPE” el cual indica el tipo del elemento que se
quiere. El valor de “INPUT_TYPE” puede ser uno de los siguientes: “TEXTAREA”,
“TEXT”, “CHECKBOX”, “PASSWORD”, “HIDDEN”, “FILE”, “RADIO”, “SELECT” o
“DATE”. Donde cada una de estas palabras represena el elemento que se desea. A
continuación se mostrarán ejemplos para cada uno de estos de tipos de elementos.
Al final de estos ejemplos se explicará sobre los demas elementos del arreglo.
TEXTAREA
Ejemplo:
Se desea un textarea cuyo label sea “descripción” y que tenga 6 columnas y 4 filas.
$arrFormElements = array(
"description" => array( "LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
"ROWS"
"COLS"
),
);
=> _tr("Description"),
=> "yes",
=> "TEXTAREA",
=> array("style" => ”width:400px"),
=> "text",
=> "",
=> "4",
=> "6"
TEXT
Ejemplo:
Se desea un input para ingresar el nombre de un cliente.
$arrFormElements = array(
"name" => array( "LABEL"
"REQUIRED"
=> _tr("Name"),
=> "yes",
Departamento de Desarrollo Elastix
23
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
=> "TEXT",
=> array("style" => ”width:200px"),
=> "text",
=> ""
);
CHECKBOX
Ejemplo:
Se desea un checkbox que diga “Enable”.
$arrFormElements = array(
"enable" => array( "LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
);
=> _tr("Enable"),
=> "yes",
=> "CHECKBOX",
=> " ",
=> "text",
=> ""
NOTA: Al crear elementos de este tipo, el framework automáticamente crea dos
elementos, uno es el checkbox propiamente dicho y el otro es un hidden que cuyo
valor es “on” en caso de estar activado el checkbox u “off” caso contrario. Por lo
tanto si en nuestro módulo queremos saber si el checkbox fue activado o no,
tendríamos que hacer lo siguiente:
$enable = getParameter(“enable”);
if($enable == “on”){
//Do something
}
else{
//Do something
}
PASSWORD
Ejemplo:
Se desea un campo para que el usuario ingrese una contraseña.
$arrFormElements = array(
"password" => array( "LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
=> _tr("Password"),
=> "yes",
=> "PASSWORD",
=> array("style" => ”width:200px"),
Departamento de Desarrollo Elastix
24
"VALIDATION_TYPE"
=> "text",
"VALIDATION_EXTRA_PARAM" => ""
),
);
HIDDEN
Ejemplo:
Se desea tener un campo oculto para almacenar el id de un usuario.
$arrFormElements = array(
"id" => array( "LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
);
=> " ",
=> "yes",
=> "HIDDEN",
=> " ",
=> "text",
=> ""
FILE
Ejemplo:
Se desea un campo para poder pasar la ruta de un archivo.
$arrFormElements = array(
"file" => array( "LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
);
=> _tr("File"),
=> "yes",
=> "FILE",
=> " ",
=> "filename",
=> ""
RADIO
Ejemplo:
Se desea 2 radio buttons para indicar el género de una persona.
$gender = array(“m” => _tr(“Male”), “f” => _tr(“Female”));
$arrFormElements = array(
"gender" => array( "LABEL"
=> _tr("Gender"),
"REQUIRED"
=> "yes",
"INPUT_TYPE"
=> "RADIO",
"INPUT_EXTRA_PARAM"
=> $gender,
Departamento de Desarrollo Elastix
25
"VALIDATION_TYPE"
=> "text",
"VALIDATION_EXTRA_PARAM" => ""
),
);
SELECT
Ejemplo:
Se desea un combo para seleccionar el método de pago que va a realizar un
cliente, siendo las opciones “efectivo”, “tarjeta de crédito”, “cheque”, “transferencia
bancaria”.
$paymentMethod = array(“cash” => _tr(“Cash”), “credit_card” => _tr(“Credit Card”),
“check” => _tr(“Check”),“bank_transfer” => _tr(“Bank Transfer”));
$arrFormElements = array(
"paymentMethod" => array( "LABEL" => _tr("Payment Method"),
"REQUIRED"
=> "yes",
"INPUT_TYPE"
=> "SELECT",
"INPUT_EXTRA_PARAM"
=> $paymentMethod,
"VALIDATION_TYPE"
=> "text",
"VALIDATION_EXTRA_PARAM" => ""
),
);
DATE
Ejemplo:
Se desea un campo para ingresar la fecha en la cual se realizó un pago.
$arrFormElements = array(
"paymentDate" => array( "LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
=> _tr("Payment Date"),
=> "yes",
=> "DATE",
=> "",
=> "ereg",
=> "^[[:digit:]]{1,2}[[:space:]]+[[:alnum:]]
{3}[[:space:]]+[[:digit:]]{4}$"
),
);
El formato por default de la fecha es el día en dos dígitos, luego espacio seguido
del mes en formato de tres letras, luego espacio y el año en cuatro dígitos. Si se
desea cambiar este formato simplemente habría que colocar en
“INPUT_EXTRA_PARAM” el nuevo formato, y si deseamos también poder ingresar
la hora colocamos “TIME” => true.
Departamento de Desarrollo Elastix
26
Por ejemplo si queremos que el formato sea yyyy-mm-dd h:m:s
"INPUT_EXTRA_PARAM"=>array(“TIME” => true, “FORMAT” => “%Y-%m-%d %H:
%M:%S”),
Como se pudo observar en los ejemplos anteriores existen índices que coincidían
en todos y otros que simplemente eran propios del tipo de elemento, como por
ejemplo el índice “COLS” en el “TEXTAREA”. Ahora explicaremos sobre los índices
comunes u obligatorios.
•
LABEL: El valor de este índice, como su nombre lo indica, será la etiqueta
descriptiva que se muestra junto al elemento.
•
REQUIRED: El valor de este índice puede ser “yes” o “no”, si es “yes”
entonces este campo es obligatorio para poder guardar el formulario, caso
contrario este puede quedar en blanco.
•
INPUT_TYPE: Tipo de elemento, ya descrito previamente.
•
INPUT_EXTRA_PARAM: Parámetros adicionales al input, pueden ser estilos
o atributos extras. Estos deben pasarse como arreglo, caso contrario debe
ser un string vacío.
•
VALIDATION_TYPE: Indica el tipo de validación que se le va a aplicar al
valor ingresado por el usuario. Los valores pueden ser los siguientes:
•
text - El usuario puede ingresar cualquier cosa.
•
ereg - Se debe pasar en VALIDATION_EXTRA_PARAM una expresión
regular, y se le permitirá ingresar al usuario sólo un texto que coincida
con le expresión regular ingresada.
•
filename - Se valida que lo que se ingrese en ese campo sea el nombre
de un archivo.
•
domain - Se valida que lo que se ingrese en ese campo se el nombre
de un dominio.
•
filepath - Se valida que lo que se ingrese en ese campo sea una ruta a
un archivo.
•
ip - Se valida que lo que se ingrese en ese campo sea una dirección ip.
•
mask - Se valida que lo que se ingrese en ese campo sea una máscara
de red.
•
ip/mask - Se valida que lo que se ingrese en ese campo sea una
dirección ip seguido de “/” y la máscara de red en formato decimal.
•
numeric - Se valida que lo que se ingrese en ese campo sea un
número.
•
float - Se valida que lo que se ingresa en ese campo sea un número
flotante (decimal con el punto como separador).
•
numeric_array - Se valida que lo que se ingresa en ese campo sea un
arreglo cuyos elementos sean números.
•
ereg_array - Se valida que lo que se ingresa en ese campo sea un
arreglo con valores que deben coincidir con la expresión regular pasada
en VALIDATION_EXTRA_PARAM.
•
email - Se valida que lo que se ingresa en ese campo sea una dirección
Departamento de Desarrollo Elastix
27
de correo electrónico.
•
VALIDATION_EXTRA_PARAM: Se pasa un parámetro adicional en caso de
que lo requiera VALIDATION_TYPE, como para el caso de “ereg”.
A continuación se describirán las funciones que ofrece esta clase.
•
function fetchForm($templateName, $title, $arrPreFilledValues = array())
Esta función genera una cadena que contiene un formulario HTML. Para
hacer esto, toma una plantilla de formulario (que es la pasada en el
parámetro $templateName) e inserta en ella los elementos de formulario. El
parámetro $title es el título que tendrá el formulario y el parámetro
$arrPreFilledValues es un arreglo que contiene valores por defecto para el
formulario, donde el índice es el id del elemento y el valor es el (valga la
redundancia) valor que tendría ese campo por defecto.
•
function validateForm($arrCollectedVars)
Esta función devuelve TRUE en caso de que los datos ingresados en el
formulario fueron correctos, caso contrario FALSE. El parámetro
$arrCollectedVars contiene los valores ingresados en el formulario.
Ejemplo:
Supongamos que deseamos un módulo tipo formulario, el cual tenga los
campos: “Nombre” que es una caja de texto, “Apellido” que es una caja de
texto, “Género” que es un radio button que puede ser masculino o femenino,
“Email” que es una caja de texto y “Estado Civil” que puede ser Soltero,
Viudo, Casado, Divorciado o Unión Libre. Todos estos campos son
requeridos. También hay un botón “Save” que al presionar se validan los
datos ingresados, en caso de haber un error se mantiene persistencia en los
datos y se indica el error, caso contrario se muestra un mensaje indicando
los datos ingresados.
File themes/default/form.tpl
<table width="100%" border="0" cellspacing="0" cellpadding="4" align="center">
<tr class="letra12">
<td align="left">
<input class="button" type="submit" name="save" value="{$SAVE}">
</td>
<td align="right" nowrap><span class="letra12"><span
class="required">*</span> {$REQUIRED_FIELD}</span></td>
</tr>
</table>
<table class="tabForm" style="font-size: 16px;" width="100%" >
Departamento de Desarrollo Elastix
28
<tr class="letra12">
<td align="left" width="130px"><b>{$name.LABEL}: <span
class="required">*</span></b></td>
<td align="left">{$name.INPUT}</td>
</tr>
<tr class="letra12">
<td align="left"><b>{$last_name.LABEL}: <span
class="required">*</span></b></td>
<td align="left">{$last_name.INPUT}</td>
</tr>
<tr class="letra12">
<td align="left"><b>{$gender.LABEL}: <span
class="required">*</span></b></td>
<td align="left">{$gender.INPUT}</td>
</tr>
<tr class="letra12">
<td align="left"><b>{$email.LABEL}: <span
class="required">*</span></b></td>
<td align="left">{$email.INPUT}</td>
</tr>
<tr class="letra12">
<td align="left"><b>{$marital_status.LABEL}: <span
class="required">*</span></b></td>
<td align="left">{$marital_status.INPUT}</td>
</tr>
</table>
File index.php
<?php
include_once "libs/paloSantoForm.class.php";
function _moduleContent(&$smarty, $module_name)
{
//include module files
include_once "modules/$module_name/configs/default.conf.php";
//include file language agree to elastix configuration
//if file language not exists, then include language by default (en)
$lang=get_language();
$base_dir=dirname($_SERVER['SCRIPT_FILENAME']);
$lang_file="modules/$module_name/lang/$lang.lang";
if (file_exists("$base_dir/$lang_file")) include_once "$lang_file";
else include_once "modules/$module_name/lang/en.lang";
Departamento de Desarrollo Elastix
29
//global variables
global $arrConf;
global $arrConfModule;
global $arrLang;
global $arrLangModule;
$arrConf = array_merge($arrConf,$arrConfModule);
$arrLang = array_merge($arrLang,$arrLangModule);
//folder path for custom templates
$templates_dir=(isset($arrConf['templates_dir']))?
$arrConf['templates_dir']:'themes';
$local_templates_dir="$base_dir/modules/$module_name/".$templates_dir.'/'.
$arrConf['theme'];
//conexion resource
//$pDB = new paloDB($arrConf['dsn_conn_database']);
$pDB = ""; //In this case we do not use a database
//actions
$action = getAction();
$content = "";
switch($action){
case "save":
$content = saveTestModule($smarty, $module_name, $local_templates_dir);
break;
default: // view_form
$content = viewFormTestModule($smarty, $module_name,
$local_templates_dir);
break;
}
return $content;
}
function viewFormTestModule($smarty, $module_name, $local_templates_dir)
{
$arrFormTestModule = createFieldForm();
$oForm = new paloForm($smarty,$arrFormTestModule);
//begin, Form data persistence to errors and other events.
$_DATA = $_POST;
$smarty->assign("SAVE", _tr("Save"));
$smarty->assign("REQUIRED_FIELD", _tr("Required field"));
$smarty->assign("icon", "images/list.png");
Departamento de Desarrollo Elastix
30
$htmlForm = $oForm->fetchForm("$local_templates_dir/form.tpl",_tr("Test
Module"), $_DATA);
$content = "<form method='POST' style='margin-bottom:0;' action='?
menu=$module_name'>".$htmlForm."</form>";
return $content;
}
function saveTestModule($smarty, $module_name, $local_templates_dir)
{
$arrFormTestModule = createFieldForm();
$oForm = new paloForm($smarty,$arrFormTestModule);
if(!$oForm->validateForm($_POST)){
// Validation basic, not empty and VALIDATION_TYPE
$smarty->assign("mb_title", _tr("Validation Error"));
$arrErrores = $oForm->arrErroresValidacion;
$strErrorMsg = "<b>"._tr("The following fields contain
errors").":</b><br/>";
if(is_array($arrErrores) && count($arrErrores) > 0){
foreach($arrErrores as $k=>$v)
$strErrorMsg .= "$k, ";
}
$smarty->assign("mb_message", $strErrorMsg);
return viewFormTestModule($smarty, $module_name, $local_templates_dir);
}
else{
//Here are extra validations
$name = getParameter("name");
$last_name = getParameter("last_name");
$gender = getParameter("gender");
$email = getParameter("email");
$marital_status = getParameter("marital_status");
if(!in_array($gender,array("male","female"))){
$smarty->assign("mb_title", _tr("Validation Error"));
$smarty->assign("mb_message", _tr("The gender can only be \"male\" or
\"female\""));
return viewFormTestModule($smarty, $module_name,
$local_templates_dir);
}
elseif(!
in_array($marital_status,array("single","widowed","married","divorced","cohabiti
ng"))){
$smarty->assign("mb_title", _tr("Validation Error"));
$smarty->assign("mb_message", _tr("The marital status can only
be \"single\", \"widowed\", \"married\", \"divorced\" or \"cohabiting\""));
Departamento de Desarrollo Elastix
31
return viewFormTestModule($smarty, $module_name,
$local_templates_dir);
}
else{
$smarty->assign("mb_title", _tr("Message"));
$message = _tr("The following data was entered").":<br />";
$message .= "<b>"._tr("Name").":</b> ".htmlentities($name)."<br
/><b>"._tr("Last Name").":</b> ".htmlentities($last_name)."<br
/><b>"._tr("Gender").":</b> ".htmlentities($gender)."<br
/><b>"._tr("Email").":</b> ".htmlentities($email)."<br /><b>"._tr("Marital
Status").":</b> ".htmlentities($marital_status);
$smarty->assign("mb_message",$message);
}
}
return viewFormTestModule($smarty, $module_name, $local_templates_dir);
}
function createFieldForm()
{
$gender = array("male" => _tr("Male"), "female" => _tr("Female"));
$marital_status = array("single" => _tr("Single"), "widowed" =>
_tr("Widowed"), "married" => _tr("Married"), "divorced" => _tr("Divorced"),
"cohabiting" => _tr("Cohabiting"));
$arrFields = array(
"name"
=> array("LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
"last_name" => array("LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
"gender" => array("LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
=> _tr("Name"),
=> "yes",
=> "TEXT",
=> "",
=> "text",
=> ""
=> _tr("Last Name"),
=> "yes",
=> "TEXT",
=> "",
=> "text",
=> ""
=> _tr("Gender"),
=> "yes",
=> "RADIO",
=> $gender,
=> "text",
=> ""
Departamento de Desarrollo Elastix
32
),
"email"
=> array("LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
"VALIDATION_EXTRA_PARAM"
),
"marital_status" => array("LABEL"
"REQUIRED"
"INPUT_TYPE"
"INPUT_EXTRA_PARAM"
"VALIDATION_TYPE"
=> _tr("Email"),
=> "yes",
=> "TEXT",
=> "",
=> "email",
=> ""
=> _tr("Marital Status"),
=> "yes",
=> "SELECT",
=> $marital_status,
=> "text",
"VALIDATION_EXTRA_PARAM" => ""
),
);
return $arrFields;
}
function getAction()
{
if(getParameter("save"))
return "save";
else
return "report";
}
?>
Vista del módulo tipo formulario según el código descrito anteriormente
Departamento de Desarrollo Elastix
33
Clase paloSantoGrid.class.php
Esta clase nos sirve para manejar de una manera sencilla los módulos tipo grilla.
Es necesaria incluirla en nuestro módulo en caso de desear usarla.
El constructor de esta clase tiene la siguiente forma:
function paloSantoGrid($smarty)
Donde $smarty es una instancia de smarty (la cual es pasada a la función
_moduleContent de nuestro módulo).
Esta clase cuenta con las siguientes funciones:
•
function addNew($task="add", $alt="New Row", $asLink=false)
Esta función permite agregar un elemento a la grilla cuya funcionalidad es la
de añadir un nuevo dato mostrado en la grilla. El parámtro $task será el
atributo “name” del elemento, el parámetro $alt es el label que se mostrará
para el elemento y el parámetro $asLink es TRUE si el elemento será un link
caso contrario será un input tipo submit.
•
function customAction($task="task", $alt="Custom Action", $img="",
$asLink=false)
Esta función permite agregar un elemento a la grilla. El parámtro $task será
el atributo “name” del elemento, el parámetro $alt es el label que se mostrará
para el elemento, el parámetro $asLink es TRUE si el elemento será un link
caso contrario será un input tipo submit y el parámetro $img es la ruta a una
imagen que será el ícono representativo del elemento.
•
function deleteList($msg="", $task="remove", $alt="Delete Selected",
$asLink=false)
Esta función permite agregar un elemento a la grilla cuya funcionalidad es la
de eliminar uno o más datos mostrado en la grilla. El parámetro $msg será
el mensaje de confirmación que aparecerá, el parámtro $task será el atributo
“name” del elemento, el parámetro $alt es el label que se mostrará para el
elemento y el parámetro $asLink es TRUE si el elemento será un link caso
contrario será un input tipo submit.
•
function addLinkAction($href="action=add", $alt="New Row", $icon=null,
$onclick=null)
Esta función permite agregar un elemento a la grilla tipo link. El parámetro
$href es hacia dónde apunta el link, el parámetro $alt es el label que se
Departamento de Desarrollo Elastix
34
mostrará para el elemento, el parámetro $icon es la ruta a una imagen que
será el ícono representativo del elemento y el parámetro $onclick es el
evento que se va a vincular al hacer click en dicho link (opcional).
•
function addSubmitAction($task="add", $alt="New Row", $icon=null,
$onclick=null)
Esta función permite agregar un elemento a la grilla tipo submit. El
parámetro $task es el atributo “name” del elemento, el parámetro $alt es el
label que se mostrará para el elemento, el parámetro $icon es la ruta a una
imagen que será el ícono representativo del elemento y el parámetro
$onclick es el evento que se va a vincular al hacer click en dicho elemento
(opcional).
•
function addButtonAction($name="add", $alt="New Row", $icon=null,
$onclick="javascript:click()")
Esta función permite agregar un elemento a la grilla tipo botón. El parámetro
$name es el atributo “name” del elemento, el parámetro $alt es el label que
se mostrará para el elemento, el parámetro $icon es la ruta a una imagen
que será el ícono representativo del elemento y el parámetro $onclick es el
evento que se va a vincular al hacer click en dicho elemento (opcional).
•
function addInputTextAction($name_input="add", $label="New Row",
$value_input="", $task="add", $onkeypress_text=null)
Esta función permite agregar un elemento a la grilla tipo “input text”. El
parámetro $name_input es el atributo “name” del elemento, el parámetro
$label es el label que se mostrará para el elemento, el parámetro
$value_input es el valor por default del input, el parámetro $task es la acción
que se envía al servidor al presionar el “botón” asociado a la caja de texto y
el parámetro $onkeypress_text es el evento que se asociará a la caja de
texto cada vez que se presiona una tecla.
•
function addComboAction($name_select="cmb", $label="New Row",
$data=array(), $selected=null, $task="add", $onchange_select=null)
Esta función permite agregar un elemento a la grilla tipo “combo box”. El
parámetro $name_select es el atributo “name” del elemento, el parámetro
$label es el label que se mostrará para el elemento, el parámetro $data es
un arreglo con los datos del combo, el parámetro $selected es el elemento
seleccionado por default, el parámetro $task es la acción que se envía al
servidor al presionar el “botón” asociado al combo y el parámetro
$onchange_select es el evento que se asociará al combo cada vez que se
cambia el valor del combo.
Departamento de Desarrollo Elastix
35
-
•
function addHTMLAction($html)
Esta función permite agregar un nuevo elemento tipo html a la grilla. El
parámtro $html es el código html a añadir.
•
function addFilterControl($msg, &$arrData, $arrFilter = array(),
$always_activated=false)
Esta función permite agregar un controlador de filtro en la grilla (mensajes
en color púrpura aparecen cuando el filtro es aplicado). El parámetro $msg
es el mensaje que aparecerá al aplicar el filtro, el parámetro $arrData es el
arreglo con los datos, este nos sirve para saber si el filtro está siendo
aplicado o no, el parámetro $arrFilter es un arreglo que nos sirve para
asociar dos o más filtros como uno sólo, donde la clave del arreglo es el
nombre del elemento del filtro y el valor es el valor default que tendrá. Y el
parámetro $always_activated será true si es que deseamos que siempre se
muestre el controlador de filtro, caso contrario se deja en false.
Clase paloSantoJSON.class.php
Esta clase sirve para codificar en formato JSON. Nos puede ser de gran ayuda
cuando se haga una petición AJAX al servidor, y enviarle la respuesta al cliente en
formato JSON. Codifica un arreglo de tres elementos, cuyos índices son “error”, en
esta se almacenan los errores en caso de haberlos, “statusResponse” que
almacena un estado de la respuesta, por default se setea en OK y “message” que
almacena la respuesa deseada.
Debemos incluir esta clase en nuestro módulo en caso de desear usarla.
El constructor es el siguiente:
function PaloSantoJSON()
Cuenta con las siguientes funciones:
•
function createJSON()
Codifica la respuesta en JSON con el formato mencionado anteriormente.
•
function set_error($error)
Setea el valor del índice “error” por lo que tenga el parámetro $error.
Departamento de Desarrollo Elastix
36
-
•
function set_status($status)
Setea el valor del índice “statusResponse” por lo que tenga el parámetro
$status.
•
function set_message($message)
Setea el valor del índice “message” por lo que tenga el parámetro
$message.
AJAX en Elastix
El framework Elastix también cuenta con una función javascript para realizar
peticiones AJAX!!. Esta función es la siguiente:
function request(url,arrParams, recursive, callback)
El parámetro “url” es la dirección a la cual se hace la petición (usualmente será
“index.php”). El parámetro “arrParams” es un arreglo que contiene los parámetros
que recibirá el servidor. El parámetro “recursive” es un booleano, este será TRUE
si deseamos que la misma petición AJAX se vuelva a realizar una vez el servidor
responda, y si deseamos detenerlo en algún momento, la función “callback” debe
retornar TRUE. Finalmente el parámetro “callback” es una función que será
invocada una vez que el servidor responda.
Ejemplo:
Se desea crear una función javascript que realice una petición AJAX al módulo
“testModule”. Esta función recibe como parámetro un texto el cual se debe pasar al
servidor. El servidor debe responder el texto traducido en el languaje que este
seleccionado en el servidor Elastix en caso de contar con esa traducción, caso
contrario devolverá el mismo texto. En el cliente se debe mostrar un alert con el
texto devuelto por el servidor.
Archivo testModule/themes/default/js/javascript.js
function getTextTranslate(text)
{
var arrAction
= new Array();
arrAction["menu"]
= "testModule";
arrAction["action"]
= "translate";
arrAction["text"]
= text;
arrAction["rawmode"] = "yes"; //Remember, this is necessary because in
this way the server will only response the content of the module that will be a JSON.
request("index.php",arrAction,false,
Departamento de Desarrollo Elastix
37
function(arrData,statusResponse,error)
{
//The variable statusResponse contains the value assigned to
statusResponse in the JSON response.
//The variable error contains tha value assigned to error in the JSON
response.
//The variable arrData contains the value assigned to message in the
JSON response.
alert(arrData);
}
);
}
Archivo testModule/index.php
<?php
include_once "libs/paloSantoForm.class.php";
include_once "libs/paloSantoJSON.class.php";
function _moduleContent(&$smarty, $module_name)
{
/* Typical headers of the module like the last example.
.....
.....
.....
*/
$action = getAction();
$content = "";
switch($action){
case "save":
$content = saveTestModule($smarty, $module_name,
$local_templates_dir);
break;
case "translate":
$content = translateText();
break;
default: // view_form
$content = viewFormTestModule($smarty, $module_name,
$local_templates_dir);
break;
}
return $content;
Departamento de Desarrollo Elastix
38
}
/* Here goes the functions saveTestModule and viewFormTestModule like the last
example
....
....
....
*/
function translateText()
{
$jsonObject = new PaloSantoJSON();
$text
= getParameter("text");
$translated = _tr($text);
$jsonObject->set_message($translated);
return $jsonObject->createJSON();
}
function getAction()
{
if(getParameter("save"))
return "save";
elseif(getParameter("action") == "translate")
return "translate";
else
return "report";
}
Convertir un módulo en un Addon
Es común confundirse y pensar que un módulo y un addon son la misma cosa, al
final de cuentas los dos por lo general terminan siendo un nuevo menú de Elastix.
Sin embargo un addon es algo mucho más complejo que un módulo.
Un addon es un paquete de software certificado por PaloSanto Solutions y que se
encuentra disponible en formato RPM a través de un repositorio oficial. Un addon
puede contener un módulo, pero además también puede contener otros
componentes de software, escritos en cualquier lenguaje soportado por Elastix. La
instalación de un addon se realiza de manera sencilla e intuitiva a través del menú
“Addons” desde la interfaz Web de Elastix.
Dicho lo anterior es importante aclarar que un módulo de Elastix sí se puede
convertir en un addon. Para hacer esto es necesario empaquetar el módulo en
formato RPM e iniciar un proceso de certificación de software interoperable con
Elastix.
Departamento de Desarrollo Elastix
39
-
Esqueleto del fuente para el empaquetado
Usualmente el fuente contendrá un archivo XML y dos carpetas principales. El
archivo y carpetas respectivamente son: “menu.xml”, “modules” y “setup”.
•
El archivo menu.xml es un XML que contiene los módulos que serán integrados a
Elastix, indicando la ubicación, nombre, tipo, permisos,etc.
Ejemplo:
Se desea crear un archivo menu.xml, para un módulo padre llamado “Parent
Module” con id “parent_module” ubicado debajo del módulo PBX en la posición 6.
Además habrán dos módulos más el primero será “Test Module” con id
“test_module” ubicado dentro de “parent_module” en la primera posición. Y el
módulo “Link Module” con id “link_module” el cual es un módulo tipo link para
acceder al servidor en el puerto 8080. A estos módulos sólo pueden ingresar por
default los usuarios del grupo administrador.
<?xml version="1.0" encoding="UTF-8"?>
<module>
<menulist>
<menuitem menuid="parent_module" desc="Parent Module" parent="pbxconfig"
module="no" link="" order="6">
<permissions>
<group id="1" name="administrator" desc="total access"></group>
</permissions>
</menuitem>
<menuitem menuid="test_module" desc="Test Module" parent="parent_module"
module="yes" link="" order="61">
<permissions>
<group id="1" name="administrator" desc="total access"></group>
</permissions>
</menuitem>
<menuitem menuid="link_module" desc="Link Module" parent="parent_module"
module="no" link="http://{NAME_SERVER}:8080" order="62">
<permissions>
<group id="1" name="administrator" desc="total access"></group>
</permissions>
</menuitem>
</menulist>
</module>
Como se puede observar, dentro de la etiqueta “menulist” van todos los módulos y
cada módulo se describe mediante la etiqueta “menuitem” donde el atributo
“menuid” es el id del módulo, el atributo “desc” es la etiqueta que se mostrará en la
Departamento de Desarrollo Elastix
40
interfaz web, el atributo “parent” es el id del módulo que lo contendrá, el atributo
“module” puede ser “yes” si es que es un módulo propiamente dicho o “no” si es
que es un módulo padre o si es un módulo tipo link, el atributo “link” es el link al
cual apuntará el módulo y el módulo “order” es el orden que ocupará el módulo.
En la etiqueta “permissions” se detallan los grupos de usuarios que tendrán acceso
por default al módulo.
Ahora lo único que hay que hacer es usar el script elastix-menumerge pasándole el
archivo XML para que quede realizada la integración con Elastix. Así mismo si
deseamos remover algún menú, se ejecuta el script elastix-menuremove pasándole
el id del mismo. Esto se lo debe realizar en el archivo spec.
•
La carpeta “modules” contiene todos los módulos incluídos en el addon.
•
La carpeta “setup” contiene archivos de configuración o scripts necesarios para el
correcto funcionamiento de algún módulo. Además, en caso de usar alguna base
de datos local contará con una carpeta llamada “db”, dentro de esta carpeta
encontraremos un archivo llamado “db.info” y tres carpetas: “install”, “update” y
“delete”.
El archivo db.info contiene información necesaria acerca de la base de datos. Tiene
una cabecera indicando el nombre de la base, luego la palabra clave
“ignore_backup” que será igual a “yes” en caso de que no se desee hacer un
backup de una base existente con el mismo nombre, caso contrario será “no”.
También tiene la palabra clave “engine” que indica el motor que usará la base (en
Elastix se usa “sqlite3” o “mysql”), luego la palabra clave “path” que indica la ruta en
donde se encuentra la base (para sqlite3 es “/var/www/db” y para mysql es
“/var/lib/mysql”) y finalmente la palabra clave deletable que será “yes” si se desea
poder eliminar la base cuando se desinstala el paquete, caso contrario será “no” (el
hecho de tener este campo en “yes” no significa que la base se eliminará
automáticamente al desinstalar el paquete, simplemente abre esa posibilidad y lo
que se deberá hacer es colocar un script de eliminación de la base en la carpeta
“delete”).
Ejemplo:
Construir un archivo db.info para un addon que tendrá que una base de datos
sqlite3 llamada “myDBSqlite” la cual se debe hacer un backup en caso de existir y
no debe poder ser eliminable, y una base de datos mysql llamada “myDBMysql”
con las mismas caracerísticas.
[myDBSqlite]
ignore_backup = no
engine = sqlite3
path = /var/www/db
deletable = no
Departamento de Desarrollo Elastix
41
[myDBMysql]
ignore_backup = no
engine = mysql
path = /var/lib/mysql
deletable = no
Dentro de la carpeta “install” habrá una carpeta para cada base de datos con el
mismo nombre de la base. Dentro de esta carpeta habrá scripts sql que sólo se
ejecutarán en la instalación del paquete (y se aplicarán sobre la base de datos
correspondiente al nombre de la carpeta). Estos scripts tendrán los nombres
“1_schema.sql”, “2_schema.sql”, “3_schema.sql”, etc (usualmente sólo se
necesitará de uno), el número de prefijo es importante porque indica el orden de
ejecución. Para bases de datos “sqlite3” simplemente se crean tablas y se añaden
registros por default (de ser necesarios) pero para bases mysql también es
necesario la creación de la base (CREATE DATABASE dbname;) seguido de un
USE dbname; para de ahi si proseguir con la creación de las tablas y demás.
En la carpeta “update” así mismo habrá una carpeta para cada base de datos con
el mismo nombre de la base. Dentro de cada una de estas carpetas habrá otra
carpeta llamada “version_sql” que contendrán los scripts sql de actualización. El
nombre de estos scripts es sumamente importante, deben tener la siguiente
estructura:
#number_#lastVersion_#newVersion.sql
Donde:
#number es el orden de ejecución del script.
#lastVersion es la última versión existente.
#newVesion es la nueva versión a lanzar, este script sólo se ejecutará para
versiones menores a #newVesion.
Ejemplo:
¿Cuál será el nombre de scripts sql de actualización para:
1. Un script de actualización que debe ser el primero y en cuyo momento la
última versión lanzada fue 2.2.0-2 y sólo se debe ejecutar para versiones
menores a 2.2.0-3.
2. Otro script de actualización que es el segundo en ejecutarse y en cuyo
momento la última versión lanzada fue la 2.2.0-6 y sólo se debe ejecutar
para versiones menores a 2.2.0-7
Para el primer script sería: 1_2.2.0-2_2.2.0-3.sql
Para el segundo script sería: 2_2.2.0-6_2.2.0-7.sql
Nótese que siempre será #lastVersion < #newVesion, además el orden de
ejecución de los scripts va de la mano con las versiones, es decir a mayor orden
mayores versiones.
En una instalación además de ejecutarse los scripts de la carpeta “install”, se
Departamento de Desarrollo Elastix
42
ejecutarán todos los scripts de la carpeta “update”.
La carpeta “delete” también contendrá carpetas con el mismo nombre de la base de
datos, las cuales contendrán scripts sql para la desinstalación de la base con el
nombre “1_dbname.sql”, “2_dbname.sql”, “3_dbname.sql”, etc.
Es recomendable no eliminar las bases en la desinstalación del paquete
El script que se encarga de leer y ejecutar estos archivos es el “elastix-dbprocess”
que debe ser invocado en el archivo spec.
Archivo spec
Una vez armado el fuente ahora es cuestión de crear el archivo spec, para terminar
con el proceso de construcción del RPM o empaquetado.
A continuación se mostrará un pequeño ejemplo de un archivo spec sin entrar en
mayores detalles, ya que se asume que el desarrollador tiene claros conocimientos
en cuanto a la construcción de paquetes RPM.
%define modname example
Summary: Elastix Module Example
Name: elastix-%{modname}
Version: 2.2.0
Release: 1
License: GPL
Group: Applications/System
Source0: %{modname}_%{version}-%{release}.tgz
BuildRoot: %{_tmppath}/%{name}-%{version}-root
BuildArch: noarch
Prereq: elastix-framework >= 2.2.0-25
%description
Elastix Module Example
%prep
%setup -n %{modname}
%install
rm -rf $RPM_BUILD_ROOT
# Files provided by all Elastix modules
mkdir -p $RPM_BUILD_ROOT/var/www/html/
mv modules/ $RPM_BUILD_ROOT/var/www/html/
Departamento de Desarrollo Elastix
43
-
# The following folder should contain all the data that is required by the installer,
# that cannot be handled by RPM.
mkdir -p $RPM_BUILD_ROOT/usr/share/elastix/module_installer/%{name}-%{version}%{release}/
mv setup/ $RPM_BUILD_ROOT/usr/share/elastix/module_installer/%{name}-%{version}%{release}/
mv menu.xml $RPM_BUILD_ROOT/usr/share/elastix/module_installer/%{name}-%
{version}-%{release}/
%pre
mkdir -p /usr/share/elastix/module_installer/%{name}-%{version}-%{release}/
touch /usr/share/elastix/module_installer/%{name}-%{version}-%{release}/preversion_%
{modname}.info
if [ $1 -eq 2 ]; then
rpm -q --queryformat='%{VERSION}-%{RELEASE}' %{name} >
/usr/share/elastix/module_installer/%{name}-%{version}-%{release}/preversion_%
{modname}.info
fi
%post
pathModule="/usr/share/elastix/module_installer/%{name}-%{version}-%{release}"
# Run installer script to fix up ACLs and add module to Elastix menus.
elastix-menumerge $pathModule/menu.xml
pathSQLiteDB="/var/www/db"
mkdir -p $pathSQLiteDB
preversion=`cat $pathModule/preversion_%{modname}.info`
if [ $1 -eq 1 ]; then #install
# The installer database
elastix-dbprocess "install" "$pathModule/setup/db"
elif [ $1 -eq 2 ]; then #update
elastix-dbprocess "update" "$pathModule/setup/db" "$preversion"
fi
%clean
rm -rf $RPM_BUILD_ROOT
%preun
if [ $1 -eq 0 ] ; then # Validation for desinstall this rpm
echo "Delete example menus"
elastix-menuremove "%{modname}"
Departamento de Desarrollo Elastix
44
-
# Here you should call to elastix-dbprocess for deleting, the same way that it was for
install, just that instead of word “install” goes word “delete”. But this is not often used due
to the databases usually are not deleted
fi
%files
%defattr(-, asterisk, asterisk)
%{_localstatedir}/www/html/*
/usr/share/elastix/module_installer/*
%changelog
* Mon Jan 30 2012 Alberto Santos <[email protected]> 2.2.0-1
–
Initial version.
Finalización del proceso de certificación.
Una vez elaborado el RPM, se procede a firmar el contrato y enviar el
empaquetado
a
paloSanto
Solutions,
puede
ser
al
correo
[email protected] o [email protected] junto con un manual de
usuario, para proceder con la revisión del mismo. Una vez este sea aprobado
pasará a formar parte de los repositorios de Elastix y se convertirá en un Addon de
Elastix.
Si tienes alguna duda respecto al proceso de certificación o cualquier aspecto
puntual del framework Elastix puedes enviar un correo a cualquiera de las dos
direcciones mencionadas.
Departamento de Desarrollo Elastix
45
Descargar