Files
agenticSystem/docs/05-tables-and-fields.md
Jordan Diaz 6881d64a08 ajustes
2026-04-25 10:27:51 +00:00

12 KiB

Tablas y Campos

Este documento explica cómo gestionar tablas y campos en Acai usando las tools del MCP. Cubre: cómo se almacena el schema (cms/data/schema/{tabla}.ini.php), los menuType (multi, single, category, separador), el flag enlace para tablas públicas, todos los tipos de campo (textfield, textbox, wysiwyg, codigo, date, list, checkbox, upload, multitext, separator), los props comunes (isRequired, defaultValue, optionsType, etc.), la diferencia entre operaciones reversibles e irreversibles (dropData, dropColumn, rename), y el flujo correcto para crear una funcionalidad nueva. Léelo antes de usar cualquier tool del grupo tables/.

Schemas

Cada tabla tiene un schema en cms/data/schema/{tabla}.ini.php. Define:

  • Nombres y tipos de campo
  • Reglas de validación
  • Relaciones (foreign keys)
  • Configuración de display (orden, ancho, etc.)
  • Bloque [meta] con menuName, menuType, menuOrder, controller, etc.

Antes de operar sobre una tabla, siempre consulta el schema:

  • list_tables — inventario rápido del proyecto
  • get_table_schema con tableName (sin cms_) — schema completo
  • get_table_schema con minimal=true — solo nombres + tipos + labels (ahorra tokens)
  • get_table_schema con filterFields="galeria|foto|image" — filtra por palabras clave

NUNCA inventes nombres de campos o tablas. Siempre confirma con el schema.

Convenciones inmutables

Regla Valor correcto
Nombres de tabla en tools/Twig/CmsApi sin prefijo cms_
Nombres en queryDB con prefijo cms_
Primary key num (siempre)
Foreign key <entidad>_num (e.g. categoria_num)
Upload field array [{urlPath, info1, info2, info3, info4}]

Crear una tabla — create_table

create_table({
  tableName: "vacantes",        // sin cms_, lowercase + underscores
  menuName: "Vacantes",          // display en sidebar admin
  menuType: "multi",             // multi | single | category | separador
  enlace: true,                  // ¿es tabla pública con URLs?
  seoMetas: true,                // añade campos SEO meta (default false)
  menuOrder: 5                   // opcional, orden en sidebar
})

Decisiones obligatorias antes de llamar

  • enlace: true|false es una decisión de arquitectura. PREGUNTA AL USUARIO antes de llamar:
    • true → la tabla genera URLs públicas, automáticamente añade campo enlace + slug. Cada registro será una página y puede tener detalle vía custom-{tableName}.
    • false → tabla puramente administrativa (categorías internas, configuraciones, logs).
  • menuType:
    • multi → lista plana (productos, noticias, vacantes)
    • single → un único registro (home, configuración, about us)
    • category → contenedor jerárquico que agrupa otras tablas en el menú
    • separador → solo un separador visual

Después de crear la tabla

  1. Añade los campos necesarios con create_field (uno por uno).
  2. Si la tabla tiene enlace: true, considera crear la sección general custom-{tableName} para el detalle (ver 03-modules-and-sections.md).
  3. Si la tabla quiere ordenar/filtrar por fechas, añade campos fecha_publicacion, fecha_expiracion, visible (ver 04-pages-and-records.md).

Crear un campo — create_field

create_field({
  tableName: "vacantes",
  fieldName: "salario_minimo",   // identificador SQL-safe
  label: "Salario Mínimo",        // display en formulario admin
  type: "textfield",
  initialProps: {                // opcional — overrides de defaults
    isRequired: 1,
    maxLength: 100
  }
})

Tipos de campo

