PATROCINADO

Liferay 7 y expandos o campos personalizados

Índice de contenidos

Liferay 7 y expandos o campos personalizados. Flexibilidad en entidades Liferay

Primeramente, con este artículo de Liferay 7 y expandos o campos personalizados pretendo explicar esta funcionalidad, muchas veces mal usada. Veamos. En Liferay gestionamos diferentes entidades como usuarios, roles, contenidos y un muy largo etcétera. Los formularios que permiten su gestión, se componen de un número concreto de campos. Las clases del API de Liferay que permiten gestionar esas entidades desde código, tienen relación directa por tanto, con esos campos. Añadir nuevos campos implicaría entre otras cosas, extender las clases API relacionadas (si queremos proceder adecuadamente). Liferay nos proporciona un mecanismo para añadir campos personalizados a esas entidades: los expandos o campos personalizados.

¿Qué son los expandos?

En realidad, lo dicho más arriba: campos personalizados. ¿Queremos añadir un campo para el DNI de los usuarios?¿Quizás un número de socio a los usuarios considerados como tales?¿Necesitamos discriminar documentos para mediadores de seguros?¿Nos piden agregar datos adicionales a los eventos de un calendario? Y mucho más… Como he comentado, gran cantidad de las entidades que conforman Liferay, permiten utilizar estos campos personalizados o expandos. ¿Por qué el nombre expandos? Pues de expandir, lógicamente. Y aunque actualmente siempre aparece campo personalizado en la interfaz, cuando nos vamos a código trabajamos con expandos. Sin embargo, esto no queda aquí. Si bien desde la interfaz de Liferay podemos gestionar campos expandos, si utilizamos el API que provee Liferay para ellos, dispondremos además, de la capacidad de crear nuevas tablas (virtuales). Esto quiere decir que, en la práctica, podemos crear tablas nuevas sin necesidad de añadir capas adicionales, etc. Para empezar y antes de aprender como gestionar estos expandos (CRUD) desde la interfaz de Liferay, comentaros que todas las entidades que los permiten, dispondrán de un área donde pueden verse. Al principio y como es lógico, no habrá ninguno dado de alta y por tanto, estas áreas apareceran vacías. Tendremos que ir a un área específica de administración para poder gestionarlos.

Gestionar los expandos

Para dar de alta, modificar o eliminar los expandos, debemos ir al [Panel de Control/Configuración/Campos personalizados] en el área administrativa de Liferay. Hecho esto, aparecerá el panel de Recursos donde se mostrarán las posibles entidades sobre las que podemos dar de alta expandos:
  • Artículo de contenido web
  • Carpeta de contenido web
  • Carpeta de documentos
  • Categoría de mensajes
  • Documento
  • Enlaces
  • Entrada de blog
  • Entrada de marcadores
  • Evento de calendario
  • Artículo de contenido web
  • Grupo de usuarios
  • Mensaje del foro
  • Organización
  • Página
  • Página del Wiki
  • Rol
  • Sitio Web
  • Usuario
Liferay 7 y expandos o campos personalizados. Accediendo al alta de expando de usuario Pulsando en la entidad a la queremos añadir un expando, accederemos al listado de campos personalizados actualmente dados de alta en la entidad (de usuarios en la imagen). Una vez allí, podemos realizar altas, ediciones y eliminaciones.

Altas de expandos

Accedemos al formulario de alta de un expando tras seleccionar la entidad sobre la que queremos darlo de alta y, una vez en el listado de expando de esa entidad, pulsamos en el botón azul con el [+]. Antes de ser creado el nuevo expando, solamente aparecen dos campos en el formulario de alta: – clave: identificador único que le damos al expando y que podremos usar para acceder al expando desde código. – tipo: tipo del campo personalizado o expando. Una vez hemos indicado los datos necesarios, pulsamos en el botón [Guardar] y se generará el nuevo expando que, ojo, ya no podremos cambiar de clave ni tipo. El campo Tipo es un desplegable dividido en dos áreas: preestablecidos y primitivos, siendo los campos de la primera área más complejos:
Preestablecidos
  • Conjunto de valores de números enteros.
  • Conjunto de valores decimales.
  • Conjunto de valores de texto.
  • Caja de texto.
  • Caja de texto indexada.
  • Campo de texto oculto.
  • Campo de texto indexado. Campo de texto que, por defecto, podrá ser utilizado para realizar búsquedas.
