102.詳細ページの記述方法

 メンバー詳細ページはmember_detail.phpとなります。
 ここでは、前々項で紹介したように、新規で以下のような画面になります。

 

図0100b

 

 構造的にはprefecture_detail.phpと同じですが、こちらにはいろんなコントロール(入力領域)があります。
 メンバー名市郡町村以下1行テキストなので説明を省きます。問題は都道府県プルダウン、性別ラジオボタン、好きな果物のチェックボックス、そして、コメントの複数行テキストです。

都道府県プルダウン

 プルダウンはHTMLではselectタグとなります。PHPBaseではcselectクラスを利用して実装します。
 実装している関数は、echo_prefecture_select()関数です。
function echo_prefecture_select(){
    global $err_array;
    if(!isset($_POST['prefecture_id']))$_POST['prefecture_id'] = 0;
    //都道府県の一覧を取得
    $prefecture_obj = new cprefecture();
    $allcount = $prefecture_obj->get_all_count(false);
    $prefecture_rows = $prefecture_obj->get_all(false,0,$allcount);
    $tgt = new cselect('prefecture_id');
    $tgt->add(0,'選択してください',$_POST['prefecture_id'] == 0);
    foreach($prefecture_rows as $key => $val){
        $tgt->add($val['prefecture_id'],$val['prefecture_name'],$val['prefecture_id'] == $_POST['prefecture_id']);
    }
    $tgt->show($_POST['func'] == 'conf');
    if(isset($err_array['prefecture_id'])){
        echo '<br /><span class="red">' 
        . cutil::ret2br($err_array['prefecture_id']) 
        . '</span>';
    }
}
 まず新規でアクセスした場合、($_POST['prefecture_id']は存在しないので
    if(!isset($_POST['prefecture_id']))$_POST['prefecture_id'] = 0;
 のように0で初期化します。続いて、都道府県リストcprefectureのget_all_count()とget_all()を使って取得します。
 これでプルダウンは作成できますが、選択されていた場合を処理しなければなりません。この値はDBから読み込んだ時確認ページを行ったり来たりした場合、$_POST['prefecture_id']に入りますので、その値を使います。
 まず、
    $tgt = new cselect('prefecture_id');
    $tgt->add(0,'選択してください',$_POST['prefecture_id'] == 0);
 とcselectクラスのインスタンスを構築します。この際選択して下さいのオプションを記述しておきます。続いて
    foreach($prefecture_rows as $key => $val){
        $tgt->add($val['prefecture_id'],$val['prefecture_name'],$val['prefecture_id'] == $_POST['prefecture_id']);
    }
 と都道府県一覧をスキャンしながら$tgt->add()関数を呼び出します。この最後の引数に$val['prefecture_id'] == $_POST['prefecture_id']と記述します。これはtrueを渡すとselected="selected"というHTMLが記述されます。つまり選択状態になるわけです。prefecture_idが違う場合はfalseになりますので、結果としてselected="selected"は記述されません。
 最後に$tgt->show()関数確認画面か否かを引数に渡して呼び出せばプルダウンが表示されます。
 この項目は必須項目なので、その後にエラー文字列を首都力します。

性別ラジオボタン

 性別のラジオボタンはecho_member_gender_radio()関数です。ラジオボタンは単一選択なのでプルダウンとほぼ変わりません。
function echo_member_gender_radio(){
    global $err_array;
    if(!isset($_POST['member_gender']))$_POST['member_gender'] = 0;
    //メンバー性別のラジオボタンを作成
    $tgt = new cradio('member_gender');
    $tgt->add(1,'男性',$_POST['member_gender'] == 1);
    $tgt->add(2,'女性',$_POST['member_gender'] == 2);
    $tgt->show($_POST['func'] == 'conf',' ');
    if(isset($err_array['member_gender'])){
        echo '<br /><span class="red">' 
        . cutil::ret2br($err_array['member_gender']) 
        . '</span>';
    }
}
 ここでは男女addしてますが、マスタ化するまでもないので、ベタ打ちしています。最後に$tgt->show()関数を呼び出せば、表示されます。

コメントの複数行テキスト

 順番から行くと次にチェックボックスですが、ちょっと厄介なので、複数行テキストから説明します。関数はecho_member_comment()関数となります。
function echo_member_comment(){
    global $err_array;
    if(!isset($_POST['member_comment']))$_POST['member_comment'] = '';
    $tgt = new ctextarea('member_comment',$_POST['member_comment'],'cols="70" rows="10"');
    $tgt->show($_POST['func'] == 'conf');
}
 複数行テキストctextareaクラスとなります。記述方法は1行テキストと同じです。確認画面で改行brタグに変換されます。

果物のチェックボックス

 複数行チェックボックスは少し複雑な処理になります。
 まず、PHPの文法について述べます。PHPではPOSTやGETに配列を渡すことができます。inputタグなどのname'fruits[]'と記すと、$_POST['fruits'][0]、$_POST['fruits'][1]、...のように配列で渡してくれるのです。
 さてそのことを念頭に、まずデータから読み込む部分から説明しましょう。
 詳細ページでは$_POSTにDBから読み込む、と都道府県管理とところで述べました。メンバー詳細では実行ブロック内で以下のように記述されています。
    if($member_id > 0){
        if(($_POST = $member_obj->get_tgt(false,$member_id)) === false){
            $_POST['func'] = 'new';
        }
        else{
            $_POST['fruits'] = $member_obj->get_all_fruits_match(false,$member_id);
            $_POST['func'] = 'edit';
        }
    }
 赤くなっているところがそのメンバーが保存時に選択した果物の一覧ということになります。$_POST['fruits']に読み込みます。この変数はname='fruits[]'となっているチェックボックスと等価ですから、実際のチェックボックス作成と互換が取れるわけです。
 以上を念頭に果物のチェックボックスを作成する関数である、echo_fruits_match_check()関数を見てみます。
function echo_fruits_match_check(){
    global $err_array;
    global $member_id;
    //フルーツの一覧を取得
    $fruits_obj = new cfruits();
    $fruits_rows = $fruits_obj->get_all(false);
    //果物のチェックボックスを作成
    $tgt = new cchkbox('fruits[]');
    if(!isset($_POST['fruits']))$_POST['fruits'] = array();
    foreach($fruits_rows as $key => $val){
        $check = false;
        if(array_search($val['fruits_id'],$_POST['fruits']) !== false){
            $check = true;
        }
        $tgt->add($val['fruits_id'],$val['fruits_name'],$check);
    }
    $tgt->show($_POST['func'] == 'conf',' ');
}
 まず、フルーツの一覧を取得します。
    $fruits_obj = new cfruits();
    $fruits_rows = $fruits_obj->get_all(false);
 続いて、果物のチェックボックスを作成します。ここで変数名は'fruits[]'と配列にしておきます。
    $tgt = new cchkbox('fruits[]');
 また、新規の時はPOSTされませんので、POSTされてなかったときは、以下のように空の配列で初期化します。
    if(!isset($_POST['fruits']))$_POST['fruits'] = array();
 そしてチェックボックスを作成します。その際POSTされた配列内にフルーツのIDがあればチェックするように作成します。赤くなっているとことがPOST配列を調べているところです
    foreach($fruits_rows as $key => $val){
        $check = false;
        if(array_search($val['fruits_id'],$_POST['fruits']) !== false){
            $check = true;
        }
        $tgt->add($val['fruits_id'],$val['fruits_name'],$check);
    }
 最後に、show()します。
    $tgt->show($_POST['func'] == 'conf',' ');
 これで、DBから取り出した場合は、チェックが入っていて、確認画面とやり取りのなかでもPOSTが保持されます。

DB登録

 DBへの登録はregist()関数およびregist_fruits()関数をい使います。regist_fruits()関数regist()関数から呼ばれます。まずregist()関数です。
function regist(){
    global $member_id;
    $dataarr = array();
    $dataarr['member_name'] = (string)$_POST['member_name'];
    $dataarr['prefecture_id'] = (int)$_POST['prefecture_id'];
    $dataarr['member_address'] = (string)$_POST['member_address'];
    $dataarr['member_gender'] = (int)$_POST['member_gender'];
    $dataarr['member_comment'] = (string)$_POST['member_comment'];
    $chenge = new cchange_ex();
    if($member_id > 0){
        $chenge->update('member',$dataarr,'member_id=' . $member_id);
        regist_fruits($member_id);
        cutil::redirect_exit($_SERVER['PHP_SELF'] . '?mid=' . $member_id);
    }
    else{
        $mid = $chenge->insert('member',$dataarr);
        regist_fruits($mid);
        cutil::redirect_exit($_SERVER['PHP_SELF'] . '?mid=' . $mid);
    }
}
 都道府県詳細の場合は登録するフィールドは一つでしたが、ここでは複数あります。複数のフィールドは
    $dataarr['member_name'] = (string)$_POST['member_name'];
    $dataarr['prefecture_id'] = (int)$_POST['prefecture_id'];
    //......
 のように$dataarrフィールド名の連想配列として追加します。
 そしてupdateまたはinsertします。
 updateの場合はmember_idは決まっていますが、insertの場合はインサートした後でないとわかりません。
 insert()関数は追加したプライマリキーを返しますので、そのキーを使ってregist_fruits()関数を呼び出します。
function regist_fruits($member_id){
    $chenge = new cchange_ex();
    $chenge->delete("fruits_match","member_id=" . $member_id);
    foreach($_POST['fruits'] as $key => $val){
        $dataarr = array();
        $dataarr['member_id'] = (int)$member_id;
        $dataarr['fruits_id'] = (int)$val;
        $chenge->insert('fruits_match',$dataarr);
    }
}
regist_fruits()関数では、まず、
    $chenge->delete("fruits_match","member_id=" . $member_id);
 で、既に登録されているそのメンバーのフルーツを削除します。そして
    foreach($_POST['fruits'] as $key => $val){
        $dataarr = array();
        $dataarr['member_id'] = (int)$member_id;
        $dataarr['fruits_id'] = (int)$val;
        $chenge->insert('fruits_match',$dataarr);
    }
 と$_POST['fruits']の内容を、1行ずつ追加していきます。
 ここのようにいったん削除してから追加、としないと前のデータを保持してしまうので、まずいことになります。

 この項ではメンバー詳細について説明しました。やはりチェックボックスコントロールが比較的厄介な内容になります。
 ただどういうわけか、最近の傾向として、タグ(関連付け)アンケート処理などでチェックボックスをはじめとした複数選択処理が仕様として、増えているように思います。
 クライアントさんもプログラマが苦労するのを知っててわざとこのような仕様を増やしているのかなあ、などと勘ぐってしまうのです(もちろん、そんなことはないんだろうけどね)。