Tipo Uso
textfield Texto de una línea
textbox Texto multilínea plano
wysiwyg Editor de texto enriquecido
codigo Editor de código (HTML/JS/CSS snippet)
date Selector de fecha o datetime
list Select / radio / checkboxes (necesita listType + optionsType en initialProps)
checkbox Booleano (1/0)
upload Subida de archivos (imágenes, docs)
multitext Repetidor de entradas de texto
separator Separador visual en el formulario (sin columna en BD)

Props comunes (initialProps)

Pasa solo los que quieres sobrescribir; el resto usa defaults.

Prop Aplica a Descripción
isRequired todos 1 o 0
isUnique textfield, textbox 1 o 0
defaultValue todos Valor por defecto
description todos Texto de ayuda en el formulario
minLength / maxLength textfield, textbox, wysiwyg Longitud min/max
listType list select, radio, checkboxes
optionsType list text (opciones fijas) o tablename (opciones desde otra tabla)
optionsText list (text) `"opcion1,opcion2,
optionsTablename list (tablename) Tabla origen (sin cms_)
optionsValueField list (tablename) Campo del valor (típico: num)
optionsLabelField list (tablename) Campo de la etiqueta
optionsQuery list (tablename) Filtro WHERE adicional
filterField list (tablename) Filtro dinámico por valor de otro campo
allowedExtensions upload "jpg,png,webp,pdf"
maxUploads upload Número máximo de archivos
createThumbnails upload 1 o 0
maxThumbnailWidth / maxThumbnailHeight upload px
fieldWidth / fieldHeight upload px sugeridos al builder
adminOnly todos 1 oculta el campo en formularios públicos
charsetRule textfield Restricciones de caracteres
tipoTags wysiwyg Tags HTML permitidos

Ejemplo: lista desde tabla

create_field({
  tableName: "vacantes",
  fieldName: "categoria_num",
  label: "Categoría",
  type: "list",
  initialProps: {
    listType: "select",
    optionsType: "tablename",
    optionsTablename: "categorias",
    optionsValueField: "num",
    optionsLabelField: "nombre"
  }
})

Actualizar un campo — update_field

update_field({
  tableName: "vacantes",
  fieldName: "descripcion",
  newFieldName: "descripcion_corta",   // OPCIONAL — renombra columna MySQL
  props: {
    label: "Descripción Corta",
    maxLength: 200
  }
})

Casos destructivos

  • newFieldName renombra la columna MySQL. Los datos se preservan, pero rompe cualquier referencia hardcodeada (Twig, hooks, JS, queryDB). Audita el código antes de renombrar.
  • Cambiar type puede coercer/truncar datos (ej. wysiwygtextfield elimina HTML). El backend devuelve warnings en la respuesta — muéstralos al usuario.

Borrar un campo — delete_field

delete_field({
  tableName: "vacantes",
  fieldName: "campo_obsoleto",
  dropColumn: false   // default
})
  • dropColumn: false → solo elimina del schema. Si la columna MySQL tiene datos, el backend rechaza y devuelve dataCount para que avises al usuario.
  • dropColumn: trueALTER TABLE DROP COLUMN. Los datos de esa columna se pierden permanentemente.

Borrar una tabla — delete_table

delete_table({
  tableName: "tabla_obsoleta",
  dropData: false,  // default
  dryRun: true      // pre-flight check
})
  • dryRun: true → no borra nada, solo reporta recordCount. Úsalo siempre antes de pedir confirmación al usuario.
  • dropData: false → solo borra el schema (.ini.php). Si la tabla MySQL tiene registros, el backend rechaza.
  • dropData: trueDROP TABLE + delete schema. Datos perdidos permanentemente.

Reordenar — reorder_tables, reorder_fields

Pasa la lista completa ordenada de nombres. Solo cambia el orden visual, los datos no se tocan.

reorder_tables({ order: ["apartados", "blog", "productos", "vacantes"] })

reorder_fields({
  tableName: "vacantes",
  order: ["titulo", "descripcion", "salario_minimo", "fecha_publicacion", "visible"]
})

Los campos del sistema (num, creationDate, etc.) se ignoran automáticamente.

Actualizar metadata — update_table_metadata

Modifica el bloque [meta] del schema.

update_table_metadata({
  tableName: "vacantes",
  newTableName: "ofertas_empleo",   // OPCIONAL — renombra tabla MySQL
  meta: {
    menuName: "Ofertas de Empleo",
    menuOrder: 3,
    listPageFields: "titulo,fecha_publicacion,visible",
    breadcrumbField: "titulo"
  }
})

Keys aceptadas en meta: menuName, menuDesc, menuType, menuOrder, menuDisplay, menuHidden, controller, breadcrumbField, breadcrumbByLink, breadcrumbParentNum, listPageFields (csv), listPageOrder, listPageSearchFields.

newTableName renombra la tabla MySQL y rompe cualquier referencia hardcodeada (controllers custom, módulos con SQL embebido, queryDB en plantillas). Audita el código antes y avisa al usuario.

Regenerar enlaces — regenerate_enlaces

Regenera el campo enlace (slug) de todos los registros de una tabla. Cambia URLs públicas — todo lo que apunte a las antiguas dará 404 a menos que actives los aliases.

regenerate_enlaces({
  tableName: "vacantes",
  generateAlias: true   // recomendado si la tabla ya es pública
})
  • generateAlias: false (default) — solo actualiza enlace. URLs antiguas → 404.
  • generateAlias: true — escribe entradas en alias_urls para redirigir las URLs antiguas a las nuevas. Más seguro.

Listar tablas — list_tables

Devuelve todas las tablas con su menuName, menuType, menuOrder y tableName. Sin prefijo cms_. Úsalo cuando necesites un inventario rápido.

Tipos de campo y formato al insertar/actualizar registros

Al usar create_or_update_record, cada tipo espera un formato específico:

Tipo Formato Ejemplo
textfield String "Texto"
textbox String multilínea "Línea 1\nLínea 2"
date/datetime YYYY-MM-DD HH:mm:ss "2025-12-03 10:30:00"
wysiwyg String HTML "<p>Texto</p>"
list String o número "activo" o "1" (num si es FK)
checkbox Número 1/0 1 o 0
multitext String JSON "[{\"item\":\"valor\"}]"
upload NO enviar Usa upload_record_image después de crear el registro

Ver 06-hooks-and-cmsapi.md para los detalles de CmsApi::insert / update.

Flujo canónico — Funcionalidad nueva tipo "vacantes"

  1. create_table({ tableName: "vacantes", menuType: "multi", enlace: true, seoMetas: true }) — pregunta al usuario si quiere enlace y seoMetas.
  2. create_field para cada campo: titulo, descripcion (wysiwyg), salario_minimo (textfield), categoria_num (list desde tabla), fecha_publicacion (date), fecha_expiracion (date), visible (checkbox), imagen_destacada (upload).
  3. Crear sección general template/estandar/modulos/custom-vacantes/index-base.tpl con acai-write (compila automáticamente).
  4. (Opcional) Módulo de listado vacantes_listado_xxxxxx que liste registros con 'vacantes' | get('visible=1', 'fecha_publicacion DESC', 20).
  5. (Opcional) Página índice /vacantes/ en apartados con el módulo de listado.

Reglas críticas

  1. Tabla sin prefijo cms_ en todas las tools. PK siempre num.
  2. Antes de cualquier operación: get_table_schema para confirmar nombres y tipos de campo.
  3. Pregunta al usuario antes de create_table sobre enlace y seoMetas (decisiones de arquitectura).
  4. dropData, dropColumn, newFieldName, newTableName son destructivos o irreversibles — pide confirmación explícita.
  5. regenerate_enlaces: usa generateAlias: true si la tabla ya tiene tráfico público.
  6. Surfacea los warnings que el backend devuelve (cambios de tipo, renames, conteos de datos en riesgo).
  7. Upload fields no se setean en insert/update — usa upload_record_image después.