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

 ここでは、sources/prefecture_detail.phpについて説明します。

詳細ページの機能

 ページの最上部にライブラリのインクルードが前項のようにありますので、それがまず記述されます。
 そして詳細ページの機能は以下のようになります。
1、一覧ページに戻ることができる
2、都道府県名を修正できる(確認画面つき)
3、都道府県を新規で追加できる(確認画面つき)
 では個別に見ていきます。

1、一覧ページに戻ることができる

 これは単純にprefecture_listへのリンクを記述すればいいのかというと、そうでもありません。一覧ページからのリンクはページ情報が含まれますので、そのページに戻ったほうが、直感的に扱いやすいでしょう。
 prefecture_detail.php実行ブロックに、
$page = 0;
if(isset($_GET['page']) 
    && cutil::is_number($_GET['page'])
    && $_GET['page'] > 0){
    $page = $_GET['page'];
}
 と記述があります。これはページ情報があれば$pageに設置ということです。この変数は一覧に戻るのリンクに使用します。
 一覧に戻るリンクはHTMLブロックに以下のように記述されています。
<a href="prefecture_list.php<?php echo_page(); ?>">一覧に戻る</a>
 GETパラメータに<?php echo_page(); ?>が記述されています。この関数は
function echo_page(){
    global $page;
    if($page > 0){
        echo '?page=' . $page;
    }
}
 となっていて、もとの一覧ページに戻れるようになっています。

2、都道府県名を修正できる(確認画面つき)

 これはGET/POST引数で都道府県IDが指定された場合の処理になります。
 まず、実行ブロックで
$prefecture_id = 0;
//中略
if(isset($_GET['pid']) 
//cutilクラスのメンバ関数をスタティック呼出
    && cutil::is_number($_GET['pid'])
    && $_GET['pid'] > 0){
    $prefecture_id = $_GET['pid'];
}
//$_POST優先
if(isset($_POST['prefecture_id']) 
//cutilクラスのメンバ関数をスタティック呼出
    && cutil::is_number($_POST['prefecture_id'])
    && $_POST['prefecture_id'] > 0){
    $prefecture_id = $_POST['prefecture_id'];
}
 これで$prefecture_idには新規の場合は0が、それ以外は都道府県IDが代入されます。

 さて詳細ページ状態というパラメータを持っています。$_POST['func']に代入される値ですが、確認画面の場合は'conf'です。追加/更新の場合は'set'です。新規'new'になり、編集'edit'です。
 これらを$_POST['func']渡されたかどうかを判断して、状態を決定します。
 実行ブロックではその振り分けを行います。以下のコードです。
if(isset($_POST['func'])){
    switch($_POST['func']){
        case 'set':
            if(!paramchk()){
                $_POST['func'] = 'edit';
                $err_flag = 1;
            }
            else{
                regist();
                //regist()内でリダイレクトするので
                //ここまで実行されればリダイレクト失敗
                $_POST['func'] = 'edit';
                //システムに問題のあるエラー
                $err_flag = 2;
            }
        case 'conf':
            if(!paramchk()){
                $_POST['func'] = 'edit';
                $err_flag = 1;
            }
        break;
        case 'edit':
            //戻るボタン。
        break;
        default:
            //通常はありえない
            echo '原因不明のエラーです。';
            exit;
        break;
    }
}
else{
    if($prefecture_id > 0){
        if(($_POST = $prefecture_obj->get_tgt(false,$prefecture_id)) === false){
            $_POST['func'] = 'new';
        }
        else{
            $_POST['func'] = 'edit';
        }
    }
    else{
        //新規の入力フォーム
        $_POST['func'] = 'new';
    }
}
 コードを追いかけていくとわかりますが、まず$_POST['func']が渡された場合はパラメータのチェックを行います。
 パラメータのチェックが必要なのは確認画面もしくは追加/更新の時です。以下の関数を呼び出します。
function paramchk(){
    global $err_array;
    $retflg = true;
    /// 都道府県名の存在と空白チェック
    if(ccontentsutil::chkset_err_field($err_array,'prefecture_name','都道府県名','isset_nl')){
        $retflg = false;
    }
    return $retflg;
}
 ここで呼び出しているccontentsutil::chkset_err_field()関数はエラーチェック用のユーティリティ関数ですcommon/contents_func.phpに記述があります。
 この最後の引数'isset_nl'というのは存在と空白のチェックです。ccontentsutil::chkset_err_field()関数はこのパラメータによってどういうエラーチェックを行うかを決めます。'isset_nl'ccontentsutil::chkset_err_field()関数を呼び出した場合、以下のコードが実行されます。
            case 'isset_nl':
                //存在と空白チェック
                if(!isset($_POST[$name])){
                    $err_array[$name] = "{$field}が見つかりません";
                    return true;
                }
                elseif($_POST[$name] == '' ){
                    $err_array[$name] = "{$field}は必須項目です";
                    return true;
                }
            break;
 つまり$err_array配列にエラー内容をセットします。エラーの表示を修正する場合はcommon/contents_func.phpccontentsutil::chkset_err_field()関数を直接修正してください。このファイルはユーティリティ的な関数が記述されてますが、common/function.phpとは違って、ライブラリの一部という意味合いは弱いファイルとなっています。
 さて、IDが指定された場合のデータの読み込みですが、
