#CRUD-L
Una aplicación que gestiona datos utiliza ampliamente las operaciones CRUD-L (Create, Read, Update, Delete y List).
El marco de desarrollo CRUD-L de Devkron facilita y automatiza la implementación de estas operaciones sobre las entidades de datos del sistema.
CRUD-L está implementado según el patrón MVC Model View Controller
Instalación y configuración
Este marco se encuentra en el repositorio https://github.com/Induxsoft/dkl-web
De manera predeterminada, los archivos controller.dkl, entity.dk, error.dk, form.dk, list.dk, mysql.dbr.dkh, view.dk, websencia.dk deben de estar en una carpeta llamada 'crudl' directamente en la raíz de binarios de Devkron (junto a la carpeta 'web' o 'fastcgi'). Estos archivos se usan por todos los sitios Web.
entry-point.dkl. Es el punto de entrada para el controlador y debe ser colocado dentro de la carpeta del sitio Web que lo va a emplear para que sus configuraciones sean exclusivas.
controller.dkl. Es el controlador principal y es responsable de la selección del modelo y vista apropiado para cada tipo de entidad..
entity.dk. Es el modelo genérico que implementa las acciones CRUD-L con entidades de datos que se almacenan en tablas con el patrón de diseño de Devkron (Induxsoft TableModel) previsto por la biblioteca de funciones dbr.dkh y que incluye los campos de control
sys_pk, sys_guid, sys_recver, sys_dtcreated, sys_timestamp y sys_deleted
. Más información aquíview.dk. Es la vista genérica que proporciona una salida en JSON para las entidades provistas por el modelo.
error.dk. Salida de error, esta es una vista predeterminada en caso de error, probablemente deberá modificarla para adecuarla a sus requisitos de usabilidad y estilo.
mysql.dbr.dkh. Contiene funciones específicas para MySQL, incluyendo la suplantación de identidad de una base de datos en otra.
websencia.dk. Contiene funciones para renderizar vistas creadas con Websencia (páginas en formato JSON)
Conexión a la base de datos
Existen tres formas de conectar con la base de datos:
- Conexión a través del proveedor de indentidades. La autenticación de la identidad del usuario y conexión a la base de datos llegan establecidos por la capa de autorización.
- Conexión por suplantación de identidad. La identidad del usuario y sus permisos se establecen por la capa de autorización, pero se deberá obtener un identificador de sesión en la base de datos.
- Conexión constante. La base de datos y el usuario son establecidos como valores constantes en el punto de entrada (entry-point.dkl).
Dependiendo la forma de conexión elegida, el controlador requiere que se suministren parámetros a través de parámetros en la url (recuerde que los parámetros de url se encuentran disponibles en @http_context/request/get).
Parámetros de URL conocidos por el controlador
_entities_type
Este parámetro en la url indica el tipo de entidades sobre los que aplicarán las operaciones._entity_id
Este parámetro indica la clave primaria o identificador de la facilita cuando se requiere (opcional)_key
Indica el nombre del campo que usado específicamente como identificador, si no se indica se asume el camposys_pk
osys_guid
si_entity_id
es alfanumérico_app_group
(Opcional) El nombre de un grupo de aplicaciones configurado en el archivo connections.xml._connection
(Opcional) El nombre de una conexión en el grupo de aplicaciones indicado.ws
(Opcional) Identificador de espacio de trabajo si la conexión se establece por suplantación de identidad desde un workspace de Induxsoft.
Para cualquier forma de conexión deberá indicar _entities_type
, los demás solo se requieren si así lo considera en sus configuraciones.
Mapeo hacia el punto de entrada
Aunque los parámetros de Url puede establecerse como tales, resulta conveniente indicarlos a través de mapas en routes.map
/misistema/{_entities_type}/{_entity_id?} > carpertademisistema/entry-point.dkl
Ejemplos:
- Url sin mapa:
https://midominio.com/misistema/entry-point.dkl?_entities_type=cliente&_entity_id=10
- Url con mapa:
https://midominio.com/misistema/cliente/10
Configuraciones en el punto de entrada
entry-point.dkl Es el punto de entrada y el lugar en donde se puede configurar el funcionamiento del marco.
Enmascaramiento de url
Para brindar Urls más descriptivas y organizar mejor su sistema, es posible enmascarar los puntos finales y redirigirlos a entidades específicas.
Por ejemplo suponga que tiene un CRUD-L para comprobantes de movimientos de almacen.
Las entidades podrían llamarse moventrada
y movsalida
, lo que significaría tener rutas como:
/misistema/moventrada
/misistema/movsalida
No obstante estas rutas son más descriptivas y ofrecen una mejor organización:
/misistema/inventarios/movimientos/entrada
/misistema/inventarios/movimientos/salida
Para lograr esto use las funciones crudl.routes.pattern
y crudl.routes.entity
junto con un enrutamiento en routes.map
Ejemplo
(entry-point.dkl)
do crudl.routes.pattern("/module/submodule/process")
do crudl.routes.entity("inventario/movimientos/entrada","moventrada")
do crudl.routes.entity("inventario/movimientos/salida","movesalida")
(routes.map)
/{module}/{submodule}/{process}/{_entity_id?} > entry-point.dkl
Variables globales configurables
@path_root="web/nombre_host"
@base_path="ruta relativa en donde se encuentran las entidades"
@db_engine="Contiene el tipo de gestor de base de datos, por defecto viene con MY_SQL"
// Establezca estos valores únicamente si no va a conectarse a través de la capa de autorización de bases de datos
@crudl.qname="Nombre cualificado hacia una conexión de la base de datos"
//Solo si la conexión y usuario serán constantes
@crudl.user="Nombre del usuario"
@crudl.pwd="Contraseña del usuario"
/*
Si no se define el valor de @crudl.qname puede pasarse la conexión por la url como se muestra a continuación
el archivo controller.dkl esta preparado para recibir variables a través de una petición GET para poder definir una conexión o bien las entidades.
- _app_group //define la aplicación hacia el archivo de conexión de devkron
- _connection //define la conexión hacia el archivo de conexión de devkron
ejemplo
http://myhost/entry-point.dkl?_app_group=myapp&_connection=myconnection&_entities_type=myentidad
También puede utilizar un enrutamiento como lo muestra en:
https://docs.induxsoft.net/es/devkron/Sitios-y-aplicaciones-Web-con-DKL/flujo-http.md
*/
Lógica del controlador
Selección de operación
Con base en el método HTTP y la URL
Método | ...{_entities_type}/ | ...{_entities_type}/{_entity_id} |
---|---|---|
GET | list | read |
POST | create | error |
PUT | error | update |
PATCH | error | update |
DELETE | error | delete |
Selección de vista
La vista (salida devuelta) se basa en el tipo de contenido indicado en el encabezado Accept
de la solicitud HTTP y la operación realizada
Si Accept
incluye el tipo y subtipo MIME text/html
, se intentará responder contenido HTML de acuerdo a la siguiente tabla:
Operación | Éxito | Fracaso |
---|---|---|
LIST | list view | error view |
READ | form view | error view |
CREATE | redirect | form view |
UPDATE | redirect | form view |
DELETE | redirect | error view |
Si Accept
NO incluye text/html
, la respuesta será JSON (Content-type:application/json
)
Cada tipo de entidad deberá tener una carpeta con su nombre en la ruta indicada por @base_path
Por ejemplo para una entidad cliente
con @base_path="/misistema/entidades"
puede tener los siguientes archivos:
/misistema/entidades/cliente/form.dk
/misistema/entidades/cliente/list.dk
/misistema/entidades/cliente/model.dk
/misistema/entidades/cliente/controller.dk
Donde
- form.dk Es la vista específica de la entidad para la presentación como formulario
- list.dk Es la vista específica de las entidades presentadas como lista
- controller.dk Es un controlador específico para la entidad (opcional)
- model.dk Es un modelo específico para la entidad (opcional)
En general, si no se ha existe un archivo controller.dk o model.dk en la carpeta de la entidad, se usan el controlador (controller.dk) y modelo (entity.dk) predefinidos.
Operación y formatos de datos de respuesta
La operación se determina con base en el método HTTP utilizado en la solicitud de una url.
- Create. Método HTTP POST sin el parámetro
_entity_id
o con_entity_id=_new
- Read. Método HTTP GET indicando el parámetro
_entity_id
- Update. Método HTTP PATCH con el parámetro
_entity_id
o POST con encabezado HTTPAccept:text/html
y el parámetro_entity_id
- Delete. Método HTTP DELETE indicando el parámetro
_entity_id
- List. Método HTTP GET sin indicar el parámetro
_entity_id
El formato de los datos de respuesta será HTML producido por una vista específica si el encabezado Accept de la solicitud HTTP es text/html, en cualquier otro caso responderá la vista genérica (view.dk) con los datos proporcionados por el modelo como JSON.
Las operaciones CREATE y UPDATE aceptan datos codificados como application/json
útil si se envían programáticamente con Javascript (u otros lenguajes/herramientas)
o bien, como application/x-www-form-urlencoded
que es simple de enviar mediante formularios HTML estándar.
Interfaz Web (Html)
La implementación del CRUD-L con interfaz de usuario Web con vistas específicas realiza las acciones de adición y edición de elementos siguiendo el patrón PRG (Post - Redirect - Get).
Para solicitar el contenido HTML del formulario vacío para agregar, se realiza una solicitud GET con _entity_id=_new
, mientras que para obtener el
formulario con los datos de una entidad para editarla se indica su identificador (sys_pk
, sys_guid
u otro); el valor del identificador para adición (_new)
puede establecerse a través de la variable global @entity_id_blank="_new"
Siempre debe establecerse el encabezado HTTP Accept: text/html para que la respuesta del método POST usado para agregar (create) o actualizar (update) envíe la redirección (encabezado Location) en lugar de los datos en JSON de la entidad creada o actualizada.
Se ha implementado el comportamiento de actualización en el método POST (además de en PATCH) para facilitar la programación del lado del agente del usuario (navegador).
Web services REST
Como puede deducirse, las operaciones Create, Read, Update, Delete y List que son invocadas a través de los correspondientes métodos HTTP (POST, GET, PATCH y DELETE) sin el encabezado ACCEPT: text/html, implementan automáticamente la funcionalidad esperada para un servicio REST
Funcionando como Web services, las vistas específicas no se emplean, pero sí los modelos específicos si existen.
Se espera que la carga útil (payload) se envíe en JSON y la respuesta generada por la vista genérica (view.dk) será tamién JSON.
Puede deshabilitar este comportamiento automático estableciendo @auto_crud=@false
en el entry-point.dkl
CREATE
Crea (agrega) una nueva entidad.
Solicitud
End points válidos:
{aplicación}/{conexión}/{tipo_entidad_plural}/
{aplicación}/{conexión}/{tipo_entidad_plural}/{identificador}/
Método HTTP: POST
Content-Type: application/JSON;charset=utf-8
Carga útil: JSON
Respuesta
- Content-Type:
application/JSON;charset=utf-8
- Código de estado de respuesta HTTP:
200 (Ok)
- Cuerpo de la respuesta:
Entidad completa en JSON
Observaciones
Si no se incluye el id de la entidad en la URL de solicitud HTTP, deberá incluirse en el cuerpo de la carga útil; si se incluye en ambos lugares se le dará prioridad a la URL.
READ
Obtiene una entidad completa
Solicitud
End point válido:
{aplicación}/{conexión}/{tipo_entidad_plural}/{identificador}/
Método HTTP: GET
Respuesta
- Content-Type:
application/JSON;charset=utf-8
- Código de estado de respuesta HTTP:
200 (Ok)
- Cuerpo de la respuesta:
Entidad completa en JSON
UPDATE
Actualiza una entidad
Solicitud
End point válido:
{aplicación}/{conexión}/{tipo_entidad_plural}/{identificador}/
Métodos HTTP: PUT
y PATCH
Respuesta
- Content-Type:
application/JSON;charset=utf-8
- Código de estado de respuesta HTTP:
200 (Ok)
- Cuerpo de la respuesta:
Entidad completa en JSON
Observaciones
Use PUT si va a incluir todos los campos de la entidad, en caso contrario use PATCH. Si usa PUT y no incluye todos los campos, los que no se hayan incluído se establecerán a NULL o su valor predeterminado.
DELETE
Elimina una entidad
Solicitud
End point válido:
{aplicación}/{conexión}/{tipo_entidad_plural}/{identificador}/
Método HTTP: DELETE
Respuesta
- Código de estado de respuesta HTTP:
204 (Sin cuerpo en la respuesta)
- Cuerpo de la respuesta:
Vacío
LIST
Devuelve una lista de todas las entidades
Solicitud
End point válido:
{aplicación}/{conexión}/{tipo_entidad_plural}/
Método HTTP: GET
Respuesta
- Content-Type:
application/JSON;charset=utf-8
- Código de estado de respuesta HTTP:
200 (Ok)
- Cuerpo de la respuesta:
Array de entidades en JSON
Observaciones
Pueden establecerse parámetros de filtro, orden, tamaño de la lista, etcétera en la URL
Identificadores y campos de sistema
Las entidades con fuerte control de concurrencia implementan el patrón de diseño de tablas de bases de datos relacionales de Devkron, que incluye al menos los siguientes campos controlados por el sistema:
sys_pk
sys_guid
sys_dtcreated
sys_timestamp
sys_recver
sys_deleted
Puede usar como identificador tanto sys_pk
,sys_guid
o el campo que se haya definido como tal.
En actualizaciones de entidades que incluyan sys_recver, siempre deberá enviarlo en la carga útil.
Ningún campo de sistema (sys_*
) es actualizable por el usuario (programador).
Parámetros pre-definidos
Por conveniencia, los parámetros pre-definidos (previamente conocidos) inician con el caracter _
_method
Método HTTP_entities_type
Nombre del tipo de entidades_entity_id
Identificador de la entidad_limit
Cantidad máxima de elementos a devolver en LIST_fields
lista delimitada por comas de los campos a devolver (READ y LIST)_order
especificación del orden de la lista (LIST)_start
Índice de inicio de la lista_key
Nombre del campo clave usado
Implementación
Implementación del modelo
Para definir un modelo personalizado que extienda la funcionalidad predeterminada debe crear un archivo denominado model.dk
en la carpeta de la entidad de datos.
Variables globales del modelo
Las siguientes variables globales permiten configurar varias características de la funcionalidad predeterminada.
// Nombre de la tabla subyacente, si no se establece se asume el nombre del parámetro _entities_type
@table_name=""
// Nombre del campo clave predeterminado (no debería modificar este valor)
@keyfield="sys_pk"
// Consulta SQL para obtener los datos de 1 elemento de datos (usada en la operación READ), aquí puede definir uniones, renombrar o limitar los campos a devolver
@read_query="select * from #<@table_name> where #<@keyfield>=@_entity_id limit 1;"
// Consulta para obtener la clave primaria de una tabla 'principal o maestra'
@get_sys_pk="select sys_pk from #<@table_name> where #<@keyfield>=@_entity_id and ifnull(sys_deleted,0)=0 limit 1;"
// Consulta para obtener la lista de elementos de datos (usada en la operación LIST)
@list_query="select * from #<@table_name> where ifnull(sys_deleted,0)=0;"
// Lista de campos considerados de sistema (no es necesario modificar nada)
@sys_fields="sys_pk, sys_guid, sys_dtcreated, sys_timestamp, sys_recver,sys_deleted, sys_lock"
// Campos que se actualizaran (operación UPDATE), * indica que todos los que se envíen se actualizaran o bien puede indicar una lista delimitada por comas
@update_fields="*"
// Campos que se establecerán en una inserción (operación CREATE), * indica que todos los que se envíen se establecerán o bien puede indicar una lista delimitada por comas
@create_fields="*"
// Campos que se excluirán en una operación CREATE
@create_exclude_fields=""
// Campos que se excluirán en una operación UPDATE
@update_exclude_fields=""
// Alias de campos en la actualización, es una lista de pares alias:campo delimitados por comas
@update_alias_fields=""
// Alias de campos en la inserción (CREATE), es una lista de pares alias:campo delimitados por comas
@create_alias_fields=""
// Establece que cuando se realicen operaciones de entidades con elementos dependientes (hijos maestro/detalle)
// se realizará en el contexto de una transacción de base de datos (no debería modificar este valor)
@use_transaction=@true
Referencias a funciones del modelo
La extensión (personalización) del modelo debe realizarse mediante la creación de funciones que realicen las tareas específicas necesarias y además, estableciendo punteros de referencia a ellas para que se integren al flujo previsto.
Las siguientes variables globales son referencias a funciones:
@create
Referencia a una función que realiza la inserción de datos, requiere los parámetros: &db, ¶ms, &data@read
Referencia a una función que devuelve un objeto de datos, requiere los parámetros: &db, ¶ms@update
Referencia a una función que realiza la actualización de datos, requiere los parámetros: &db, ¶ms, &data@delete
Referencia a una función que elimina un elemento de datos, requiere los parámetros: &db, ¶ms@list
Referencia a una función que devuelve una lista de elementos de datos, requiere los parámetros: &db, ¶ms@blank
Referencia a una función que devuelve un elemento de datos vacío (o con datos predeterminados), requiere los parámetros: &db, ¶ms
Use la sentencia point to
de Devkron como en el ejemplo:
mifuncion_update::&db,¶ms,&data
{
// Escriba aquí la funcionalidad para actualizar los datos que recibe a través de data en la base de datos db con los parámetros (generalmente de url) de params si fuese necesario
}
// Reemplace la función predeterminada de actualización por su propia implementación
point @update to mifuncion_update
Implementación de las vistas
Las vitas se ejecutan en un contexto diferente al programa principal que responde a la solicitud HTTP, por lo que reciben
la información necesaria a través de la variable global @crud_context
que tiene los siguientes miembros:
output
Es una referencia a los datos de salida (que generalmente serán pintados en el formulario, usualmente se trata de los campos del elemento de datos).
Es un alias de outputinput
Es una referencia a los datos de entrada de la operación (usualmente lo que se envió desde el formulario)parameters
Una referencia a los parámetros de la solicitud (usualmente parámetros de la URL)error
Es nulo si todo ha ido bien o una referencia a un objeto con información del error ocurridodatabase
Es una referencia a la base de datoshttp
Es una referencia a todo el objeto@http_context
de la solicitud HTTP en curso
Vista de lista
Para definir una vista de lista personalizada se require un archivo llamado list.dk
en la carpeta de la entidad.
Vista de formulario
Para definir una vista de formulario personalizada se require un archivo llamado form.dk
en la carpeta de la entidad.
Otras configuraciones
Cambio del motor de base de datos cuando se requiere la suplantación de identidad
Modifique controller.dkl únicamente si el gestor de base datos que va utilizar es diferente a MY_SQL
Ejemplo
@db_engine="sql_server" //variable global de entry-point
switch @db_engine //bloque de código al principio de controller.dkl
{
case "sql_server"
{
include "crudl/sql_server.dbr.dkh"
}
}
sql_server.dbr.dkh debe implementar las mismas funciones que mysql.dbr.dkh