Primitivos
  • Verdadero o falso. Da a escoger Sí o No.
  • Fecha. Permite usar un selector de fechas y horas para establecer el valor.
  • Número decimal (64 bits). Permite introducir un número decimal de hasta esa precisión.
  • Conjunto de números decimales (64 bits). Permite elegir entre los decimales indicados de hasta esa precisión.
  • Número decimal (32 bits). Decimales de hasta esa precisión.
  • Conjunto de números decimales (32 bits). A elegir entre decimales de hasta esa precisión.
  • Número entero (32 bits). Enteros de hasta esa precisión.
  • Conjunto de números enteros (32 bits). A elegir números enteros de hasta ese tamaño.
  • Número entero (64 bits). Números enteros de hasta ese tamaño.
  • Conjunto de números enteros (64 bits). Permite seleccionar un número concreto de valores enteros de hasta ese tamaño.
  • Número decimal o entero (32 bits) y Número decimal o entero (64 bits). Permitirá almacenar números enteros y decimales de hasta el tamaño y precisión indicadas.
  • Número entero (16 bits). Permitirá introducir números enteros de hasta ese tamaño.
  • Conjunto de números enteros (16 bits). Aparecerá un control con diferentes números enteros entre los que tendremos que elegir. Más o menos tamaño posible de los números dependiendo de la cantidad de bits.
  • Texto. Muestra un campo de texto común.
  • Conjunto de valores de texto. Genera un control con diferentes textos entre los que deberemos elegir como valor del campo.
  • Texto localizado. Permite localizar el valor del campo.

Edición de expandos existentes

Será posible editar los expandos existentes accediendo desde el listado de campos personalizados dados de alta en la entidad elegida. Una vez allí, solamente hay que pulsar en el nombre que del expando en el listado o bien desplegar el menú de acciones del expando elegido y seleccionar [Editar]. Debemos tener en cuenta que lo único que podemos editar de un expando ya dado de alta, son sus propiedades pero nunca su clave y tipo.

Bajas de expandos

Para dar de baja un expando o campo personalizado, es suficiente con pulsar en la acción de [Eliminar] que se desplegará en el menú de acciones, en el listado de expandos en el que nos encontremos. Recordemos que este menú de acciones está representado por tres puntos verticales. Únicamente se nos pedirá confirmación del borrado que si es afirmativa, se procederá a borrar.
¡CUIDADO!
Cuando borramos un campo personalizado, se borrarán todos los valores asigados a éste en cada instancia de la entidad a la que perteneciera. Ejemplo: si teníamos un campo DNI en la entidad Usuario y lo borramos, todos los DNI de todos los usuarios serán eliminados.
 

Lógica de los expandos

La lógica detrás de los expandos está basada en cuatro tablas de la base de datos de Liferay:
TablaUso
expandotableAlmacena los datos de las tablas temporales. Por defecto, Liferay guarda los expandos contra una sola tabla virtual: CUSTOM_FIELDS:
  • tableId: id único para la tabla virtual.
  • companyId: id de la instancia de Liferay a la que pertenece, según la tabla company.
  • classNameId: id de la clase de la entidad sobre la que se crea el campo personalizado, según la tabla classname_.
  • name: nombre de la tabla virtual. En este campo, aparecerá casi siempre el nombre CUSTOM_FIELDS.
expandocolumnGuarda los datos relativos al campo expando:
  • columnId: id único para el campo.
  • companyId: id de la instancia de Liferay.
  • tableId: id de la tabla virtual.
  • name: identificador del campo expando. Este nombre se utiliza para poder obtener el valor de un campo expando desde código.
  • type_: entero que identifica al tipo de campo personalizado o expando.
  • defaultData: valor por defecto del campo.
  • typeSettings: propiedades en formato clave=valor que permiten cambiar los atributos por defecto del tipo de campo seleccionado.
