Ir al contenido
Docs

Guía para desarrolladores

Query XML

En Zittme no escribes SQL directamente: declaras las tablas y las consultas en XML. El mismo código funciona con distintos tipos de base de datos y, como la vinculación de valores es automática, no tienes que preocuparte por la inyección SQL.

Declarar tablas: schemas/*.xml

El nombre del archivo es el nombre de la tabla. El núcleo crea la tabla al instalar el módulo.

<table name="mymodule_item">
	<column name="item_srl" type="bigint" notnull="notnull" primarykey="primarykey" />
	<column name="member_srl" type="bigint" notnull="notnull" index="idx_member_srl" />
	<column name="title" type="varchar" size="250" notnull="notnull" />
	<column name="content" type="bigtext" />
	<column name="status" type="varchar" size="10" notnull="notnull" default="open" index="idx_status" />
	<column name="regdate" type="char" size="14" index="idx_regdate" />
</table>
  • Tipos principales: number / bigint / varchar (size obligatorio) / char / text / bigtext / date / float
  • Por convención, las fechas se guardan en char(14) como cadena YYYYMMDDHHIISS (date('YmdHis')).
  • Los números únicos se obtienen con getNextSequence() y se guardan en columnas *_srl.

Agregar columnas con el sitio en operación: el núcleo no agrega automáticamente columnas nuevas a una tabla que ya existe. Tienes que hacer dos cosas a la vez: modificar el XML del esquema y llamar a addColumn() en el moduleUpdate de Install.

Declarar consultas: queries/*.xml

SELECT

<query id="getItems" action="select">
	<tables>
		<table name="mymodule_item" />
	</tables>
	<columns>
		<column name="*" />
	</columns>
	<conditions>
		<condition operation="equal" column="status" var="status" default="open" />
		<condition operation="like" column="title" var="s_title" pipe="and" />
		<condition operation="more" column="regdate" var="start_regdate" pipe="and" />
	</conditions>
	<navigation>
		<index var="sort_index" default="item_srl" order="desc" />
		<list_count var="list_count" default="20" />
		<page var="page" default="1" />
	</navigation>
</query>
  • var es el nombre del valor que pasas desde PHP. Si no pasas el valor, esa condición se omite por completo. A las condiciones obligatorias agrégales notnull="notnull".
  • default es el valor predeterminado cuando no hay valor.
  • pipe es la conexión (and/or) con la condición anterior. No se usa en la primera condición.

Todas las operation disponibles:

operationSQLSignificado
equal=Igual
notequal (=not_equal)!=Distinto
more (=gte)>=Mayor o igual
excess (=gt)>Mayor que
less (=lte)<=Menor o igual
below (=lt)<Menor que
like / notlikeLIKE '%value%'Contiene / no contiene
like_prefix (=like_head)LIKE 'value%'Empieza con
like_tail (=like_suffix)LIKE '%value'Termina con
searchLIKE '%value%' por palabraDivide el término de búsqueda en palabras y compara cada una
in / notinIN (...)Incluido / excluido de la lista
betweenBETWEENRango
null / notnullIS (NOT) NULLComprobación de nulo
regexp / notregexpREGEXPExpresión regular
  • Si pones list_count y page en <navigation>, el resultado de executeQueryArray incluye la información de paginación (page_navigation).

INSERT / UPDATE / DELETE

<query id="insertItem" action="insert">
	<tables>
		<table name="mymodule_item" />
	</tables>
	<columns>
		<column name="item_srl" var="item_srl" notnull="notnull" filter="number" />
		<column name="title" var="title" notnull="notnull" />
		<column name="content" var="content" />
		<column name="status" var="status" default="open" />
		<column name="regdate" var="regdate" />
	</columns>
</query>
<query id="updateItemStatus" action="update">
	<tables>
		<table name="mymodule_item" />
	</tables>
	<columns>
		<column name="status" var="status" notnull="notnull" />
	</columns>
	<conditions>
		<condition operation="equal" column="item_srl" var="item_srl" filter="number" notnull="notnull" />
	</conditions>
</query>
  • filter="number" es una validación que solo deja pasar números.
  • Para delete, usa action="delete" y declara solo conditions. Agrega siempre notnull a las condiciones clave para que no se ejecute un delete/update sin condiciones.

Ejecutar desde PHP

$args = new \stdClass;
$args->status = 'open';
$args->page = (int)\Context::get('page') ?: 1;

$output = executeQueryArray('mymodule.getItems', $args);
if (!$output->toBool())
{
	return $output;  // DB 오류
}
$items = $output->data;              // 항상 배열
$paging = $output->page_navigation;  // navigation 선언 시
  • executeQuery es para resultados de un solo registro; executeQueryArray siempre devuelve el resultado como arreglo. Para listas usa la versión Array.
  • Si necesitas un join, pon las dos tablas en <tables> y únelas en <conditions>, o usa <table type="left join"> con declaraciones de <conditions> anidadas. Para joins complejos, lo más rápido es consultar el XML de consultas de los módulos del núcleo (board, document).

La trampa más común

Las columnas que no están en <columns> se descartan en silencio. Aunque pases $args->new_column = 'value' desde PHP, si esa columna no está declarada en <columns> del XML de la consulta insert/update, se ignora sin ningún error. Si te pasa que "estoy seguro de que lo guardé, pero no está en la base de datos", casi seguro es esto.

Cuando agregues una columna, modifica estos tres lugares a la vez.

  1. Agrega la columna en schemas/table.xml
  2. addColumn en el moduleUpdate de Install (para sitios ya instalados)
  3. Agrégala en <columns> del XML de las consultas insert/update relacionadas