Contenedores

De Egeasy
Saltar a: navegación, buscar

¿Qué es un contenedor?

Un contenedor es un recurso fundamental de ODL que nos permite crear objetos en un sistema de información.

Pero, ¿y qué función cumplen los objetos en ODL?

Su principal función es representar aquellos elementos o conceptos físicos que intervienen en el sistema de información de una organización. Elementos tales como fichas, ficheros, informes, registros, oficinas, etc., son ejemplos de elementos que puede generar un sistema de información y que podrán ser representados en ODL.

¿Qué definiciones podemos realizar?

En ODL, existen dos formas de definir un contenedor:

Definiciones de tipo

Una definición de tipo nos permite crear objetos en un sistema de información. Es un concepto basado en POO, donde se define una clase con su posterior creación de objetos u otras clases derivadas.

La estructura del objeto vendrá definida, valga la redundancia, en la definición de tipo. Formularios, secciones o campos son algunos de los componentes que podremos incluir en la definición y que nos permitirán introducir la información que almacenará el objeto. Una vez creado el objeto, podrá ser editado o eliminado por el usuario, siempre y cuando tenga los permisos necesarios para poder realizar dichas operaciones.

NOTA: Existen varios casos en los que un objeto no puede ser eliminado:

  • Si un objeto tiene un campo timbre o firma, y el campo timbre está timbrado o el campo firma está firmado, el objeto no se podrá eliminar.
  • Otra posibilidad que se puede dar es que un objeto puede estar "apuntado" por otros objetos mediante un campo vínculo. En este caso, tampoco se podría eliminar el objeto.
  • El último caso está relacionado con el workflow del sistema de información. Si un objeto es el target de alguna tarea, y ésta no ha sido abortada, dicho objeto tampoco podrá ser eliminado.
  • También hay que tener en cuenta los roles que tenga asignados el usuario, ya que en al menos uno de ellos debe tener incluído el siguiente permiso: accede [Definición de contenedor]: crear;. Este permiso permite al usuario crear, modificar, abrir o eliminar un objeto de la definición en cuestión. Los permisos abrir o eliminar no permite eliminar objetos.

Definiciones de sistema

Una definición de sistema permite crear objetos al crear un centro. Los objetos creados en la instalación de un centro los denominaremos objetos de sistema.

Aunque en ODL se puede definir cualquier componente en un contenedor, en los objetos de sistema normalmente se suele utilizar la componente colección para realizar visualizaciones de objetos, o, en su defecto, catálogos. Estos componentes nos permitirán realizar visualizaciones personalizadas de los tipos de objetos que se desee, especificando la información a mostrar. A diferencia de las definiciones de tipo, el usuario no podrá crear, modificar o eliminar los objetos de sistema; será una tarea exclusiva del programador.

Veamos un ejemplo

Vamos a realizar un sencillo ejemplo de forma que podamos reflejar en un caso práctico los conceptos anteriormente explicados.

Imaginemos que tenemos una estantería vacía. Y en esa estantería iremos insertando libros con el transcurso del tiempo. Veamos pues como podemos trasladar este caso a lenguaje ODL usando contenedores.

¿Cómo implementamos una definición de tipo?

Como ya hemos dicho, ODL nos ofrece una serie de componentes que podremos utilizar en la definición de un tipo contenedor. Los componentes más comunes son formularios, secciones y campos.

Un campo es la unidad más básica para la introducción de datos. Una sección es un conjunto de campos y un formulario es un conjunto de secciones y campos. Éstos nos permitirán introducir la información relativa a un objeto.

Por tanto, para el concepto de Libro realizaremos una definición de tipo, usando los componentes antes mencionados, que nos permitirá crear un objeto por cada libro que insertemos en la estantería:

tipo [Libro] es contenedor
   [Datos] es formulario
      [Código] es timbre
         -certificado.valor = [&Valor_secuencia];
         -certificado.secuencia.nombre = "STR$LIBRO";
         -certificado.secuencia.longitud = 4;
      [Título] es texto
      [Autor] es texto
      [Edición] es texto
      [Editorial] es texto
[Contenido] es seccion [Tipo] es texto -edicion.valores = $Matriz("Literario","Biografía","Científico","Infantil"); -apariencia.desplegable = verdadero; [Sinopsis] es texto -edicion.longitud = 1000; fin fin fin
Nuestra definición de tipo ya está creada. Como podrás observar, hemos definido un formulario dentro del contenedor, que a su vez contiene varios campos y una sección que nos va a permitir introducir la información perteneciente a cada libro. Existe un campo timbre que se utiliza para autonumerar, en este caso, los libros que vayamos registrando. Los demás campos son todos de tipo texto.

Otro elemento que aparece en la definición que no hemos comentado son los atributos. Los atributos intervienen en todas las definiciones de ODL, y sirven para configurar el comportamiento de las definiciones. Los atributos que aquí se contemplan son relativos a campos y no nos detendremos en explicar su funcionamiento. En este mismo documento, abordaremos con mayor profundidad los atributos que afectan directamente a los contenedores.

Ahora, veamos cómo se refleja el código en la aplicación egExplorer de forma que nos permita crear objetos de tipo Libro:
Crear un objeto en egExplorer

Una vez rellenado los campos, guardaremos el objeto. Pero, ¿cómo puedo obtener un listado de los libros que voy introduciendo? ¿Cómo puedo "ver mi estantería"?

¿Cómo implementamos una definición de sistema?

Nos disponemos a crear una instancia del sistema, un elemento estático en el que podremos visualizar los objetos que hemos creado. La forma de definir un objeto de sistema es similar a la definición de tipo pero sin incluir la palabra reservada tipo. Es decir, [nombre] es contenedor. Sin más preámbulos, veamos como se define nuestra "estantería":


[Estantería 1] es contenedor
   [Contenido] es coleccion
      -nombre_tabla = "TC$LIBROS";
contiene [Libro]
columna [Código] -columna_bd.nombre = "CÓDIGO"; -origen = [Datos].[Código];
columna [Título] -columna_bd.nombre = "TÍTULO"; -origen = [Datos].[Título];
columna [Autor] -columna_bd.nombre = "AUTOR"; -origen = [Datos].[Autor];
columna [Sinopsis] -columna_bd.nombre = "SINOPSIS"; -origen = [Datos].[Contenido].[Sinopsis]; fin fin

Como ya hemos dicho, un contenedor puede almacenar componentes. En este caso, se utiliza la componente colección para visualizar los objetos creados. En la colección, especificamos los campos que queremos visualizar además de especificar el tipo de objetos.

A continuación veremos el contenido de nuestra estantería:

Abrir un objeto de sistema

Al hacer clic en Estantería 1 accedemos a un objeto de sistema, que al tener contenida una colección, ésta se abrirá, y se visualizará el listado de los libros incluídos en nuestra estantería. Una vez en la colección, podremos crear aquellos contenedores que estén definidos en ella, que en este caso, sólo podrán ser de tipo Libro.

Crear un nuevo contenedor dentro de un objeto de sistema

Propiedades de un contenedor

En ODL, cada contenedor que sea crea en el sistema adquiere una serie de propiedades. Éstas almacenan información relativa a cada contenedor creado, que puede resultar útil en tareas de mantenimiento del sistema de información:

  • Nombre: es el nombre que adquiere el objeto. Si no se especifica, adquiere el nombre de la definición.
  • ID: identificador del contenedor. Valor entero único generado para cada contenedor del sistema.
  • Tipo: tipo del contenedor.
  • Dominio: informa de la ubicación del recurso.
  • Creado: fecha de creación del contenedor.
  • Creador: usuario que ha creado el contenedor.
  • Modificado: fecha de la última modificación del contenedor.
  • Modificador: usuario que ha realizado la última modificación del contenedor.
  • Protegido: evita que un objeto se pueda "mover", por ejemplo, a otras colecciones. Además, no permite la edición del objeto. Se puede asignar o desasignar.

