本文へスキップ
ドキュメント

開発者ガイド

クエリ XML

Zittme では SQL を直接書かず、テーブルとクエリを XML で宣言します。DB の種類が違っても同じコードが動き、値のバインドが自動なので 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
  • 日付は慣例として char(14) に YYYYMMDDHHIISS 文字列で保存します(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) NULLNULL の検査
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> に2つのテーブルを置いて <conditions> でつなぐか、<table type="left join"> と <conditions> の下位宣言を使います。複雑な結合はコアモジュール(board、document)のクエリ XML を参考にするのが一番の近道です。

よくある落とし穴

<columns> にないカラムは黙って捨てられます。PHP で $args->new_column = 'value' を渡しても、insert/update クエリ XML の <columns> にそのカラムが宣言されていなければ、エラーなしで無視されます。「確かに入れたのに DB にない」なら、十中八九このケースです。

カラムを追加するときは、次の3か所をあわせて修正してください。

  1. schemas/table.xml にカラムを追加
  2. Install の moduleUpdate に addColumn(既存のインストール済みサイト向け)
  3. 関連する insert/update クエリ XML の <columns> に追加