expandorowRegistro virtual relacionado con la tabla también virtual. Cada vez que almacenamos un valor en un campo expando, se añade un registro virtual:
  • rowId_: id único para el registro.
  • companyId: id de la instancia de Liferay.
  • modifiedDate: fecha de modificación del registro.
  • tableId: id de la tabla virtual.
  • classPK: id de clase primario.
expandovalueAlmacena los valores de todos los campos personalizados.
  • valueId: id único para el valor.
  • companyId: id de la instancia de Liferay.
  • tableId: id de la tabla virtual.
  • columnId: id de la columna o campo expando al que pertenece el valor.
  • rowId_: id del registro del valor.
  • classNameId: id del nombre de la clase.
  • classPK: id único de la clase.
  • data_: valor almacenado del campo expando.
Liferay 7 - Tablas de expandos

Campos expandos en plantillas Velocity

Para acceder a los campos expando de cualquier entidad como un contenido web, Liferay nos provee de la clase ExpandoBridgeImpl . Además, observaremos que se nos proporcionan métodos para más tareas como la adición de campos, etc. Gracias a que todas las entidades que pueden utilizar campos expando, disponen de un método getExpandoBridge() que devuelve un objeto de la clase citada más arriba. Utilizándolo, accedemos al campo expando de esa entidad:
$article.getExpandoBridge().getAttribute("ISBN")
En el ejemplo, se accede al campo personalizado «ISBN» de un contenido web representado por la variable Velocity, $article.

Los expandos en plantillas Freemarker

En realidad, lo que hemos de hacer es lo mismo que lo explicado para Velocity, aplicando por supuesto la sintaxis Freemarker:
<#assign mediadorSitio = layout.getGroup().getExpandoBridge().getAttribute("MEDIADOR")>
Suponiendo en el ejemplo que el sitio actual tiene un campo personalizado MEDIADOR.

Acceder a los expandos desde Java

Finalmente, ¿cómo accedemos al valor de un expando desde el código Java de un portlet o módulo personalizado? En primer lugar, del mismo modo que hemos visto en las plantillas, usando: entidad.getExpandoBridge().getAttribute("ID_CAMPO_PERSONALIZADO"). Sin embargo aquí hemos de tener en cuenta los permisos. Si un visitante (rol Guest en Liferay) visita una página que contiene un portlet (…aplicación, módulo…) que lee un determinado campo personalizado, si los permisos sobre ese campo no están correctamente definidos, obtendremos como resultado finalmente: null. Para evitar esto, debemos dar los permisos adecuados al campo personalizado que queremos leer desde el portlet al usuario visitante (insisto, rol Guest) para que pueda leerlo. La otra posibilidad, más complicada pero más flexible y potente, es usar el API de los Expandos. Para empezar, la clase ExpandoValueLocalServiceUtil nos permitirá acceder al expando (entre otras cosas): Como resultado obtendremos un objeto de tipo ExpandoValue . Usaremos alguno de los métodos para obtener el valor deseado, como indica el ejemplo, donde finalmente, se obtendrá una cadena:
ExpandoValue idMediador = ExpandoValueLocalServiceUtil.getValue(PortalUtil.getCompanyId(objetoRequest), User.class.getName(), "CUSTOM_FIELDS", "MEDIADOR", user.getPrimaryKey());
String mediador = idMediador.getString();
/* TENGAMOS EN CUENTA ESTOS DATOS RELEVANTES... 
- El segundo parámetro es User.class.getName(): la clase de la entidad que contiene el expando.
- "CUSTOM_FIELDS": la constante que identifica la tabla virtual de expandos.
- "MEDIADOR": el identificador del expando cuando se creó.
- El último parámetro es user.getPrimaryKey: el PrimaryKey del usuario del que queremos obtener el valor del campo personalizado.*/
¡OJO!
En el ejemplo presuponemos que el campo personalizado es de tipo Texto. Si fuese de tipo Texto Localizado, el método empleado para obtener el valor del ExpandoValue debería ser idMediador.getString(PortalUtil.getLocale(objetoRequest)), ya que sería una cadena localizada.
 