Validaciones en un contenedor

ODL ofrece una operación llamada validación que permite definir condiciones en un contenedor. ¿Pero condiciones para qué?

Cuando creamos un objeto, es necesario garantizar la integridad de la información introducida. Pero además de introducir información, puede ser necesario introducirla con un formato determinado. Aquí es donde intervienen las validaciones. Se incluirán condiciones en el contenedor sobre ciertas entradas de información (campos), de manera que al querer guardar el objeto, no se llevará a cabo esta operación si no se cumplen las condiciones definidas.

Antes de definir una condición debemos saber qué atributos tenemos que incluir. El atributo regla indicará el campo sobre el que queremos que se evalúe la condición. El tipo indicará el carácter de la condición, si es estricta será de tipo error, y si no, será de tipo advertencia. Finalmente indicaremos un mensaje de error en el atributo mensaje, y una localización del campo afectado en forma de enlace en el atributo localizacion.componente.

Utilizando el ejemplo anterior, definiremos condiciones en el contenedor Libro, y veremos su comportamiento a la hora de crear un objeto de tipo "Libro".

tipo [Libro] es contenedor
   [Datos] es formulario
      [Código] es timbre
         -certificado.valor = [&Valor_secuencia];
         -certificado.secuencia.nombre = "STR$LIBRO";
         -certificado.secuencia.longitud = 4;
      [Título] es texto
      [Autor] es texto
      [Edición] es texto
      [Editorial] es texto
[Contenido] es seccion [Tipo] es texto -edicion.valores = $Matriz("Literario","Biografía","Científico","Infantil"); -apariencia.desplegable = verdadero; [Sinopsis] es texto -edicion.longitud = 1000; fin fin
condicion [Campo Título, está vacío] -regla = [Datos].[Título] = vacio; -localizacion.componente = [Datos].[Título]; -tipo = error; -mensaje = "Debe introducir el título del Libro";
condicion [Año de la edición con 4 dígitos] -regla = $longitudTexto([Datos].[Año de la edición]) < 4; -localizacion.componente = [Datos].[Año de la edición]; -tipo = advertencia; -mensaje = "Formato del año incorrecto, debe tener 4 dígitos como mínimo. En caso de ser un año inferior a 4 dígitos, añadir ceros a la izquierda";
condicion [Tipo de libro no aceptado] -regla = ([Datos].[Contenido].[Tipo] <> "Literario") y ([Datos].[Contenido].[Tipo] <> "Biografía") y ([Datos].[Contenido].[Tipo] <> "Científico") y ([Datos].[Contenido].[Tipo] <> "Infantil"); -localizacion.componente = [Datos].[Contenido].[Tipo]; -tipo = error; -mensaje = "Por favor, seleccione uno de los valores del desplegable. Este campo no puede tener otro valor"; fin
Comportamiento de las distintas condiciones

Ciclo de eventos de un contenedor

Aprovechando que en el apartado anterior hemos intentado crear un objeto definiendo condiciones en la definición de tipo, es un buen momento para entender los eventos que se producen al crear un objeto.

El primer evento que se produce es la verificación de validaciones, es decir, que antes de que se guarde el objeto, la integridad de la información introducida tiene que ser la exigida en su definición. Si esto se cumple, el siguiente evento es guardar el objeto. Una vez almacenado, el tercer evento es actualizar las tablas de colección, de forma que el objeto creado aparezca en aquellas colecciones donde esté incluído el tipo del objeto. Y finalmente, se ejecutan las exportaciones asociadas a ese contenedor.

Herencia en contenedores

