大雑把に言うと「あるデータの塊を一意に扱う」ためのクラスです。とりあえず「1塊 == DBの1テーブル」であると認識していただいて差し支えはまったくありません。
この特徴のため、いわゆる「O/Rマッパー」的な側面があります。
何はともあれclassを作成して扱ってみましょう。
まずファイルの格納先ですが。どこでもいいんですが、個人的には libディレクトリ内に clumpというディレクトリを切って。clump系のクラスはすべてそこに突っ込むようにしています。だってわかりやすいしw
概ね「テーブル名_clump」というクラス名にする事が多いのですが(混乱がない)、まぁその辺はお好きに。
各classは、data_clump、もしくはdata_clump_validatorのいずれかの継承クラスとして作成してください。以下、説明は全て「data_clump_validatorを継承した」前提で執筆します。
とりあえず。ほぼ定型処理として以下を入れてください。
public function __construct()
{
//$this->init();
parent::__construct();
}
public function init()
{
parent::init();
$this->set_element();
}
/**
* 基本的な情報の設定
*
* テーブル名およびカラム名を設定する
*
* @access protected
*/
protected function set_element()
{
// テーブル名の設定
$this->set_table_name('team_topic_res');
// 要素の設定
// $inname, $cginame, $tmpname, $dbname, $keyflg
$this->push_element('res_id','','','','pk');
$this->push_element('topic_id', '', '', '', '');
$this->push_element('client_id', '', '', '', '');
$this->push_element('comment', '', '', '', '');
$this->push_element('write_date', '', '', '', '');
// validate項目とvalidateの仕方の設定
// $name, $type, $must = false, $min = -1, $max = -1
$this->make_validate('comment', 'any', true, -1, 500);
}
こんな感じです以上…では切ないので色々と。
set_table_nameはまぁそのまんま。ここうまく使うとちょいと面白い事が出来るですが(大規模なんかで「IDのhash値でテーブル名分ける」とかね)、とりあえずは素直にストレートに。
「デフォルトとして、class名から"_clump"を削除した値」って事も想定はしましたが、現状実装はしてません。
とりあえずdata_clumpの最大級の眼目の場所。簡単に書くと「内部呼称とHTML内のINPUTエレメントのnameアトリビュート値とDBのカラム名とテンポラリテーブル(セッションテーブル)に格納するときの一時的な名前と、あとはプライマリキーであるかどうか」を一気に指定していきます。いやまぁなんていうかほぼそのまんま。
基本手でごりごり書いていくですが。一応、
なんてのが、運が良ければ、作成の…0.5助くらいにはなる、かも…しれません。多分。あるいは。もしかしたら。
ちなみに。空文字の場合のデフォルトは「内部呼称(inname)の値」。特に問題がなければ、一緒にしちゃって良いように思われます。気になる人や問題がある人は個々に設定してください。
チェック項目用のListです。データの形、必須か否か、最大値、最小値がそれぞれ指定できます(ぢつはもうちょっと柔軟に出来るのですがそれは後ほど)。
データの形は、validator_clump というclassにそのまんま依存しています。で、原稿書いている 2008/09/02 現在。
に対応しています。いやまぁisクラス書きゃ対応追加は容易なので…要望はお早めにw
なお。数字と数値は「文字か値か」の違いです。具体的にはmaxとminの指定で差異が発生します。
$this->make_validate('age', 'numeric', true, 0, 120);
は0歳から120歳までをフォローしますが、万が一これで
$this->make_validate('age', 'digit', true, 0, 120);
以下、model(base_modelとかその系列)の継承クラスのexecute系メソッド内で使う事を想定しています。
そうでない場合は、適宜かみ砕いて都合良く読み替えたり脳内置換したり脳内補完したりしてください。
また、以下「hoge_clump」というクラス名で説明をしていきます。
// cgiリクエストが詰まったオブジェクト取ってくる
$req = $this->get_cgi_request();
// hogeクラスを「にゅ~」
$hobj = new hoge_clump();
$hobj->set_from_cgi($req);
いぢょ。これで、clumpクラス内にデータががっつり入りました。
// DBハンドル取ってくる
$dbh = $this->get_db();
// hogeクラスを「にゅ~」
$hobj = new hoge_clump();
$hobj->set_db($dbh);
$hobj->set_value('key', $key, false);
$ret = $hobj->get();
これで「keyというカラムが$keyな値であるデータをDBからいただいてきて腹ん中に修める」事が出来ます。
このパターンだと「プライマリキーとして指定したものでしかWHERE出来ません」が。例えば「今回は email という値から検索したいなぁ」なんて時は
// DBハンドル取ってくる
$dbh = $this->get_db();
// hogeクラスを「にゅ~」
$hobj = new hoge_clump();
$hobj->set_db($dbh);
$hobj->set_value('email', $email, false);
$ret = $hobj->get_nopk();
ごくごくシンプルですが。get_valueメソッドを使います。
$email = $hobj->get_value('email');
set_valueを使うのですが…ここはちょいと色々と。
O/Rマッパ的要素があるために。set_valueは、呼び方というか引数一つで「DBと連動したりしなかったり」します。
ちょいとその辺の要素を分解整理してみましょう。
まず。「getやget_nopkをcallするために、keyを指定するset_value」では、当然ながら「DBと連動しちゃ困ります」。
なので、この手の用途の時には、第3引数に明示的にfalseを指定します。前述してるソースですが、今回はset_valueを中心に眺めてみてください。
// DBハンドル取ってくる
$dbh = $this->get_db();
// hogeクラスを「にゅ~」
$hobj = new hoge_clump();
$hobj->set_db($dbh);
$hobj->set_value('email', $email, false);
$ret = $hobj->get_nopk();
つぎ。getしたりget_nopkした時の値変更ですが。…これも二種類ありまして。
基本的には「Object内のデータが変わったら連動するようにDBの値も変わって欲しい」ので。その場合、第3引数にtrueを設定します。
$hobj->set_value('counter', $counter, true);
$hobj->set_value('counter', $counter, false);
$hobj->set_value('hogera', $hogera, false);
$hobj->set_value('mugera', $mugera, false);
$hobj->update();
おまけ。CGI Requestデータから情報をげとってそのままDBに格納する場合、
// DBハンドル取ってくる
$dbh = $this->get_db();
// cgiリクエストが詰まったオブジェクト取ってくる
$req = $this->get_cgi_request();
// hogeクラスを「にゅ~」
$hobj = new hoge_clump();
$hobj->set_from_cgi($req);
// データ突っ込む
$hobj->set_db($dbh);
$hobj->insert();
いわゆる「入力 -> 確認 -> 完了」なんかの時に便利ですね。基本はこんな感じで。
// データ突っ込む
$hobj->set_to_tmp();
というロジックになります。
ただ。「すでに手持ちにあるセッションオブジェクトに入れて~」というケースもあるので。その場合
// データ突っ込む
$hobj->set_to_tmp($お手持ちのセッションオブジェクト);
概ね、set_to_tmpと一緒です。つまり、通常は
// データげと
$hobj->set_from_tmp();
// データげと
$hobj->set_from_tmp($お手持ちのセッションオブジェクト);
convインスタンスはmodelクラスから取得できるので、って前提で、こうなります。
// convインスタンス取ってくる
$conv = $this->get_conv();
// 設定
$hobj->set_all_to_conv($conv);
ちょいと話が飛びますが。
DBのkeyには、自然キーと人工キーという二種類があります。リレーショナルデータベース、という数学論としては「自然キー」を推奨しているのですが、例えばOracleとか、その辺の製品を扱っている、いわゆるデータベースエンジニアとかいう方々は、人工キーを推している事が多いようです。
まぁ善し悪しって話はおいておくのですが。
個人的には、やはり「候補キー」と呼称されるタプル群がいくつかあってその中の一つを「主キーにする」というのが、大変にきれいであるように感じられます。
別の観点として。
いわゆる「デリートフラグ」とかってやつですが。…あれがtrue(削除された)ってデータが増えると、テーブルが太るんですよね。ちょっと気になるところです。
等々、の観点から。
MWでは「デリートキーをonにする論理削除ではなく、レコードそのものを物理削除するほうを推奨する」方向で考えています。
ってのを踏まえて。
// 削除
$hobj->del();
ここからが、妙技。
まず。「テーブル名 + '_delete'」というテーブルを用意してください(この辺、prefixにするかsuffixにするか、また付け加える文字列については可変予定です)。
しかる後にdelメソッドを。
するとなんと不思議。本体テーブルから削除されて、_deleteテーブルに同じ情報がinsertされています。 ちなみに_deleteテーブルは「主キー設定をしない」「元テーブル+'delete_date'というタプル」という構成が好ましいですっていうかそれ前提です。
これであれば。
例えば「emailは重複させたくないからuniquではじきたい」とかそういった「真っ当なDBの使い方」が割と簡単にできるようになります。
今までの説明でも概ね使えるのですが。さらにより一層「お便利に使う」ための一助としてのご提案です。
例えば現状。CONVで、いわゆる「単置換」しかサポートしていないです。言い換えると。typeがtextだったりtextareaだったりするとよいのですが、これがradioだったりselectだったりすると、どうしても個別ロジックが必要になります。
また、確認画面では「selectで得られた値」ではなくて「selectで得られた値から導き出される文字列」になる事も多々。
そんな時の、ぶっちゃけご提案的Tipsです。
まず。convでいうところのconv_util::monoDicCheckedなどは。data_clump継承クラス内に作成します。
概ね、こんな感じで。
public function set_all_to_conv($conv)
{
// まずは親call
parent::set_all_to_conv($conv);
// で、個別処理
conv_util::monoDicChecked...
}
なんてルールを決めた上で、同じくset_all_to_convメソッド内に記述してしまえば便利です。
これもset_all_to_convと全く同様で。個別にmodelとかに散らかすのではなく、clumpクラス内に集約して持っておくようにしましょう。
二点ご紹介。
いち。
「トークナイザつかってユニークなIDを与えたい」なんてケースは多々。この場合
$hobj->set_value_token(カラム名, false);
に。
「今この瞬間の日付を入れたい」ってのが以下略。同様に
$hobj->set_value_nowdate(カラム名, false);
「最低限きちんとntpで時刻あわせをしておきましょう」。
よく「DBの側の日付を取得」と言いますしそれは正論なのですが。それも「DBサーバを複数台にした」瞬間に同じ問題が発生するので。
まずは「きちんとntpで時刻あわせをする」事を意識しましょう。
で…ある意味ここが真骨頂。がつりんといってみましょう。