//都道府県クラスを構築
$prefecture_obj = new cprefecture();
 とcprefectureクラスのインスタンスを構築し
    if($prefecture_id > 0){
        if(($_POST = $prefecture_obj->get_tgt(false,$prefecture_id)) === false){
            $_POST['func'] = 'new';
        }
        else{
            $_POST['func'] = 'edit';
        }
    }
 と読み込んでいます。この処理はどういう処理かというと$_POST変数の直接読み込んでいます。
 $_POST変数は特殊なグローバル変数ですが、読み込みオンリーというわけではありません。ですから配列内に値をセットすることも可能です。
 このような形にすることでDBから読んだ場合ユーザーがPOSTした場合を同じように扱えることになります。
 そして、各コントロール(ここでは都道府県のフィールドです)は
function echo_prefecture_name(){
    global $err_array;
    if(!isset($_POST['prefecture_name']))$_POST['prefecture_name'] = '';
    $tgt = new ctextbox('prefecture_name',$_POST['prefecture_name'],'size="70"');
    $tgt->show($_POST['func'] == 'conf');
    if(isset($err_array['prefecture_name'])){
        echo '<br /><span class="red">' 
        . cutil::ret2br($err_array['prefecture_name']) 
        . '</span>';
    }
}
 のように記述します。ここで出てくるctextboxはページャー同様common/controls.phpに記述があるinputクラスです。このクラスは入力状態確認状態を表示することができます。show()メンバ関数trueを渡すと確認状態falseを渡すと入力状態、になります。
    $tgt->show($_POST['func'] == 'conf');
 と記述されていますので、$_POST['func'] が'conf'の時はtrueという意味になります。

 また入力状態確認状態の違いは操作ボタンにもあります。
function echo_switch(){
    global $prefecture_id;
    if($_POST['func'] == 'conf'){
        $button = '更新';
        if($prefecture_id <= 0){
            $button = '追加';
        }
        $str =<<<END_BLOCK
<input type="button"  value="戻る" onClick="javascript:set_func_form('edit','')"/> 
<input type="button"  value="{$button}" onClick="javascript:set_func_form('set','')"/>
END_BLOCK;
    }
    else{
        $str =<<<END_BLOCK
<input type="button"  value="確認" onClick="javascript:set_func_form('conf','')"/>
END_BLOCK;
    }
    echo $str;
}
 この関数は入力状態確認状態で表示を振り分けています。

 最後に更新処理ですがregist()関数を使います。
function regist(){
    global $prefecture_id;
    $dataarr = array();
    $dataarr['prefecture_name'] = (string)$_POST['prefecture_name'];
    $chenge = new cchange_ex();
    if($prefecture_id > 0){
        $chenge->update('prefecture',$dataarr,'prefecture_id=' . $prefecture_id);
        cutil::redirect_exit($_SERVER['PHP_SELF'] . '?pid=' . $prefecture_id);
    }
    else{
        $pid = $chenge->insert('prefecture',$dataarr);
        cutil::redirect_exit($_SERVER['PHP_SELF'] . '?pid=' . $pid);
    }
}
 まず、赤くなっているところに注目してください。cchange_exクラスのインスタンスを構築しています。このクラスは一覧表示のところの削除のところでも紹介しました。updateやinsertもこの関数を使います。
 使い方ですが、
    $dataarr['prefecture_name'] = (string)$_POST['prefecture_name'];
 のように連想配列を作って、updateやinsert関数に渡します。この配列は$arr['フィールド名'] = 値となる連想配列です。この例では'prefecture_name'フィールドだけですが、通常はもっとたくさんのフィールドを修正、追加します。
 そんな場合は
    $dataarr['hoge'] = (string)$_POST['huga'];
    $dataarr['hogehoge'] = (int)$_POST['hogehoge'];
 のようにします(string)や(int)は必要です。この関数は内部で値の型を知らべて、形に合ったSQL文を作成します。特に、番号は必ず(int)を付けましょう。

3、都道府県を新規で追加できる(確認画面つき)

 追加処理は更新処理とほとんど変わりません。regist()関数idが0の場合cchange_ex::insert()関数を読んでいます。