ODL permite la herencia entre contenedores. Esto quiere decir que es posible realizar una definición de tipo a partir de otra definición "padre". Las definiciones de tipo derivadas heredarán todos los componentes definidos en la definición "padre".

Existe también la opción de redefinir componentes o campos en un contenedor derivado, así como definir nuevos componentes. Además, ODL permite declarar tipos abstractos, de forma que no se podrán crear objetos de ese tipo.

Veamos a continuación un ejemplo de herencia en contenedores, utilizando el contenedor tipo Libro como contenedor padre:

tipo abstracto [Libro] es contenedor
   [Datos] es formulario
      [Código] es timbre
         -certificado.valor = [&Valor_secuencia];
         -certificado.secuencia.nombre = "STR$LIBRO";
         -certificado.secuencia.longitud = 4;
      [Título] es texto
      [Autor] es texto
      [Edición] es texto
      [Editorial] es texto
[Contenido] es seccion [Tipo] es texto -edicion.valores = $Matriz("Literario","Biografía","Científico","Infantil"); -apariencia.desplegable = verdadero; [Sinopsis] es texto -edicion.longitud = 1000; fin fin fin
tipo [Literario] es [Libro]
   [Datos] es formulario
      [Contenido] es seccion
         [Tipo] es texto
            -edicion.modo = referencia;
            -edicion.valor = "Literario";
      fin
      [Artículos relacionados] es tabla
         [Título del artículo] es texto;
         [Autor del artículo] es texto;
         [Año del artículo] es texto;
      fin
   fin
fin
En este caso, hemos declarado el tipo Libro como abstracto, de forma que no podremos crear un objeto de tipo Libro. Hemos definido un contenedor "Literario" a partir de Libro, donde redefinimos el campo [Tipo] que hay en el tipo padre, y además hemos añadido una tabla al formulario.

A la hora de redefinir un campo, hay que tener en cuenta los componentes en las que está definido, para incluírlas también en la definición. El campo [Tipo] que hemos redefinido está incluído en una sección que a su vez está incluído en un formulario. Por tanto, hemos incluído el formulario y la sección en el nuevo contenedor "Literario" para referenciar el campo [Tipo] y poder redefinirlo.

El resultado de nuestro contenedor "Literario" será el formulario definido en el tipo Libro con el campo [Tipo] redefinido y el añadido de un campo tabla.

En caso de querer incluir algún atributo o redefinirlo, se realizará adoptando el mismo comportamiento que para redefinir un campo, incluyendo aquellas definiciones necesarias para referenciar al atributo en cuestión, como hemos podido ver en el ejemplo.

Atributos

A la hora de definir un contenedor, es probable que queramos configurar ciertos aspectos en su definición de forma que satisfagan las necesidades del sistema de información. Para esto, existen los atributos.

En ODL existen atributos generales sobre los recursos (contenedores, tareas, habitaciones, enumerados y roles) y otros atributos exclusivos de los contenedores. Entre ellos, se distinguen dos tipos de atributos: accesibles y ocultos (el programador no puede asignarle un valor, esa tarea la realiza la plataforma). A continuación listaremos la especificación de aquellos atributos que afectan exclusivamente a los contenedores, para finalmente realizar un ejemplo con aquellos atributos que pueden ser asignables por el programador.

Atributos de los recursos


Atributo Tipo Valor por defecto Observaciones
ayuda Texto Marcador dentro de la ayuda
descripcion Texto [Nombre] Comentario sobre el recurso
etiqueta Texto [Nombre] Etiqueta del recurso. Expresión que aparecerá del contenedor cuando sea vinculado.
grupo Texto Grupo de recursos en el que se clasifica
icono Texto Identificar del icono
plantilla_impresion Texto Nombre del fichero de la plantilla de impresión (.ar)
publico Lógico Verdadero Indica que al recurso pueden acceder todos los usuarios
registrar_accesos Texto Nada Registran los accesos al recurso (.log). Nunca (Nada), cuando se accede (Lectura) o cuando se modifique (Escritura)
mostrar_propiedades Lógico Verdadero Se desea mostrar la pestaña de propiedades del recursos


