前回は選択項目編集画面からホームへ戻ったときのセッション処理の追加と収支データ出力箇所のページネーション機能の追加を行いました。
↓前回の記事はこちら
今回はカレンダーを作成し、いついくらの収支があったのかをひと目で分かる機能を追加します。
カレンダー機能の追加
PHPでカレンダーを作成する方法は調べるとわかりやすい記事が多く出てくるのでそちらを参考にします。
↓今回参考にさせていただいた記事はこちら
いきなりPHPで実装せず、まずはHTMLでカレンダーを作成します。
<div class="u-flex-box records-input-calendar"><!--追加 78行目付近-->
<section class="p-section p-section__records-input">
:
省略
:
</section>
</div><!--追加 213行目付近-->
まずデータ入力要素とカレンダーを横並びにするため、データ入力要素の親要素「<div class=”u-flex-box records-input-calendar”>」を作成します。
今回はすでにCSSを指定しているためCSSは割愛します。
続いてカレンダーをHTMLで作成します。記述場所は「</section>」の下に追記します。
<section class="p-section p-section__records-input">
:
省略
:
</section>
<!--以下追加 214行目付近-->
<section class="p-section p-section__calendar" id="calendar">
<p>
<a href=""><</a>
2022年10月
<a href="">></a>
<a href="">今月</a>
</p>
<div class="p-calendar__sum">
<p>
支出合計<span class="pc_only">:</span><br class="sp_only">
<span class="text-red">-¥10,000</span>
</p>
<p>
収入合計<span class="pc_only">:</span><br class="sp_only">
<span class="text-blue">¥100,000</span>
</p>
<p>
収支合計<span class="pc_only">:</span><br class="sp_only">
<span class="text-blue">¥90,000</span>
</p>
</div>
<table class="p-calendar">
<tr>
<th>日</th>
<th>月</th>
<th>火</th>
<th>水</th>
<th>木</th>
<th>金</th>
<th>土</th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
</tr>
<tr>
<td>9</td>
<td>10</td>
<td>11</td>
<td>12</td>
<td>13</td>
<td>14</td>
<td>15</td>
</tr>
<tr>
<td>16</td>
<td>17</td>
<td>18</td>
<td>19</td>
<td>20</td>
<td>21</td>
<td>22</td>
</tr>
<tr>
<td>23</td>
<td>24</td>
<td>25</td>
<td>26</td>
<td>27</td>
<td>28</td>
<td>29</td>
</tr>
<tr>
<td>30</td>
<td>31</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</section>
こちらもCSSをすでに指定しているので割愛します。以上をコーディングすると以下のようにカレンダーが表示されます。
続けて日付の中にその日の収入合計金額と支出合計金額を表示するコーディングを追加します。
また日付クリックで詳細モーダルを表示するようにしたいので、収入合計金額と支出合計金額をaタグで囲います。
<!--書き換え前-->
<td>1</td>
<!--書き換え後-->
<td>
1<br>
<a href="">
<span class="text-red">-¥1,000</span>
<span class="text-blue">¥100,000</span>
</a>
</td>
ここではサンプルとして1日の部分にコーディングしました。
こちらもCSSは設定済みです。
データがある日はこのように出力されるようにします。
静的コーディングが完成したのでいよいよPHPを使って出力をしていきます。
まずはデータを含まないノーマルなカレンダーをPHPで出力します。もちろんカレンダー上部の「<」「>」「今月」ボタンも動くようにします。
まずはカレンダー本体上部の「<」「>」「今月」ボタンから実装します。
以下を<section class=”p-section p-section__calendar”>の下に追記します。
<!--216行目付近-->
<?php
//パラメータ処理
if(isset($_GET['ym'])){
$ym = $_GET['ym'];
}else{
$ym = date('Y-m');
}
$base_date = strtotime($ym); //パラメータもしくは現在の年月のタイムスタンプ
$prev = date('Y-m', strtotime('-1 month', $base_date)); //前月取得
$next = date('Y-m', strtotime('+1 month', $base_date)); //次月取得
$calendar_title = date('Y年n月', $base_date); //カレンダータイトル
?>
まず何月のカレンダーを表示するかは「ym」パラメータで管理します。そしてその値を基準に前月や次月のリンクやタイトルを変数に格納します。
「$base_date」はパラメータもしくは現在の年月でYYYY-mmという形式で格納されている$ymですが、文字列として格納されているのでその値をタイムスタンプ形式に直した値を格納しています。
続いて「$prev」「$next」は前月または次月のリンクに用いる値を格納しています。
strtotime(‘-1 month’, $base_date)は先程定義したタイムスタンプ形式の$base_dateから1ヶ月前を計算しタイムスタンプ形式にしています。次月の計算も仕組みは前月計算と同様です。
そしてカレンダーのタイトルは「$base_date」を「〇〇〇〇年〇月」という形式にして格納しています。
上記を使ってまずはカレンダー本体上部をPHP化します。
<!--229行目付近-->
<p>
<a href="?ym=<?php echo $prev; ?>"><</a>
<?php echo $calendar_title; ?>
<a href="?ym=<?php echo $next; ?>">></a>
<a href="?ym=<?php echo date('Y-m'); ?>">今月</a>
</p>
上記のように実装すると「<」「>」「今月」ボタンが動くようになります。
続いて月操作の下、1ヶ月の収入合計、支出合計とそれを計算した合計金額を出力します。
1ヶ月の収入合計、支出合計とそれを計算した合計金額の部分を以下に書き換えます。
<!--236行目付近から-->
<div class="p-calendar__sum">
<?php
$sql = 'SELECT (SELECT SUM(amount) FROM records WHERE type=0 AND date LIKE ? AND user_id=?)AS spending_sum, (SELECT SUM(amount) FROM records WHERE type=1 AND date LIKE ? AND user_id=?)AS income_sum FROM records WHERE user_id=? LIMIT 1';
$stmt = $db->prepare($sql);
$ym_param = $ym . '%';
$stmt->bind_param('sisii', $ym_param, $user_id, $ym_param, $user_id, $user_id);
sql_check($stmt, $db);
$stmt->bind_result($month_spending_sum, $month_income_sum);
$stmt->fetch();
?>
<p>
支出合計<span class="pc_only">:</span><br class="sp_only">
<span class="text-red">-¥<?php echo number_format($month_spending_sum); ?></span>
</p>
<p>
収入合計<span class="pc_only">:</span><br class="sp_only">
<span class="text-blue">¥<?php echo number_format($month_income_sum); ?></span>
</p>
<p>
<?php
$month_sum = $month_income_sum - $month_spending_sum;
$abs_month_sum = abs($month_sum);
if ($month_sum < 0) {
$sign = '-';
$class = 'text-red';
} else {
$sign = '';
$class = 'text-blue';
}
?>
収支合計<span class="pc_only">:</span><br class="sp_only">
<span class="<?php echo $class; ?>">
<?php echo $sign . '¥' . number_format($abs_month_sum); ?>
</span>
</p>
<?php $stmt->close(); ?>
</div>
まずは収入合計と支出合計を抽出するSQLを$sqlに格納します。その後の流れはこれまでのSQL実行部分と同様です。
途中でdateのあいまい検索にセットする値を変数に格納しています。あいまい検索では「%」というワイルドカードを使用するので事前に変数と文字列連結をして変数に入れておきます。
収入合計と支出合計の取得ができたら、その値をnumber_format関数で出力します。
最後の合計金額は、まず収入合計から支出合計を引いた数($month_sum)を求めます。その後出力に使用する$month_sumを絶対値に変換した$abs_month_sumを求めます。
そしてテキストの色や符号を決めるため$month_sumを条件に用いて負の値のときと正の値のときで適当な値を$signと$classに格納します。
そしてspanのclassに$classを、金額部分に$signと「¥」と$abs_month_sumを文字列連結させて出力します。
続いてカレンダーの日付と曜日が月に合うように実装します。
今回はカレンダーの配列を作り、for文で出力します。
まずは曜日以外のtrタグtdタグをコメントアウト、または削除します。
そしてその部分にカレンダーのプログラムを記述します。
<?php
//表示中の月の日数を取得
$day_count = date('t', $base_date);
//曜日取得(日曜日なら0、月曜日なら1・・・土曜日なら6が入る)
$youbi = date('w', $base_date);
//カレンダー配列の初期化
$weeks = [];
$week = '';
//初週の空セルの作成($youbiに格納されている数だけ空のtdタグを$weekに追加)
$week .= str_repeat('<td></td>', $youbi);
//日毎のデータ抽出(1日から表示月の末尾まで繰り返す)
for ($day = 1; $day <= $day_count; $day++, $youbi++) {
//YYYY-mm-dd形式の文字列生成(セルの日付とリンクパラメータ、SQLのbind_paramに使用)
if ($day < 10) :
$date = $ym . '-' . '0' . $day;
else :
$date = $ym . '-' . $day;
endif;
//詳細表示のリンク生成
if (isset($_GET['ym'])) :
$detail_url = $_SERVER['REQUEST_URI'] . '&detail=' . $date;
else :
$detail_url = $_SERVER['REQUEST_URI'] . '?detail=' . $date;
endif;
//データ抽出
$sql = 'SELECT (SELECT SUM(amount) FROM records WHERE type=0 AND user_id=? AND date=?)AS spending_sum, (SELECT SUM(amount) FROM records WHERE type=1 AND user_id=? AND date=?)AS income_sum FROM records WHERE user_id=? AND date=? LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bind_param('isisis', $user_id, $date, $user_id, $date, $user_id, $date);
$stmt->execute();
$stmt->bind_result($spending_sum, $income_sum);
$stmt->fetch();
//セル内HTML変数格納
$cel_link = '<a href="' . $detail_url . '">';
$cel_spending = '<span class="text-red">-¥' . number_format($spending_sum) . '</span>';
$cel_income = '<span class="text-blue">¥' . number_format($income_sum) . '</span>';
$close_a = '</a>';
//日付セルの中身生成
if ($spending_sum > 0 && $income_sum > 0) :
//支出と収入の両方が存在するとき
$cel_content = $cel_link . $cel_spending . $cel_income . $close_a;
elseif ($spending_sum > 0 && ($income_sum == null || $income_sum == 0)) :
//支出のみ存在するとき
$cel_content = $cel_link . $cel_spending . $close_a;
elseif (($spending_sum == null || $spending_sum == 0) && $income_sum > 0) :
//収入のみ存在するとき
$cel_content = $cel_link . $cel_income . $close_a;
else :
//どちらも存在しないとき
$cel_content = '';
endif;
//$weekにセルを追加
$week .= '<td>' . $day . '<br>' . $cel_content . '</td>';
//抽出結果の初期化
$spending_sum = null;
$income_sum = null;
$stmt->close();
//週末、月末の処理
if ($youbi % 7 == 6 || $day == $day_count) :
$weeks[] = '<tr>' . $week . '</tr>';
$week = '';
endif;
}
// 出力
foreach ($weeks as $week) {
echo $week;
}
?>
ノーマルなカレンダーを作るプログラムの基礎の部分は冒頭で紹介した記事を参考にしています。
ここではfor文内を少し解説します。
//YYYY-mm-dd形式の文字列生成(セルの日付とリンクパラメータ、SQLのbind_paramに使用)
if ($day < 10) :
$date = $ym . '-' . '0' . $day;
else :
$date = $ym . '-' . $day;
endif;
まずはセルの日付とリンクパラメータ、SQLのbind_paramに使用する「YYYY-mm-dd」形式の値をセットします。$ymには「YYYY-mm」の形式で値が格納されているので、日を表す「-dd」の部分を付け加えた値を文字列連結で生成します。
その際に、一桁のときに「0」を頭につけたいので、if文で分岐させています。
//詳細表示のリンク生成
if (isset($_GET['ym'])) :
$detail_url = $_SERVER['REQUEST_URI'] . '&detail=' . $date;
else :
$detail_url = $_SERVER['REQUEST_URI'] . '?detail=' . $date;
endif;
続いてカレンダーのセルをクリックして詳細表示をするリンクを生成します。
詳細表示のリンクには「detail」パラメータに「YYYY-mm-dd」形式で格納している$dateをセットします。
カレンダーの表示する月もパラメータで管理しているので、そのymパラメータがセットされているかいないかで条件分岐しています。
詳細表示のリンク生成の下にSQLのプログラムがありますが、プログラムの流れはこれまでと同様なので割愛します。ここでは支出合計と収入合計を抽出しています。
//セル内HTML変数格納
$cel_link = '<a href="' . $detail_url . '">';
$cel_spending = '<span class="text-red">-¥' . number_format($spending_sum) . '</span>';
$cel_income = '<span class="text-blue">¥' . number_format($income_sum) . '</span>';
$close_a = '</a>';
//日付セルの中身生成
if ($spending_sum > 0 && $income_sum > 0) : //支出と収入の両方が存在するとき
$cel_content = $cel_link . $cel_spending . $cel_income . $close_a;
elseif ($spending_sum > 0 && ($income_sum == null || $income_sum == 0)) : //支出のみ存在するとき
$cel_content = $cel_link . $cel_spending . $close_a;
elseif (($spending_sum == null || $spending_sum == 0) && $income_sum > 0) : //収入のみ存在するとき
$cel_content = $cel_link . $cel_income . $close_a;
else : //どちらも存在しないとき
$cel_content = '';
endif;
抽出ができたら、その値によって日付セルの中身を決める変数($cel_contet)を定義します。
$cel_contentに文字列連結で入れていくため、事前に変数にHTMLを格納しておきます。
場合分けは「収支両方ある時」「支出のみのとき」「収入のみの時」「どちらもない時」の4パターンです。場合によってaタグやspanタグを入れている変数をつなげてセル内の要素を生成していきます。
//$weekにセルを追加
if (date('w', strtotime($date)) === '0') :
$week .= '<td class="sunday">' . $day . '<br>' . $cel_content . '</td>';
elseif (date('w', strtotime($date)) === '6') :
$week .= '<td class="saturday">' . $day . '<br>' . $cel_content . '</td>';
else :
$week .= '<td>' . $day . '<br>' . $cel_content . '</td=>';
endif;
//抽出結果の初期化
$spending_sum = null;
$income_sum = null;
$stmt->close();
$cel_contentへの格納が完了したら、$weekにtdタグや日付を入れている$dayなどと連結して追加します。
この際、if文で生成した日が土曜日と日曜日の場合にはクラス名を付与した状態で追加されるようにしました。(CSSで文字色を指定しているため)
1日分のセルが完成したら、SQLで取得した値をリセットします。
//週末、月末の処理
if ($youbi % 7 == 6 || $day == $day_count) :
$weeks[] = '<tr>' . $week . '</tr>';
$week = '';
endif;
}
// 出力
foreach ($weeks as $week) {
echo $week;
}
最後に週末(土曜日)や月末の場合の処理を記述します。
上記の場合には、生成した日付セルをまとめてtrタグで囲い配列に追加する処理が必要になります。
まず1つ目の「$youbi % 7 == 6」は土曜日の条件です。for文の上で月初日の曜日を「$youbi」に格納しています。そして$youbiをfor文内で毎回プラス1しているので、もし月初日が土曜日なら6から条件に一致する間プラス1されます。(for文内でecho $youbiとすると分かりやすいです。)
もし月初日が土曜日なら、6(土)7(日)8(月)9(火)10(水)11(木)12(金)13(土)…と続きます。すると土曜日は6、13、21、28と7の倍数の1つ前になります。7の1つ前の数=7で割るとあまりが6になる数なのでプログラムのような条件になります。
2つ目の条件式は月末の条件です。$day_countで表示している月の日数を取得しているのでその値と回し番号の$dayを比較して一致するときが月末になります。
以上の条件に当てはまるとき生成した日付セルをまとめてtrタグで囲い配列に追加し、$weekを初期化します。
これでfor文内の処理は完了です。この処理が日数分繰り返されます。
for文の処理が終わったらforeachで配列を1つ1つ取り出しながら出力します。
すると以下のようにカレンダーと収支金額が出力されるようになります。
カレンダーの出力は完了しました。ここでスマホのときに、次月・今月・前月ボタンをクリックすると画面上部に戻ってしまうのでアンカーリンクをつけて、カレンダーの要素が表示されるようにします。
まず各aタグにidとonclick属性を追加します。
<!--229行目付近から-->
<p>
<a id="js-prevMonth" href="?ym=<?php echo $prev; ?>" onclick="onClickMonth('js-prevMonth');"><</a>
<?php echo $calendar_title; ?>
<a id="js-nextMonth" href="?ym=<?php echo $next; ?>" onclick="onClickMonth('js-nextMonth');">></a>
<a id="js-nowMonth" href="?ym=<?php echo date('Y-m'); ?>" onclick="onClickMonth('js-nowMonth');">今月</a>
</p>
続いて関数を作成します。
const onClickMonth = (target) => {
const windowWidth = window.outerWidth;
const windowSp = 767;
if (windowWidth <= windowSp) {
const targetElement = document.getElementById(target);
const targetLink = targetElement.getAttribute('href');
const newHref = targetLink + '#calendar';
targetElement.setAttribute('href', newHref);
}
}
まずリンクがクリックされたら、ウィンドウの幅を取得しwindowWidthに格納します。そしてこの処理はスマホサイズ以下のときに行いたいので、windowSpに画面幅を格納します。
そして条件文に「画面幅が指定したwindowSpより小さいとき」と置きます。そしてaタグやそのhref属性を取得し、アンカーリンクの「#calendar」を追加します。
そして前回収支データのページネーションを作成した際に、以下のようにリンクを作成しましたが、このままだとデータ一覧で2ページ目以降を表示している状態でカレンダーのリンクを押下すると、カレンダーは該当付きの表示に切り替わりますが、データ一覧が1ページ目に戻ってしまいます。
逆にカレンダーで当月以外を表示した状態でページネーションをクリックした場合は、カレンダーが当月に戻ってしまいます。
そこで以下のように書き換えます。
<!--書き換え前 669行目付近から-->
<?php for ($i = 1; $i <= $pages; $i++) : ?>
<?php if ($i == $page_id) : ?>
<span><?php echo $i; ?></span>
<?php else : ?>
<a href="./index.php?page_id=<?php echo $i; ?>#data-table"><?php echo $i; ?></a>
<?php endif; ?>
<?php endfor; ?>
<!--書き換え後-->
<?php for ($i = 1; $i <= $pages; $i++) : ?>
<?php if ($i == $page_id) : ?>
<span><?php echo $i; ?></span>
<?php elseif ($i != $page_id && !isset($_GET['ym'])) : ?>
<a href="./index.php?page_id=<?php echo $i; ?>#data-table"><?php echo $i; ?></a>
<?php else : ?>
<a href="./index.php?ym=<?php echo $ym; ?>&page_id=<?php echo $i; ?>#data-table"><?php echo $i; ?></a>
<?php endif; ?>
<?php endfor; ?>
aタグを出力するときに条件分岐を発生させ、ymパラメータがセットされていないときはこれまでのリンクを出力し、ymパラメータがセットされているときはymパラメータを含めたリンクを出力するようにしました。
スマホ版のページネーションも同じように書き換えます。
<!--書き換え前 785行目付近から-->
<?php if ($page_id > 1) : ?>
<a class="prev" href="./index.php?page_id=<?php echo ($page_id - 1); ?>#data-table_sp">前へ</a>
<?php endif; ?>
<?php if ($page_id < $pages) : ?>
<a class="next" href="./index.php?page_id=<?php echo ($page_id + 1); ?>#data-table_sp">次へ</a>
<?php endif; ?>
<!--書き換え後-->
<?php if ($page_id > 1 && isset($_GET['ym'])) : ?>
<a class="prev" href="./index.php?ym=<?php echo $ym; ?>&page_id=<?php echo ($page_id - 1); ?>#data-table_sp">前へ</a>
<?php elseif ($page_id > 1 && !isset($_GET['ym'])) : ?>
<a class="prev" href="./index.php?page_id=<?php echo ($page_id - 1); ?>#data-table_sp">前へ</a>
<?php endif; ?>
<?php if ($page_id < $pages && isset($_GET['ym'])) : ?>
<a class="next" href="./index.php?ym=<?php echo $ym; ?>&page_id=<?php echo ($page_id + 1); ?>#data-table_sp">次へ</a>
<?php elseif ($page_id < $pages && !isset($_GET['ym'])) : ?>
<a class="next" href="./index.php?page_id=<?php echo ($page_id + 1); ?>#data-table_sp">次へ</a>
<?php endif; ?>
以上でまずはカレンダーを今月以外でページ送りを操作しても、表示中の月カレンダー表示かつ送ったページのデータ一覧が表示されるようになりました。
続いて2ページ名工を表示した状態でカレンダーを操作したときに、1ページ目に戻らないように修正します。
まずは終始データを抽出するSQLを格納している「$sql_dataoutput」の上に書いていた以下のプログラムを、カレンダーのタイトルを格納している「$calendar_title」の下に移動させます。
//移動前
$max_view = 10;
if (!isset($_GET['page_id'])) :
$page_id = 1;
$page_param = $page_id - 1;
else :
$page_id = $_GET['page_id'];
$page_param = ($page_id - 1) * $max_view;
endif;
$sql_dataoutput= 'SELECT ・・・省略・・・';
//移動後
$calendar_title = date('Y年n月', $base_date); //既存のプログラム
$max_view = 10;
if (!isset($_GET['page_id'])) :
$page_id = 1;
$page_param = $page_id - 1;
else :
$page_id = $_GET['page_id'];
$page_param = ($page_id - 1) * $max_view;
endif;
そして「<」「>」「今月」ボタンのリンクに入れる値を変数に格納します。
if (!isset($_GET['page_id'])) :
$page_id = 1;
$page_param = $page_id - 1;
$calendar_link_prev = '?ym=' . $prev; //追加
$calendar_link_next = '?ym=' . $next; //追加
$calendar_link_now = '?ym=' . date('Y-m'); //追加
else :
$page_id = $_GET['page_id'];
$page_param = ($page_id - 1) * $max_view;
$calendar_link_prev = '?ym=' . $prev . '&page_id=' . $page_id; //追加
$calendar_link_next = '?ym=' . $next . '&page_id=' . $page_id; //追加
$calendar_link_now = '?ym=' . date('Y-m') . '&page_id=' . $page_id; //追加
endif;
条件上のページ送りがセットされていないとき(1ページ目が表示されているとき)は、ymパラメータのみのリンクをセットします。
条件下のページ送りがあるとき(2ページ目以降が表示されているとき)はymパラメータの後ろにpage_idパラメータを連結させたリンクを格納しています。
それぞれのリンクがセットできたので、それぞれのhref属性を修正します。
<!--244行目付近から-->
<p>
<a id="js-prevMonth" href="<?php echo $calendar_link_prev; ?>" onclick="onClickMonth('js-prevMonth');"><</a>
<?php echo $calendar_title; ?>
<a id="js-nextMonth" href="<?php echo $calendar_link_next; ?>" onclick="onClickMonth('js-nextMonth');">></a>
<a id="js-nowMonth" href="<?php echo $calendar_link_now; ?>" onclick="onClickMonth('js-nowMonth');">今月</a>
</p>
以上で2ページ目以降が表示されているときに、カレンダーの月操作をしても、1ページ目に戻らず操作前に表示していたページが保持されるようになりました。
次は収支がある日付セルをクリックすると詳細モーダルを表示する機能を実装します。
日付セルクリックで詳細表示
カレンダーを実装した際に、収支がある日付のセルにaタグを出力しました。そのhrefに「detail=YYYY-mm-dd」というパラメータを記述しています。
このdetailパラメータが存在するときにその日の詳細を表示するモーダルを出します。
以下を操作完了モーダルsectionの下に記述します。
<!-- カレンダー日別収支詳細表示 76行目付近に以下を追加-->
<?php if (isset($_GET['detail'])) : ?>
<section class="p-section p-section__full-screen" id="detailModalBox">
<div class="p-detail-box">
<!--タイトル出力-->
<p class="p-detail-box__title">
<?php
$param_date = $_GET['detail'];
$title_date = date('Y年n月j日', strtotime($param_date));
echo $title_date;
?>
</p>
<!--詳細データ抽出-->
<?php
$sql = 'SELECT records.id, records.date, records.title, records.amount, spending_category.name, income_category.name, records.type, payment_method.name, creditcard.name, qr.name, records.memo
FROM records
LEFT JOIN spending_category ON records.spending_category = spending_category.id
LEFT JOIN income_category ON records.income_category = income_category.id
LEFT JOIN payment_method ON records.payment_method = payment_method.id
LEFT JOIN creditcard ON records.credit = creditcard.id
LEFT JOIN qr ON records.qr = qr.id
WHERE records.date=? AND records.user_id = ?';
$stmt = $db->prepare($sql);
$stmt->bind_param('si', $param_date, $user_id);
sql_check($stmt, $db);
$stmt->bind_result($id, $date, $title, $amount, $spending_cat, $income_cat, $type, $payment_method, $credit, $qr, $memo);
while ($stmt->fetch()) :
?>
<div class="p-detail-box__content">
<div class="outline">
<p>
<?php echo $title; ?>
<span>
<?php
if ($type === 0 && $spending_cat !== null) {
echo '(' . $spending_cat . ')';
} elseif ($type === 1 && $income_cat !== null) {
echo '(' . $income_cat . ')';
} else {
echo '(不明)';
}
?>
</span>
</p>
<p class="<?php echo $type === 0 ? 'text-red' : 'text-blue'; ?>"><?php echo $type === 0 ? '-¥' . number_format($amount) : '+¥' . number_format($amount); ?></p>
</div>
<?php if ($type === 0) : ?>
<p class="detail">
<?php
echo ($payment_method != '') ? $payment_method : '不明';
if ($credit !== null || $qr !== null) {
echo '/' . $credit . $qr;
}
?>
</p>
<?php endif; ?>
<div class="p-detail-box__editbutton">
<form action="./record-edit.php" method="POST">
<input type="hidden" name="record_id" value="<?php echo h($id); ?>">
<input type="submit" class='c-button c-button--bg-green edit fas' id="" value="編集">
</form>
<a class='c-button c-button--bg-red delete' id="delete<?php echo h($id); ?>" href='./delete.php?id=<?php echo h($id); ?>&from=index' onclick="deleteConfirm('<?php echo h($title); ?>','delete<?php echo h($id); ?>');"> 削除 </a>
</div>
</div>
<?php endwhile; ?>
<?php
if (isset($_GET['ym'])) :
$ym = $_GET['ym'];
endif;
if (isset($_GET['page_id'])) :
$page_id = $_GET['page_id'];
endif;
if (isset($_GET['ym']) && isset($_GET['page_id'])) :
$detail_ok_link = './index.php?ym=' . $ym . '&page_id=' . $page_id . '#calendar';
elseif (isset($_GET['ym'])) :
$detail_ok_link = './index.php?ym=' . $ym . '#calendar';
elseif (isset($_GET['page_id'])) :
$detail_ok_link = './index.php?page_id=' . $page_id . '#calendar';
else :
$detail_ok_link = './index.php';
endif;
?>
<a class="c-button c-button--bg-blue" href="<?php echo $detail_ok_link; ?>">OK</a>
</div>
</section>
<?php endif; ?>
<!-- カレンダー日別収支詳細表示 -->
少し長いですが、大まかな出力処理はスマホの収支一覧と同じです。
<?php if (isset($_GET['detail'])) : ?>
<section class="p-section p-section__full-screen" id="detailModalBox">
<div class="p-detail-box">
まずはsection全体をPHPのif文で囲い、detailパラメータがセットされているときという条件を置きます。
<!--タイトル出力-->
<p class="p-detail-box__title">
<?php
$param_date = $_GET['detail'];
$title_date = date('Y年n月j日', strtotime($param_date));
echo $title_date;
?>
</p>
「〇〇〇〇年〇月〇日」という形式のタイトルを出力する部分です。
まずはdetailパラメータにセットしてある値を$param_date変数に格納します。この変数はこの下の日付フォーマットとSQLのbind_paramで使用します。
そしてdate関数で〇〇〇〇年〇月〇日という形式に整形した値を$title_dateに格納し、これを出力しています。
<?php
$sql = 'SELECT records.id, records.date, records.title, records.amount, spending_category.name, income_category.name, records.type, payment_method.name, creditcard.name, qr.name, records.memo
FROM records
LEFT JOIN spending_category ON records.spending_category = spending_category.id
LEFT JOIN income_category ON records.income_category = income_category.id
LEFT JOIN payment_method ON records.payment_method = payment_method.id
LEFT JOIN creditcard ON records.credit = creditcard.id
LEFT JOIN qr ON records.qr = qr.id
WHERE records.date=? AND records.user_id = ?';
$stmt = $db->prepare($sql);
$stmt->bind_param('si', $param_date, $user_id);
sql_check($stmt, $db);
$stmt->bind_result($id, $date, $title, $amount, $spending_cat, $income_cat, $type, $payment_method, $credit, $qr, $memo);
while ($stmt->fetch()) :
?>
続いて詳細を抽出するためSQLを実行します。ここはこれまでのSQL実行と流れは同様なので割愛します。
<div class="p-detail-box__content <?php echo $memo !== '' ? 'hasmemo' : ''; ?>">
<div class="outline">
<p>
<?php echo $title; ?>
<span>
<?php
if ($type === 0 && $spending_cat !== null) {
echo '(' . $spending_cat . ')';
} elseif ($type === 1 && $income_cat !== null) {
echo '(' . $income_cat . ')';
} else {
echo '(不明)';
}
?>
</span>
<i class="fa-regular fa-message" onclick="showMemo('<?php echo h($memo); ?>');"></i>
</p>
<p class="<?php echo $type === 0 ? 'text-red' : 'text-blue'; ?>">
<?php echo $type === 0 ? '-¥' . number_format($amount) : '+¥' . number_format($amount); ?>
</p>
</div>
上記はタイトルやカテゴリー、メモアイコンと金額の出力部分です。
プログラムはスマホのデータ一覧出力のときと同様です。
<?php if ($type === 0) : ?>
<p class="detail">
<?php
echo ($payment_method > 0) ? $payment_method : '不明';
if ($credit !== null || $qr !== null) {
echo '/' . $credit . $qr;
}
?>
</p>
<?php endif; ?>
上記は収入データの際に、支払い方法や種類を出力する部分です。「選択しない」で登録されている場合も考えて、0より大きいときは抽出した値を出力し、0のときは不明と出力します。
クレジットカードとスマホ決済の出力は三項演算子にせずそのまま出力します。
<div class="p-detail-box__editbutton">
<form action="./record-edit.php" method="POST">
<input type="hidden" name="record_id" value="<?php echo h($id); ?>">
<input type="submit" class='c-button c-button--bg-green edit fas' id="" value="編集">
</form>
<a class='c-button c-button--bg-red delete' id="delete<?php echo h($id); ?>Calendar" href='./delete.php?id=<?php echo h($id); ?>&from=index' onclick="deleteConfirm('<?php echo h($title); ?>','delete<?php echo h($id); ?>Calendar');"> 削除 </a>
</div>
上記は編集や削除ボタンを出力している部分です。formタグ内はスマホ版のデータ一覧で記述したプログラムと同様です。
</div>
<?php endwhile; ?>
<?php
if (isset($_GET['ym'])) :
$ym = $_GET['ym'];
endif;
if (isset($_GET['page_id'])) :
$page_id = $_GET['page_id'];
endif;
if (isset($_GET['ym']) && isset($_GET['page_id'])) :
$detail_ok_link = './index.php?ym=' . $ym . '&page_id=' . $page_id . '#calendar';
elseif (isset($_GET['ym'])) :
$detail_ok_link = './index.php?ym=' . $ym . '#calendar';
elseif (isset($_GET['page_id'])) :
$detail_ok_link = './index.php?page_id=' . $page_id . '#calendar';
else :
$detail_ok_link = './index.php';
endif;
?>
<a class="c-button c-button--bg-blue" href="<?php echo $detail_ok_link; ?>">OK</a>
</div>
</section>
<?php endif; ?>
if文末尾は「OK」ボタンを出力する部分です。
このボタンを押下することで、detailパラメータが削除され元のページに戻ります。
その前のPHPのプログラムはOKボタンのaタグのhref属性に入れるリンクを、パラメータの条件によって適当な文字列を格納するプログラムです。
ここでモーダルが出ているときにスクロールができてしまうので、モーダルが表示されているときは下のページはスクロールできないようにします。
プログラムは操作完了や更新などのモーダルのときと同様です。
//カレンダー詳細表示section要素取得
const detailModalBox = document.getElementById('detailModalBox');
if (detailModalBox != null) {
body.classList.add("openedModal");
} else {
body.classList.remove("openedModal");
}
以上で詳細表示の機能は完了です。
最後にデータ一覧のページ操作をした状態で、詳細表示をすると2つ目のパラメータも「?」で繋がり詳細が表示されないので修正します。
//詳細表示リンク生成 417行目付近
if (isset($_GET['ym']) || isset($_GET['page_id'])) : //条件追加
$detail_url = $_SERVER['REQUEST_URI'] . '&detail=' . $date;
詳細表示リンクを生成する条件にpage_idパラメータがセットされているときという条件を付け加えることで正しくパラメータがつながるようになります。
最後に
今回はカレンダーを表示させ、収支がある日付をクリックするとその日の詳細が表示されるような機能を追加しました。
次回はスマホUIの修正を行います。
最後までお読みいただきありがとうございました。
コメント