クエリ 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 の一覧:
| operation | SQL | 意味 |
|---|---|---|
equal | = | 等しい |
notequal (=not_equal) | != | 等しくない |
more (=gte) | >= | 以上 |
excess (=gt) | > | 超過 |
less (=lte) | <= | 以下 |
below (=lt) | < | 未満 |
like / notlike | LIKE '%value%' | 含む / 含まない |
like_prefix (=like_head) | LIKE 'value%' | 〜で始まる |
like_tail (=like_suffix) | LIKE '%value' | 〜で終わる |
search | 単語ごとの LIKE '%value%' | 検索語を単語に分けてそれぞれ照合 |
in / notin | IN (...) | リストに含む / 除外 |
between | BETWEEN | 範囲 |
null / notnull | IS (NOT) NULL | NULL の検査 |
regexp / notregexp | REGEXP | 正規表現 |
<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か所をあわせて修正してください。
schemas/table.xmlにカラムを追加- Install の moduleUpdate に addColumn(既存のインストール済みサイト向け)
- 関連する insert/update クエリ XML の
<columns>に追加