Atributo oculto Tipo Observaciones
asistente Definicion asistente Asistente asociado al recurso
habitaciones {Definicion recurso} Habitaciones a las que se puede enviar el recurso
impresiones Definicion impresion Formatos de impresión que se pueden realizar del contenedor
verificación Definicion verificacion Verificación a realizar sobre el recurso


Atributos de los contenedores


Atributo Tipo Valor por defecto Observaciones
nombre Expresión / Texto [Nombre de la definición] Fórmula para sugerir un nombre para el contenedor
referencia Expresión / Texto Fórmula para calcular la referencia de un contenedor
asunto Texto


Atributo oculto Tipo Observaciones
colecciones {Definición colección} Colecciones en las que se puede almacenar el contenedor
exportaciones {Definición exportación} Exportaciones que tiene definidas el contenedor
asistentes {Definición asistente} Asistentes que tiene definidos el contenedor
asistente_automatico {Definición asistente} Asistente que se ejecuta automáticamente al crear el contenedor
tareas {Definición tarea} Tipos de tareas que se pueden lanzar sobre el contenedor
referencias.definicion {Definición} Referencias que se realizan de manera indirecta al contenedor, tanto colecciones como exportaciones.
referencias.columna Texto Nombre de la columna donde se almacena la referencia indirecta


Ejemplo: uso de atributos

Atributo nombre

tipo [Libro] es contenedor
   -nombre = "'Libro de la biblioteca'";
   [Datos] es formulario
   ...
   ...
   ...   
   fin
fin

En caso de no asignar ningún valor, el objeto obtendrá el nombre del tipo, en este caso, Libro. Pero además, este atributo permite definir una expresión, utilizando funciones de librería y operadores, de forma que pueda obtener diferentes valores.

tipo [Libro] es contenedor
   -nombre = "$si([Datos].[Autor] = vacio,[Datos].[Título],[Datos].[Autor] + "" - "" + [Datos].[Título]";
   [Datos] es formulario
   ...
   ...
   ...
   fin   
fin

El resultado de la expresión sería el siguiente:

Moficar el nombre de un objeto mediante una expresión en el atributo nombre

Atributo mostrar_propiedades

tipo [Libro] es contenedor
   -nombre = "$si([Datos].[Autor] = vacio,[Datos].[Título],[Datos].[Autor] + "" - "" + [Datos].[Título]";
   -mostrar_propiedades = falso;
   [Datos] es formulario
   ...
   ...
   ...
   fin   
fin

Si no se especifica, su valor será verdadero. Al ponerlo a falso, la pestaña propiedades de cada objeto "Libro", no se mostrará al usuario:

La pestaña "propiedades" del objeto no estará visible

Atributo icono

[Estantería 1] es contenedor
   -icono = "Estante";
   [Contenido] es coleccion
   ...
   ...
   ...
   fin
fin

Como ya habíamos dicho, hay atributos para variar el aspecto visual en el entorno egExplorer. Este atributo es uno de ellos. Podemos especificar un icono, en este caso para nuestro objeto de sistema Estantería_1:

Introducir un icono a nuestro objeto de sistema

Atributo descripcion

[Estantería 1] es contenedor
   -icono = "Estante";
   -descripcion = "Estantería de libros de la biblioteca";
   [Contenido] es coleccion
   ...
   ...
   ...
   fin
fin

Este atributo muestra la descripción del contenedor. En este caso, vemos como aparece la descripción al abrir nuestro objeto de sistema Estantería_1. Si nos fijamos en la imagen anterior, vemos que en vez de la descripción, aparece el nombre de la colección [Contenido]:

Descripción de un contenedor

Atributo publico

