前回は操作カラムの削除ボタンから、収支データを削除する機能を実装しました。
今回は編集ボタンから収支データを編集できるように実装していきます。
前回の記事はこちら↓
削除機能同様、まずは流れを確認します。
①データidを渡し編集ページに移動
②渡されたデータidをもとに入力情報を復元
③UPDATE文で情報を更新しパラメータ付きでホームに戻す
それでは順番に実装していきます。
データidを渡し編集ページに移動
編集ボタンを押し編集画面へ遷移した際、recordsテーブルの何番目のデータの情報であるかを渡す必要があります。
index.phpの編集ボタン部分を見ると以下のようになっています。
<!--パソコン表示用-->
<form action="./record-edit.php" method="POST">
<input type="hidden" name="record_id" value="1">
<input type="submit" class='c-button c-button--bg-green edit fas' value="">
</form>
<!--スマホ表示用-->
<form action="./record-edit.php" method="POST">
<input type="hidden" name="record_id" value="1">
<input type="submit" class="c-button c-button--bg-green edit" value="編 集">
</form>
formタグを仕込んで、編集ボタンを押したらrecord-edit.phpにPOST送信する処理になっています。
ここで注目するのがtype=hiddenで画面上では非表示にしているinput要素です。
このvalue属性には現在「1」が入っていますが、これをSQLで取得した$id(=データ番号)に変更します。(スマホ表示用も同様に書き換え)
<!--PC用-->
<form action="./record-edit.php" method="POST">
<input type="hidden" name="record_id" value="<?php echo h($id); ?>"> <!--value属性を変更-->
<input type="submit" class='c-button c-button--bg-green edit fas' value="">
</form>
<!--スマホ用-->
<form action="./record-edit.php" method="POST">
<input type="hidden" name="record_id" value="<?php echo h($id); ?>"> <!--value属性を変更-->
<input type="submit" class="c-button c-button--bg-green edit" value="編 集">
</form>
これで編集画面にデータ番号を渡すことができるようになります。
実際に情報が渡っているか確認します。以下をrecord-edit.phpの冒頭に記述します。
<?php
require_once('./dbconnect.php');
include_once('./functions.php');
if ($_POST['record_id'] && $_POST['record_id'] > 0) :
$record_id = $_POST['record_id'];
echo $record_id;
else :
header('Location: ./index.php?dataOperation=error');
exit();
endif;
?>
まずはこれまで通りデータベース接続ファイルと関数ファイルを読み込みます。
そしてif文でname属性がrecord_idの情報がPOST送信されているかつ、その値が0より大きい場合に値を変数に格納しています。
もし条件に一致しない遷移が行われた場合は削除機能の正しくない処理としてパラメータ付きでホームへ戻しています。
以上を記述して編集ボタンを押すと、画面上部にデータ番号が表示されます。
それではこの数値を使って情報を復元しましょう。
入力情報を復元する
それぞれの項目に編集したい情報を復元するため、まずはそのデータを探し各情報を変数に格納します。以下を冒頭のPHPプログラム内に追記します。
//SQLの発行と実行
$sql = 'SELECT count(*), id, date, title, amount, spending_category, income_category, type, payment_method, credit, qr, memo FROM records WHERE id =? LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bind_param('i', $record_id);
sql_check($stmt, $db);
//取得した値の格納
$stmt->bind_result($count, $id, $date, $title, $amount, $spending_category, $income_category, $type, $payment_method, $credit, $qr, $memo);
$stmt->fetch();
//不正な遷移が行われた場合の処理
if ($count !== 1) :
header('Location: ./index.php?dataOperation=error');
endif;
//仮出力
$br = '<br>';
echo $br . $date . $br . $title . $br . $amount . $br . $spending_category . $br . $income_category . $br . $type . $br . $payment_method . $br . $credit . $br . $qr . $br . $memo;
$stmt->close();
少し長くなりましたが、SQLを発行・実行・取得値の格納を行い仮出力をしています。
ここで不正な遷移の処理を挟んでいるのは、ホーム画面では表示されていないtype=hidden要素の落とし穴を補うためです。
一見画面上では見えていないのですが、デベロッパーツール上では確認したりvalue属性の値を変えることができます。
ここでvalueをデータベースに存在しない値に変更され遷移が行われたときは、日付やタイトルなどすべてのカラムがnullとなることを条件文に利用して、パラメータ付きでホームへ戻す処理をします。
↓デベロッパーツールからvalueを変更し遷移を試みた例
正しく遷移が行われた場合は、編集画面が表示され現在echoで仮出力しているデータ内容が画面左上に表示されます。
それではこの数値を使って情報を復元します。
現在時刻とデータidをセットする
情報復元の前に、入力情報と更新をするときに必要なデータidをtype=hiddenでフォームの中にセットします。
<input type="hidden" name="record_id" value="<?php echo h($id); ?>">
<input type="hidden" name="input_time" id="input_time" value="<?php echo date("Y/m/d-H:i:s"); ?>">
日付・タイトル・金額情報の復元
以下のコードは入力箇所や属性を一部抜粋して記述しています。
<!--日付の復元-->
<label for="date"><input name="date" value="<?php echo h($date); ?>"></label>
<!--タイトルの復元-->
<input name="title" value="<?php echo h($title); ?>">
<!--金額の復元-->
<input name="amount" value="<?php echo h($amount); ?>">
上記3項目はvalue属性に取得した値をechoすることで復元ができます。
データタイプ(支出・収入)情報の復元
続いて支出・収入ラジオボタンの復元です。これは取得した値とラジオボタンのvalue属性の値が一致した場合に、選択していることを表す「checked」をinputタグ内に出力することで復元できます。
<!--支出ラジオボタン-->
<input type="radio" name="type" value="0" <?php echo $type === 0 ? 'checked' : ''; ?>>支出
<!--収入ラジオボタン-->
<input type="radio" name="type" value="1" <?php echo $type === 1 ? 'checked' : ''; ?>>収入
見やすくするため必要な属性のみを抜粋しています。
タイプの復元は、取得してきた$typeの値を条件に三項演算子を展開し、$typeの値とvalueの値が一致する場合にcheckedをタグ内に出力することで、選択状態にすることができます。
カテゴリーや支払い方法情報の復元
続いてカテゴリーや支払い方法などを復元する前に、現在収入が選択されているのに下の項目が表示されないので、ホーム画面のように支出タイプなら支出カテゴリーや支払い方法を、収入タイプなら収入カテゴリーを表示するようにします。
まず「record-edit.js」という名前でJavaScriptファイルを作成し、record-edit.phpのbody閉じタグ前にファイルの読み込みを追記します。
<script src="./js/radio.js"></script>
<script src="./js/import.js"></script>
<script src="./js/functions.js"></script>
<!--以下を追記-->
<script src="./js/record-edit.js"></script> <!--読み込む順番を変えると関数が動かなくなります-->
ファイルを作成したら以下を記述します。
//支出が選択されていたら支出カテゴリーを表示
//収入が選択されていたら収入カテゴリーを表示
if (typeChecked[0].checked) { //支出ボタン選択時
spendingCategoryBox.classList.add('show');
paymentMethodBox.classList.add('show');
} else if (typeChecked[1].checked) { //収入ボタン選択時
incomeCategoryBox.classList.add('show');
}
冒頭のif文では、支出か収入かのラジオボタンにcheckedがあるかを調べ、選択状態にあれば該当要素(カテゴリー選択や支払い方法選択)にクラスを付与して表示するようにしています。
以上を記述して再度編集画面をリロードすると以下のように、カテゴリー要素が表示されます。
それではカテゴリーと支払い方法(支出データのとき)の復元をします。
<!--支出カテゴリーの復元-->
<div class="u-js__show-switch flex p-form__flex-input sp-change-order" id="spendingCategoryBox">
<p class="long-name">支出カテゴリー</p>
<select name="spending_category" id="spendingCategory">
<option value="0">選択してください</option>
<!--以下に書き換え-->
<?php
//データベースと連携するためSQLを発行し実行
$stmt_spandingcat = $db->prepare('SELECT * FROM spending_category');
sql_check($stmt_spendingcat, $db);
$stmt_spendingcat->bind_result($id, $name);
while ($stmt_spendingcat->fetch()) :
?>
<!--選択項目をループ文で出力&
冒頭で取得したカテゴリーの数値とvalue属性の値が一致の場合はselectedを出力で選択状態に
-->
<option value="<?php echo h($id); ?>" <?php echo $spending_category === $id ? 'selected' : ''; ?>><?php echo h($name); ?></option>
<?php endwhile; ?>
<!--//書き換えここまで-->
<!--以下削除-->
<option value="1">食費</option>
<option value="2">日用品</option>
<option value="3">交通費</option>
<!--削除ここまで-->
</select>
</div>
書き換え前は項目がデータベースと連携していなかったので、まずはSQLでデータベースの内容を取得しwhileのループ文で出力します。
取得したデータをもとにoptionタグで選択項目を出力する処理は、ホーム画面と同様です。
ここでデータの復元をするので、冒頭で取得したカテゴリーの数値とvalue属性の数値が一致するoptionタグにはselectedを出力させます。
このようにすることで情報を復元することができます。
同じ処理を収入カテゴリーでも行います。
支出カテゴリーと同様に「選択してください」以外のoptionタグは削除します。
<?php
$stmt_incomecat = $db->prepare('SELECT * FROM income_category');
sql_check($stmt_incomecat, $db);
$stmt_incomecat->bind_result($id, $name);
while ($stmt_incomecat->fetch()) :
?>
<option value="<?php echo h($id); ?>" <?php echo $income_category === $id ? 'selected' : ''; ?>><?php echo h($name); ?></option>
<?php endwhile; ?>
書き換える場所とプログラムの流れは支出カテゴリーと同様です。
$spending_categoryとなっていたところを$income_categoryに変えるだけです。
次に支払い方法の復元を行います。
プログラムの流れはホーム画面で選択項目をデータベースと連携させたときと同じです。
「選択しない」以外のoptionタグは削除します。
<div id="paymentMethodBox" class="u-js__show-switch flex p-form__flex-input sp-change-order">
<p class="long-name">支払い方法</p>
<select name="payment_method" id="paymentMethod" onchange="hasChildSelect('1', creditSelectBox, qrChecked);hasChildSelect('2', qrSelectBox, creditChecked);">
<option value="0">選択してください</option>
<!--以下を追記-->
<?php
$fixedPaymentMethod = ['現金', 'クレジット', 'スマホ決済'];
$fixedPaymentMethod_id = ['', 'radioCredit', 'radioQr'];
for ($i = 0; $i < 3; $i++) : ?>
<option value="<?php echo $i + 1; ?>" id="<?php echo $fixedPaymentMethod_id[$i]; ?>"><?php echo $fixedPaymentMethod[$i]; ?></option>
<?php endfor; ?>
<?php
$stmt_paymethod = $db->prepare('SELECT * FROM payment_method WHERE id > 3');
sql_check($stmt_paymethod, $db);
$stmt_paymethod->bind_result($id, $name);
while ($stmt_paymethod->fetch()) :
?>
<option value="<?php echo h($id); ?>" <?php echo $payment_method === $id ? 'selected' : ''; ?>><?php echo h($name); ?></option>
<?php endwhile; ?>
<!--追記ここまで-->
</select>
</div>
これまで同様、冒頭で取得してきた$payment_methodの数値とoptionタグのvalue属性の値が一致の場合はselectedを出力しています。この処理をfor文で出力している現金〜スマホ決済にも記述します。
<option value="<?php echo $i; ?>" id="<?php echo $fixedPaymentMethod_id[$i]; ?>" <?php echo $payment_method === $i + 1 ? 'selected' : ''; ?>><?php echo $fixedPaymentMethod[$i]; ?></option>
上記まで実装をするとカテゴリーや支払い方法までが復元できます。
上記左画像では、クレジットカードやスマホ決済が選択されているので、更に詳細な選択項目を出す必要があります。
クレジットカードとスマホ決済情報の復元
現状のプログラムでは、クレジットやスマホ決済が選択されている場合でも詳細項目が表示されません。
詳細項目を表示するJavaScriptプログラムをrecord-edit.jsに記述していきましょう。
//支払い方法のvalueを取得し、2か3だったら詳細項目を表示する
const paymentMethodValue = paymentMethod.value;
if (paymentMethodValue === "2") {
creditSelectBox.classList.add('show');
} else if (paymentMethodValue === "3") {
qrSelectBox.classList.add('show');
}
支払い方法で現在選択されている項目のvalueを取得し変数に格納します。
そしてその値が2(=クレジットカード選択)か3(=スマホ決済選択)の場合に該当要素にクラスを付与して表示する処理です。
以上を記述することでクレジットカードやスマホ決済が選択されているデータの場合は、詳細選択要素が表示されるようになります。
続けてクレジットカードとスマホ決済のデータを復元します。
<?php
$stmt_〇〇 = $db->prepare('SELECT * FROM creditcard'); //スマホ決済はcreditcardをqrに書き換え
sql_check($stmt_〇〇, $db);
$stmt_〇〇->bind_result($id, $name);
while ($stmt_〇〇->fetch()) :
?>
<!--スマホ決済は以下$creditを$qrに書き換え-->
<option value="<?php echo h($id); ?>" <?php echo $credit === $id ? 'selected' : ''; ?>><?php echo h($name); ?></option>
<?php endwhile; ?>
「選択しない」のoptionタグの下に追記しました。また直接書いていたその他のoptionタグは削除しました。
value属性には取得した$idを出力し、冒頭で取得した$credit or $qrの値とvalueの値が一致する場合に、選択状態を表すselectedを出力するよう記述しています。
以上を実装することで以下のようにクレジットカードとスマホ決済の情報復元をすることができるようになりました。
最後にメモを復元しましょう。
メモ情報の復元
textareaタグで作成しているメモ要素にメモ情報を復元します。
<textarea name="memo" id="" cols="45" rows="5" placeholder="入力収支の詳細"><?php echo h($memo); ?></textarea>
textareaタグとその閉じタグの間に冒頭で取得した$memoを出力し復元します。
以上で情報の復元は完了しました。
続いて更新ボタンを押したら既存の情報を変更した情報に上書きする機能を実装します。
更新ボタンを押してデータを更新する
まずは更新ボタンを押したら、更新プログラムのファイルに移動させるためにformタグのaction属性にファイルルートを記述するのですが、更新プログラムはデータ登録プログラムと似ているので、以前作ったrecord-create.phpに移動しようと思います。
まずは更新画面のformタグのaction属性に「./record-create.php」を指定します。
<form class="p-form p-form--input-record" name="recordInput" action="./record-create.php" method="POST">
続いてrecord-create.phpに移動した際、どちらのフォームからの送信かを見分けて処理を行う必要があるため、登録や更新ボタンを作っているinputタグにname属性を付けて処理を分けます。では双方のtype=submitのinputタグにname属性を追加します。
<!--ホーム画面(index.php)登録ボタンの場合-->
<input class="c-button c-button--bg-blue" name="record_create" type="submit" value="登録">
<!--更新画面(record-edit.php)更新ボタンの場合-->
<input class="c-button c-button--bg-blue" name="record_update" type="submit" value="更新">
上記で追加したname属性を使って条件分とその処理をrecord-create.phpに記述します。
登録処理と更新処理で異なる処理部分は、SQLの発行〜bind_param()で値を設定するまでです。
//書き換え前
$sql = 'INSERT INTO records VALUES(0,?,?,?,?,?,?,?,?,?,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiiiss', $date, $title, $amount, $spending_category, $income_category, $type, $payment_method, $credit, $qr, $memo, $input_time);
//書き換え後
if (isset($_POST['record_create']) && $_POST['record_create'] === '登録') :
$sql = 'INSERT INTO records VALUES(0,?,?,?,?,?,?,?,?,?,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiiiss', $date, $title, $amount, $spending_category, $income_category, $type, $payment_method, $credit, $qr, $memo, $input_time);
elseif (isset($_POST['record_update']) && $_POST['record_update'] === '更新') :
$id = filter_input(INPUT_POST, 'record_id', FILTER_SANITIZE_SPECIAL_CHARS);
$sql = 'UPDATE records SET date=?, title=?, amount=?, spending_category=?, income_category=?, type=?, payment_method=?, credit=?, qr=?, memo=?, input_time=? WHERE id=?';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiiissi', $date, $title, $amount, $spending_category, $income_category, $type, $payment_method, $credit, $qr, $memo, $input_time, $id);
else :
header('Location: ./index.php?dataOperation=error');
exit();
endif;
条件分岐 if (isset($_POST[‘record_create’]) && $_POST[‘record_create’] === ‘登録’) の処理内容は書き換え前と同じプログラムです。
elseif (isset($_POST[‘record_update’]) && $_POST[‘record_update’] === ‘更新’) の処理内容が更新プログラムです。
まず登録処理では受け取る必要はなかったデータidを受け取る必要があるので、$idとしてデータを受け取り格納しています。
そしてUPDATE文で該当データを更新します。最後にbind_param()でSQLの「?」に入れる値をセットしています。
これ以降のSQL実行プログラムに変更はありません。
ここまで実装すると、更新画面から情報を更新すると、ホーム画面では更新された情報が一覧部分に表示されます。登録プログラムも問題なく動いています。
更新プログラムは以上で完成です。
最後におまけとして、更新画面が完了したら削除の処理のときと同様にメッセージを出すようにします。
【おまけ】更新完了メッセージを出す
現在、record-create.phpの最後のheader()でindex.phpを指定していますが、パラメータを付けてホームへ戻すようにします。
//書き換え前
header('Location: ./index.php');
exit();
//書き換え後
if (isset($_POST['record_create']) && $_POST['record_create'] === '登録') :
header('Location: ./index.php');
elseif (isset($_POST['record_update']) && $_POST['record_update'] === '更新') :
header('Location: ./index.php?dataOperation=update');
endif;
exit();
登録の処理の際はこれまで同様パラメータは無しでホームへ返し、更新処理の際はパラメータ付きでホームへ返します。
それではindex.phpのメッセージ部分を編集していきます。
まずメッセージボックスを出す条件に、$_GET[‘dataOperation’] === ‘update’ を追加します。
<!--書き換え前-->
<?php if ($_GET['dataOperation'] && ($_GET['dataOperation'] === 'delete' || $_GET['dataOperation'] === 'error')) : ?>
<!--書き換え後-->
<?php if ($_GET['dataOperation'] && ($_GET['dataOperation'] === 'delete' || $_GET['dataOperation'] === 'update' || $_GET['dataOperation'] === 'error')) : ?>
続いてメッセージ本文の部分を書き換えます。
<!--書き換え前-->
<p id="doneText">
<?php echo ($_GET['dataOperation'] === 'error') ? '正しく処理されませんでした' : '操作が完了しました'; ?>
</p>
<!--書き換え後-->
<p id="doneText">
<?php
if ($_GET['dataOperation'] === 'error') :
echo '正しく処理されませんでした';
elseif ($_GET['dataOperation'] === 'delete') :
echo '削除しました';
elseif ($_GET['dataOperation'] === 'update') :
echo '更新しました';
endif;
?>
</p>
これまでは三項演算子で出力していましたが、パターンが3つに増えたのでif-elseif文で出力する方法に変更しています。
更新が正常に処理されホームへ戻ると、上記のようなメッセージが出力されました。
最後に
少し長くなりましたが、今回は登録した情報を更新する機能を実装しました。
次回はカテゴリーや支払い方法、クレジットやスマホ決済の編集画面の機能を実装していきます。
最後までお読みいただきありがとうございました。
コメント