Develop and Download Open Source Software

Recent Changes

2011-03-30
2011-03-29
2011-03-23
2011-02-25
2010-05-20
2008-09-03

Wiki Guide

Side Bar

data clumpとは

大雑把に言うと「あるデータの塊を一意に扱う」ためのクラスです。とりあえず「1塊 == DBの1テーブル」であると認識していただいて差し支えはまったくありません。
この特徴のため、いわゆる「O/Rマッパー」的な側面があります。

とりあえず大雑把に準備

classファイルを作る

何はともあれ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();
  }
これで、initのタイミングで「必要な情報を設定する」ようにし向けます。
続いて、set_elementメソッドを実行します。基本的に外から呼ばれる事はないはずなので、protectedにしておきます。中では、「データの要素の指定」と「validateの指定」を行います。
…うんえとねこの辺、YAMLだのXMLだので設定ファイル、とか、コードジェネレータとか、考えてるですが…やってません orz

  /**
   * 基本的な情報の設定
   *
   * テーブル名およびカラム名を設定する
   *
   * @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)の値」。特に問題がなければ、一緒にしちゃって良いように思われます。気になる人や問題がある人は個々に設定してください。

validate項目の設定(data\clump_validator固有)

チェック項目用のListです。データの形、必須か否か、最大値、最小値がそれぞれ指定できます(ぢつはもうちょっと柔軟に出来るのですがそれは後ほど)。
データの形は、validator_clump というclassにそのまんま依存しています。で、原稿書いている 2008/09/02 現在。

  • alphanum : 英数字
  • numeric : 数値
  • digit : 数字
  • email : email
  • url : URL
  • dir : ディレクトリ名使用可能文字
  • date : 日付
  • any : なんでも(つまり形チェックはしない)

に対応しています。いやまぁisクラス書きゃ対応追加は容易なので…要望はお早めにw
なお。数字と数値は「文字か値か」の違いです。具体的にはmaxとminの指定で差異が発生します。

    $this->make_validate('age', 'numeric', true, 0, 120);

は0歳から120歳までをフォローしますが、万が一これで

    $this->make_validate('age', 'digit', true, 0, 120);
とやると、0桁から120桁までの数字を許容範囲とします。…とりあえず人間の寿命ぢゃねぇです(笑

使い方基本

以下、model(base_modelとかその系列)の継承クラスのexecute系メソッド内で使う事を想定しています。
そうでない場合は、適宜かみ砕いて都合良く読み替えたり脳内置換したり脳内補完したりしてください。
また、以下「hoge_clump」というクラス名で説明をしていきます。

データを一式、CGIデータから受け取る

  // cgiリクエストが詰まったオブジェクト取ってくる
  $req = $this->get_cgi_request();

  // hogeクラスを「にゅ~」
  $hobj = new hoge_clump();
  $hobj->set_from_cgi($req);

いぢょ。これで、clumpクラス内にデータががっつり入りました。

データを一式、DBから受け取る

  // 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_nopkメソッド」をご利用ください。
いずれの場合も、$retにfalseが帰ってきた場合、何らかのエラーが発生して情報が取れない事を意味します。

data_clump内の情報にアクセスする(read)

ごくごくシンプルですが。get_valueメソッドを使います。

  $email = $hobj->get_value('email');

data_clump内の情報を変更する(write)

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);
ただ。仕様的に「1つの値ごとにUPDATEがSQLとして流れる」ので。複数の値を変更するときは、以下のような書き方もありです。
  $hobj->set_value('counter', $counter, false);
  $hobj->set_value('hogera', $hogera, false);
  $hobj->set_value('mugera', $mugera, false);
  $hobj->update();
この場合、updateのタイミングで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();
こんな風に書くと一撃です。

data_clump内の情報をセッションテーブルに保存する

いわゆる「入力 -> 確認 -> 完了」なんかの時に便利ですね。基本はこんな感じで。

  // データ突っ込む
  $hobj->set_to_tmp();
この場合

  • session_data_dbクラスをnew
  • set_tmp_keyされていればそれを(推奨)、されていなければトークナイザでkeyを作成(非推奨)
  • set_session_table_nameで設定されていればそのテーブル名に対して。設定されていなければデフォルトであるsession_dataテーブルに
  • まず上述の情報から、セッションテーブルをread
  • 全データを各要素ごとにadd_once
  • write

というロジックになります。
ただ。「すでに手持ちにあるセッションオブジェクトに入れて~」というケースもあるので。その場合

  // データ突っ込む
  $hobj->set_to_tmp($お手持ちのセッションオブジェクト);
とすると、お手持ちのセッションオブジェクトにぶち込んでくれます。

data_clump内の情報をセッションテーブルから取り出す

概ね、set_to_tmpと一緒です。つまり、通常は

  // データげと
  $hobj->set_from_tmp();
お手持ち指定なら
  // データげと
  $hobj->set_from_tmp($お手持ちのセッションオブジェクト);
となるわけです。

data_clump内の情報を一式表示する(conv用)

convインスタンスはmodelクラスから取得できるので、って前提で、こうなります。

  // convインスタンス取ってくる
  $conv = $this->get_conv();

  // 設定
  $hobj->set_all_to_conv($conv);
なお。convがf_convクラスだろうがsecure_convクラスだろうが、その辺まで判定したうえで「エスケープ処理して」設定します。現状「非エスケープ項目」については考えてません。
また、現状は未対応ですが、多分、Smarty対応もします。必要なら声かけてくださいませ。
なお、convの単置換子名(またはSmartyの場合変数名)は、inname(普段get_valueとかで使う値)と一緒です。

delメソッドの妙技(笑

ちょいと話が飛びますが。
DBのkeyには、自然キーと人工キーという二種類があります。リレーショナルデータベース、という数学論としては「自然キー」を推奨しているのですが、例えばOracleとか、その辺の製品を扱っている、いわゆるデータベースエンジニアとかいう方々は、人工キーを推している事が多いようです。
まぁ善し悪しって話はおいておくのですが。
個人的には、やはり「候補キー」と呼称されるタプル群がいくつかあってその中の一つを「主キーにする」というのが、大変にきれいであるように感じられます。

別の観点として。
いわゆる「デリートフラグ」とかってやつですが。…あれがtrue(削除された)ってデータが増えると、テーブルが太るんですよね。ちょっと気になるところです。

等々、の観点から。
MWでは「デリートキーをonにする論理削除ではなく、レコードそのものを物理削除するほうを推奨する」方向で考えています。
ってのを踏まえて。

  // 削除
  $hobj->del();
いぢょ…で片付いたら妙技でもなんでもありませんがな。

ここからが、妙技。

まず。「テーブル名 + '_delete'」というテーブルを用意してください(この辺、prefixにするかsuffixにするか、また付け加える文字列については可変予定です)。
しかる後にdelメソッドを。

するとなんと不思議。本体テーブルから削除されて、_deleteテーブルに同じ情報がinsertされています。 ちなみに_deleteテーブルは「主キー設定をしない」「元テーブル+'delete_date'というタプル」という構成が好ましいですっていうかそれ前提です。

これであれば。
例えば「emailは重複させたくないからuniquではじきたい」とかそういった「真っ当なDBの使い方」が割と簡単にできるようになります。

単体で応用

今までの説明でも概ね使えるのですが。さらにより一層「お便利に使う」ための一助としてのご提案です。

set_to_all_convに追記

例えば現状。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...
}
さらに。前述したように「selectで選んだコードに対応する文字列を確認画面で出したい」なんてケースは。

  • name + '_value'に値を入れる(nameが'select_one'なら、その値は'select_one_value'に入る)

なんてルールを決めた上で、同じくset_all_to_convメソッド内に記述してしまえば便利です。

is_validに追記

これもset_all_to_convと全く同様で。個別にmodelとかに散らかすのではなく、clumpクラス内に集約して持っておくようにしましょう。

お便利メソッド

二点ご紹介。

いち。

「トークナイザつかってユニークなIDを与えたい」なんてケースは多々。この場合

  $hobj->set_value_token(カラム名, false);
で設定出来ます。第二引数のfalseは、普段のset_valueの第三引数と同じ意味です。

に。

「今この瞬間の日付を入れたい」ってのが以下略。同様に

  $hobj->set_value_nowdate(カラム名, false);
で片付きます…が、日付の場合、一つ注意点。

「最低限きちんとntpで時刻あわせをしておきましょう」。

よく「DBの側の日付を取得」と言いますしそれは正論なのですが。それも「DBサーバを複数台にした」瞬間に同じ問題が発生するので。
まずは「きちんとntpで時刻あわせをする」事を意識しましょう。

本格的な応用編

で…ある意味ここが真骨頂。がつりんといってみましょう。

loop用データの作り方

いわゆる「入力 -> 確認 -> 完了」における楽な使い方

複数のテーブルに値がまたがる場合

現在未実装な今後予定

テーブル名によってアクセスするDBを切り替える

IDの値によってアクセスするテーブル名を切り替える


SourceForge.JP is a Japanese version of SourceForge.net. For developments that are not related to Japan, we recommend you to use SourceForge.net.