Expandos en código JSP y utilizando tags de Liferay

Por supuesto podemos hacer uso de scriplets en nuestras páginas JSP y aplicar los visto un poco más arriba pero sabemos bien que no es el camino adecuado. A veces no queda más remedio pero en la medida de lo posible usaremos juegos de etiquetas o tags junto con los scriplets indispensables. En conclusión y siguiendo las buenas prácticas propuestas por Liferay, usaremos en las páginas JPSs, etiquetas: JSP, EL, JSTL y los taglibs de Liferay. Efectivamente, Liferay pone a nuestra disposición juegos de etiquetas o taglibs para muy diversos trabajos. El que nos interesa en este punto es el que tiene como namespace liferay-ui. Aquí teneis el JavaDoc y una pequeña descripción . Curiosamente, en el momento de escribir esta entrada, no están reflejadas las siguientes etiquetas en el JavaDoc y sin embargo, si nos situamos en la carpeta /WEB-INF/tld de nuestra instalación de Liferay y editamos (con Notepad++ por ejemplo) el fichero liferay-ui.tld, veremos que existen estas tags o etiquetas: custom-attribute, custom-attribute-list y custom-attributes-available. Igualmente, si usamos las etiquetas, veremos que funcionan perfectamente, mostrándonos un campo del tipo elegido para cada expando, el valor o valores, etc.

Ejemplo de uso con custom-attribute-list para la entidad Liferay, User (usuario):

<%-- Lista los campos personalizados existentes para la entidad indicada, así como sus valores en
aquellos que lo tuvieran. --%>
<%@page import="com.liferay.portal.kernel.theme.ThemeDisplay"%>
<%@page import="com.liferay.portal.kernel.model.User"%>
<%@ page import = "com.liferay.portal.kernel.util.WebKeys" %>
 
<%
ThemeDisplay tema = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
User usuario = tema.getUser();
%>
 
 	 	 	 	 	 	

Ejemplo de uso con custom-attribute para obtener un campo expando determinado de un usuario en concreto:

<%-- Muestra el campo "DNI", en el tipo de campo dado de alta, con el valor que estuviera almacenando, para el usuario logado actualmente. --%>
<%@page import="com.liferay.portal.kernel.theme.ThemeDisplay"%>
<%@page import="com.liferay.portal.kernel.model.User"%>
<%@ page import = "com.liferay.portal.kernel.util.WebKeys" %>
 
