跳到主要內容
文件

開發者指南

查詢 XML

在 Zittme 中不直接撰寫 SQL,而是以 XML 宣告資料表與查詢。即使資料庫種類不同,同一份程式碼也能執行;值的繫結是自動完成的,因此不必擔心 SQL 注入。

資料表宣告:schemas/*.xml

檔案名稱就是資料表名稱。安裝模組時,核心會建立資料表。

<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>
  • 主要型別:number / bigint / varchar(必須指定 size)/ char / text / bigtext / date / float
  • 日期依慣例以 YYYYMMDDHHIISS 字串儲存在 char(14) 中(date('YmdHis'))。
  • 唯一編號以 getNextSequence() 取得,放入 *_srl 欄位。

上線運作中新增欄位:核心不會自動在已建立的資料表上加入新欄位。必須同時做兩件事:修改結構描述 XML,並在 Install 的 moduleUpdate 中呼叫 addColumn()。

查詢宣告: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 是從 PHP 傳入的值的名稱。若未傳入值,該條件會整個被省略。 必要條件請加上 notnull="notnull"。
  • default 是沒有值時的預設值。
  • pipe 是與前一個條件的連接方式(and/or)。第一個條件不使用。

可用的 operation 一覽:

operationSQL意義
equal=等於
notequal (=not_equal)!=不等於
more (=gte)>=大於等於
excess (=gt)>大於
less (=lte)<=小於等於
below (=lt)<小於
like / notlikeLIKE '%value%'包含 / 不包含
like_prefix (=like_head)LIKE 'value%'以~開頭
like_tail (=like_suffix)LIKE '%value'以~結尾
search逐詞 LIKE '%value%'將搜尋字詞拆成單字後分別比對
in / notinIN (...)包含於列表 / 排除
betweenBETWEEN範圍
null / notnullIS (NOT) NULL檢查 NULL
regexp / notregexpREGEXP正規表示式
  • 在 <navigation> 中設定 list_count 與 page 後,executeQueryArray 的結果會一併附上分頁資訊(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" 是只允許數字通過的驗證。
  • delete 只需在 action="delete" 中放 conditions。為避免出現沒有條件的 delete/update,請務必在關鍵條件上加上 notnull。

在 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 適合單筆結果,executeQueryArray 則一律以陣列回傳結果。列表請使用 Array 版本。
  • 需要聯結時,可在 <tables> 中放入兩個資料表並在 <conditions> 中串接,或使用 <table type="left join"> 與 <conditions> 子宣告。複雜的聯結最快的方法是參考核心模組(board、document)的查詢 XML。

最常見的陷阱

未列在 <columns> 中的欄位會被默默丟棄。 即使在 PHP 中傳入 $args->new_column = 'value',若 insert/update 查詢 XML 的 <columns> 中沒有宣告該欄位,就會在沒有任何錯誤的情況下被忽略。如果「明明有寫入,資料庫裡卻沒有」,十之八九就是這個原因。

新增欄位時,請同時修改以下三處。

  1. 在 schemas/table.xml 中新增欄位
  2. 在 Install 的 moduleUpdate 中呼叫 addColumn(供既有安裝的網站使用)
  3. 在相關 insert/update 查詢 XML 的 <columns> 中新增