Este atributo por defecto tiene asignado como valor verdadero, por eso no hemos tenido ningún problema para acceder a ninguno de los objetos que hemos creado. Si lo incluimos en Estantería 1, al querer abrir el objeto de sistema nos saldrá un mensaje de error. Si por el contrario lo incluimos en la definición de tipo Libro, podremos abrir el objeto de sistema Estantería 1, nos aparecerá la lista de libros pero no podremos abrir ningún objeto de tipo Libro. En este caso, lo definimos en el objeto de sistema. Prueba a hacerlo también con el contenedor de tipo "Libro":

[Estantería 1] es contenedor
   -icono = "Estante";
   -descripcion = "Estantería de libros de la biblioteca";
   -publico = falso;
   [Contenido] es coleccion
   ...
   ...
   ...
   fin
fin
Restringir acceso mediante el atributo publico

En caso de tener asignado un rol que nos permita abrir o crear un contenedor al que le hemos incluido el atributo publico con valor falso, prevalecerán los permisos que tenga ese usuario sobre el atributo publico en caso de contradicción.

Atributo grupo

Cuando accedemos a una colección y picamos en Nuevo contenedor, nos aparece una ventana con las definiciones de contenedores que están incluídas en la colección y sobre las cuáles podremos crear objetos. Es posible que al ser muchas definiciones nos interese agruparlas por alguna característica concreta. Para ello, utilizaremos el atributo grupo.

Imaginemos que tenemos una colección que contiene todos aquellos documentos de entrada y salida que se generan en nuestra organización, y que hay varias definiciones de documentos de entrada y varias de documentos de salida. Queremos crear dos grupos, uno llamado Documentos de entrada y otro Documentos de salida. Como hay varias definiciones que nosotros consideramos como documentos de entrada, debemos añadir el atributo grupo seguido de su valor:

tipo [Documento de entrada 1] es contenedor
   ...
   ...
   -grupo = "Documentos de entrada";
   ...
fin

Esto lo haremos con todas las definiciones que queramos agrupar en Documentos de entrada. Lo mismo haremos con las definiciones que queramos incluir en el grupo Documentos de salida:

tipo [Documento de salida 1] es contenedor
   ...
   ...
   -grupo = "Documentos de salida";
   ...
fin

Ahora, si accedemos al egExplorer y entramos a la colección donde están incluídas las definiciones agrupadas, veremos lo siguiente:

Atributo grupo01.jpg Atributo grupo02.jpg Atributo grupo03.jpg

Vemos que además de los dos grupos creados, hay otras pestaña llamada Todo donde se listarán todas las definiciones.

Crear subgrupos

Otra utilidad que nos ofrece ODL para agrupar las definiciones y que añaden un nivel más de organización son los subgrupos. Los subgrupos nos permitirán crear grupos dentro de un grupo. Para ello, no será necesario incluir un nuevo atributo (ya que no existe), sino que en el propio atributo grupo añadiremos un punto seguido del nombre del subgrupo:

-grupo = "Grupo.subgrupo";

Utilizando el ejemplo del apartado anterior, dentro de los documentos de salida vamos a crear dos subgrupos, uno llamado Requerimientos y otro Resoluciones. Para ello, modificaremos el atributo grupo en cada una de las definiciones, que en nuestro ejemplo son tres: Documento de salida 1, Documento de salida 2 y Documento de salida 3. Veamos las modificaciones:

tipo [Documento de salida 1] es contenedor
   ...
   ...
   -grupo = "Documentos de salida.Requerimientos";
   ...
fin
tipo [Documento de salida 2] es contenedor
   ...
   ...
   -grupo = "Documentos de salida.Requerimientos";
   ...
fin
tipo [Documento de salida 3] es contenedor
   ...
   ...
   -grupo = "Documentos de salida.Resoluciones";
   ...
fin

El efecto resultante es el siguiente:

Subgrupos.jpg