<%
ThemeDisplay tema = (ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
User usuario = tema.getUser();
%>
 
 	 	 	 	 	 	
Los atributos utilizados en las etiquetas son:
  • className: nombre de la clase de la entidad Liferay consultada.
  • classPK: id del objeto (instancia de la entidad Liferay) consultado.
  • editable: si podemos editar los valores del campo mostrado.
  • name: identificador del campo expando consultado.
  • label: si queremos que aparezca o no, la etiqueta del campo, cuando se muestre en la interfaz.
La etiqueta custom-attributes-available es similar a custom-attributes-list, mostrándonos aquellos campos expando o personalizados, disponibles. Los ejemplos muestran el uso de las etiquetas mencionadas pero adicionalmente tendremos que añadir un formulario y una lógica que procese ese formulario para que los datos que añadamos o modifiquemos en esos cambios queden registrados.

Gestionando expandos desde código

Este es el plato fuerte. Usando el API de Liferay hemos visto que podemos obtener los valores de expandos, usados para extender el número de campos de tablas existentes de Liferay. De hecho, podemos usar el API desde Java, Velocity y Freemarker para ser exactos. Lo que no suele saberse, es que podemos agregar tablas virtuales a la base de datos de Liferay y, mediante el API de los expandos, gestionar esas tablas y sus datos (¿una tabla personalizada con códigos postales por ejemplo?). Las siguientes clases obran la magia, una por cada tabla expando: Adicionalmente, nos será imprescindible esta otra clase que nos permitirá indicar el tipo de las columnas de las tablas virtuales: com.liferay.expando.kernel.model.ExpandoColumnConstants También necesitaremos indicar el valor classPK que es un identificador único. Si es para trabajar con un recurso preexistente, el recurso proveerá de un método que devuelva ese valor. Si en cambio, como pretendemos ahora, queremos agregar un nuevo recurso (tabla, campo, fila, valor…) necesitamos ese id único. No es necesario que lo calculemos nosotros:
// Generamos un classPK único para un nuevo usuario, por ejemplo:
long classPK = CounterLocalServiceUtil.increment(User.class.getName());

// Generamos un classPK genérico:
long classPK = CounterLocalServiceUtil.increment();
En esta URL disponéis de un ejemplo de uso de trabajo con el API de expandos aunque es para la versión 6.2 de Liferay que es fácilmente adaptable a la versión 7: https://sourceforge.net/projects/meeralferay/files/LiferayExpandoAPIExample/ . Es un ejemplo realizado por el usuario de Liferay, Meera Prince . Finalmente, mencionar que es posible además que es posible hacer uso de llamadas a los servicios remotos del API de Liferay, desde JavaScript por ejemplo, tal como se indica en este artículo del Developer Network de Liferay: https://dev.liferay.com/es/develop/tutorials/-/knowledge_base/7-0/invoking-liferay-services . Necesitaremos las mismas clases indicadas arriba cuyo resumen está presente aquí: https://docs.liferay.com/portal/7.0-ga7/javadocs/portal-kernel/com/liferay/expando/kernel/service/package-summary.html . Veamos un ejemplo:
//Añadimos un valor al campo personalizado DNI de la entidad User de Liferay, a un usuario concreto:
 Liferay.Service(
  '/expandovalue/add-value',
  {
    companyId: 1001010,
    className: 'com.liferay.portal.kernel.model.User',
    tableName: 'CUSTOM_FIELDS',
    columnName: 'DNI',
    classPK: 10101,
    data: '578326598J'
  },
  function(obj) {
    console.log(obj);
  }
);

Recomendación y conclusiones

En resumen, los expandos o campos personalizados nos proveen de un sistema sumamente potente y flexible que nos permite escalar las entidades de Liferay y el modelo de datos de Liferay en general. Esto sin embargo tiene un precio que ya habréis podido deducir: intervienen cuatro tablas en la base de datos; cada vez que se quiere leer un expando, se consultan cuatro tablas… Ahora imaginad cien usuarios accediendo al mismo lugar al mismo tiempo. Sacad vuestras propias conclusiones. Por ese motivo, yo personalmente recomiendo su uso siempre y cuando no se usen en exceso o no tengamos otra opción por culpa de los requerimientos (tiempos, dificultad, etc.). Nada más, un saludo y hasta otra.

3 comentarios

  1. Muy bien explicado, me gustaría ver un ejemplo en freemarker trayendo información de un campo personalizado de un usuario, blos, etc. en especifico

    1. Muchas gracias Rodolfo por tu comentario y petición. Sí, la verdad es que estaría bien seguir con más artículos sobre expandos y lo que sugieres es ideal. Apuntado y nota pegada con imán a la puerta del frigorífico para que no se pierda. Una cosa, ¿has probado ya los objetos personalizados de Liferay Portal 7.4?

      Por cierto, no olvides visitar el canal de Youtube, tal vez encuentres material que te interese y si es así, suscríbete. Un cordial saludo.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Foto Perfil
JOSÉ MANUEL DOMÍNGUEZ ROMERO
Más de 20 años formando y desarrollando, siempre aprendiz, ahora emprendedor que intenta compartir toda esa experiencia y conocimientos.
X

¡¡¡ ÚLTIMAS DONACIONES !!!

🏆 Catalina Gasco Leonarte 🏆

¿Me invitas a un café?

¿Necesitas clases particulares de programación?

Reserva conmigo y recíbelas a través de Skype, Zoom, Hangouts, Discord o similar.

Clases particulares

PATROCINADORES

(Los patrocinadores incluyen enlaces de afiliados, con cuyos servicios llevamos años, sin queja alguna y por tanto contrastados y recomendados por nosotros)

GANA DINERO CON FIVERR