(PHP)Smarty利用時に入力チェックエラー時に入力画面に戻し入力データを再表示する方法
フォームの入力でチェックをした後どうするかについて、
エラー画面に遷移しエラー表示→入力画面に戻す(戻るボタンで戻ってもらう)
という方法と、
入力画面に戻しエラー表示
という2パターンがあると思います。
(まぁAjax使ってたりすると、JavaScript内でチェックかけてPHP側行く前の入力画面の段階でDOMを使ってエラー表示する方法ができるんですが。。。)
今回やろうとしてるのは後者の方法です。
なぜなら、前者だと作るのは楽ですが、ユーザビリティを考えると後者の方が利点があります。
しかし、ここで問題になってくるのが、入力画面に戻った時にユーザの入力内容をどう再表示するかということです。
とりあえず、入力チェックエラー後に、エラー画面ではなく入力画面を再表示する場合のSmartyテンプレートの書き方例 を参考にして書いてみました。
概要として、PDOを使ってSQLiteから表示項目を取得して入力ページを表示。入力チェックでNGなら、入力ページに戻し、エラーを表示するというものです。
try {
// DBに接続する
$db = new PDO( 'sqlite2:./test.sqlite', '', '' );
/* ..... DBアクセス ..... */
//項目取得
$dbRes_product = $db->query( 'SELECT * FROM product ORDER BY id' )->fetchAll();
$dbRes_questionnaires = $db->query( 'SELECT * FROM questionnaires ORDER BY id' )->fetchAll();
// DBから切断する ( $db = null; も可能)
unset( $db );
} catch( PDOException $ex ) {
// DBアクセスができなかったとき
print 'アクセスできません : ' . $ex->getMessage();
unset( $db );
die();
}
//Smarty読み込み(ドキュメントルート外のSmartyクラスにアクセス)
require_once('./smarty/libs/Smarty.class.php');
//Smartyオブジェクト作成
//Smartyのディレクトリ設定(キャッシュやテンプレート置き場など)
$smarty->template_dir = "./smarty/templates";
$smarty->compile_dir = "./smarty/templates_c";
$smarty->cache_dir ="./smarty/cache";
//エスケープ
$smarty->default_modifiers = array('escape','nl2br');
//$_SESSION['postdata']にユーザが入力したデータがあるのでそれをアサイン
if( isset($_SESSION['postdata'])){
$smarty->assign("q", $_SESSION['postdata'] );
}else{
$smarty->assign("q", array());
}
//エラー情報アサイン
if( isset($_SESSION['err_info'])){
$smarty->assign("err", $_SESSION['err_info'] );
}else{
$smarty->assign("err", array());
}
$smarty->assign("product", $dbRes_product);
$smarty->assign("questionnaires", $dbRes_questionnaires);
//テンプレート表示
$smarty->display("connect.tpl");
?>
method="post" action="confirm.php" >
氏名(必須):
{if isset($err.name)}
{/if}
type="text" name="name" value="{if isset($q.name)}{$q.name}{else}氏名入力してください{/if}" >
{if isset($err.product)}
{/if}
{section name=iCnt loop=$product}
{if isset($q.product)
&& $q.product eq $product[iCnt].id}
checked="checked"
{/if}
value="{$product[iCnt].id}">{$product[iCnt].value}
{/section}
{if isset($err.questionnaires)}
{/if}
{section name=iCnt loop=$questionnaires}
type="checkbox" name="questionnaires[]"
{if isset($q.questionnaires)
&& is_array($q.questionnaires)
&& $questionnaires[iCnt].id|in_array:$q.questionnaires}
checked="checked"
{/if}
value="{$questionnaires[iCnt].id}">{$questionnaires[iCnt].value}
{/section}
type="submit" value="送信" name="submit">
(文字数制限のためハイライト無し)
session_start();
//入力チェック
InputCheck();
//okなら確認画面等に遷移。
function InputCheck(){
//セッション変数きれいに
unset($_SESSION['postdata']);
unset($_SESSION['err_info']);
//入力チェック処理
if( isset($_POST['name']) || empty($_POST['name']) ){
$errInfo['name'] = '氏名が指定されていません。';
}
if( ! isset($_POST['product']) ){
$errInfo['product'] = '項目が選択されていません。';
}
if( ! isset($_POST['questionnaires']) ){
$errInfo['questionnaires'] = '項目が選択されていません。';
}
if( count($errInfo) > 0 ){
//POSTデータ,エラー情報をセッション変数に持たす
$_SESSION['err_info'] = $errInfo;
$_SESSION['postdata'] = $_POST;
header("Location:input.php");
exit;
}
}
?>
ユーザが入力したフォームのデータをセッション変数に持たし、テンプレート内のIF文を使って、セッション変数が存在するならセットするというものですね。
テキストボックスなら、フォーム入力データを持つセッション変数内に存在すれば value にセットするだけです。
ラジオボタンは、ループ内で、データがフォーム入力データを持つセッション変数内に存在し、かつ value と同じ値ならチェックします。
複数選択できるチェックボックスは、ラジオボタンとほぼ同様ですが、is_array,in_array を使うのがみそです。
エラー情報も同様に、テンプレート内のIF文でデータがあれば表示します。
まぁたしかに、テンプレート内に条件分岐を入れるのは余りきれいなやり方ではないですが、それ以外にいい方法も思いつかなかったので。。。。