概要
某大手予約サイトのような、予約時の日時選択画面を作成しました。横軸に当日から1週間の日付、縦軸に30分間隔で営業時間帯の時刻表示がされます。
DBから取得した情報をもとに、予約可能な箇所には「◎」、すでに予約が入っていたり定休日で予約できない場合には「×」を表示しています。
下記サイトののカレンダー作成方法を参考に、アレンジ加えて作成しました。
(https://codeforfun.jp/php-calendar/)
実際の画面
コード
- PHP
date_reserve.php
<?php session_start(); ?>
<?php require('./dbconnect.php'); ?>
<?php
$youbiarray = [
'日', //0
'月', //1
'火', //2
'水', //3
'木', //4
'金', //5
'土', //6
];
//POSTされた情報を整形して変数に格納
if(isset($_REQUEST['rdate'])){
$rdate = $_REQUEST['rdate'];
$date = date('Y年n月j日',strtotime($rdate)).'('.$youbiarray[date('w',strtotime($rdate))].')';
} else {
$rdate = null;
}
//今月の日付 フォーマット 例)2020-10-2
if (!isset($rdate)){
$today = date('Y-n-j');
} else {
$today = $rdate;
}
$dttoday = new DateTime($today);
$dttoday2 = new DateTime($today);
//前週・次週の月日を取得
//1週間前
$sprev = $dttoday2->modify('-1 week');
$prev = $sprev->format('Y-n-j');
//1週間後(直前のmodifyで-1week しているので、+2weekする)
$snext = $dttoday2->modify('+2 week');
$next = $snext->format('Y-n-j');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section id="reserve">
<div class="reserve-section">
<?php
//時間選択
$sql=$db->prepare('SELECT r.res_date, r.comp_date FROM reserve r
WHERE r.res_date >= ?'); //DBから予約日時と席が空く時間を取得
$sql->bindparam(1,$today); //本日以降
$sql->execute();
$result = $sql->fetchALL();
$i=0;
if (isset($result)){
foreach ($result as $row){
$resdata[$i] = explode(" ",$row['res_date']);
$hoge = explode(" ",$row['comp_date']);
$resdata[$i][2] = $hoge[1];
$i++;
}
if(isset($resdata)){
$_SESSION['yoyaku'] = $resdata; //画面遷移時のため、SESSIONに保存
}
}
?>
<div class="reserve-box">
<div class="calender">
<?php
//1週間ことの情報を画面表示
if (!isset($rdate) || $rdate === date('Y-n-j')){ //本日以前は表示させない
echo '<h3><font color="white">< 前の週</font> 次の週<a href="?rdate='. $next .'"> <font color="white">></font></a></h3>';
} else {
echo '<h3><a href="?rdate='. $prev .'"><font color="white"><</font> </a>前の週 次の週<a href="?rdate=' .$next .'"> <font color="white">></font></a></h3>';
}
?>
<table class="table table-bordered">
<tr>
<th></th>
<?php
//1週間分の日付表示
for ($i=0; $i<=6; $i++){
if ($dttoday->format("w") === "0") {
echo '<th class="calender-date sunday">'.$dttoday->format("n月j日").'('.$youbiarray[$dttoday->format("w")].')</th>';
} else if ($dttoday->format("w") === "6"){
echo '<th class="calender-date saturday">'.$dttoday->format("n月j日").'('.$youbiarray[$dttoday->format("w")].')</th>';
} else {
echo '<th class="calender-date">'.$dttoday->format("n月j日").'('.$youbiarray[$dttoday->format("w")].')</th>';
}
$dttoday->modify("+1 day");
}
?>
</tr>
<!-- 各日付、時間帯ごとの予約状況表示 -->
<?php
//XX:30の時刻表示用変数
$thirty = false;
$i = 9;
while ($i<=18) { //18時まで表示
$dttoday = new DateTime($today);
echo '<tr>';
for ($n=0; $n<=7; $n++){ //7日分
if ($n===0){ //n===0の時は時刻表示
if ($thirty && $i === 18) { //18:00で表示を止めるための処理
$i++;
break;
} else if ($thirty) { //XX:30の時刻表示用変数
$reservetime = sprintf('%02d',$i) . ':30';
echo '<td>'.$reservetime.'</td>';
$thirty = false;
$i++;
} else { //XX:00の時刻表示用変数
$reservetime = sprintf('%02d',$i) . ':00';
echo '<td>'.$reservetime.'</td>';
$thirty = true;
}
} else { //n!==0の時はボタンを表示
$flag = true;
if (isset($_SESSION['yoyaku'])){
foreach ($_SESSION['yoyaku'] as $row){
if ($dttoday->format('Y-m-d') == $row[0]){
if ($reservetime >= substr($row[1],0,5) && $reservetime <= substr($row[2],0,5)){
$flag = false;
}
}
}
}
if ($dttoday->format("w") === "3"|| ((!$flag))) { //水曜時はボタンを非表示
echo '<td>×</td>';
} else { //ボタン表示してデータをPOST
echo '<td><form method="post" action="###">';
echo '<input type="hidden" name="rtime" value="'.$reservetime.'">';
echo '<button type="submit" name="rdate" value="'.$dttoday->format('Y-m-j').'">◎</button>';
echo '</form></td>';
}
$dttoday->modify('+1 day');
}
}
echo '</tr>';
}
?>
</table>
</div>
</div>
</div>
</section>
<footer></footer>
</body>
</html>
1行目
初回表示時は$today
に本日の日付をいれ、1週間分の日付表示。
1週間前、1週間後の月日を取得し、「前の週」「次の週」をクリック時には該当のデータを$today
にいれ、表示する日付を変更。
2行目以降
1列目には時刻を表示。
時刻の分表示は 30 と 00 を$thirty
で管理し1行表示ごとに切替。
2~8行目にはボタンを配置。
ボタンひとつひとつに、該当する日付と時刻がPOSTされるようになっています。
DBからdatetime型の予約開始時間と予約終了時間を取得して、その範囲内にあれぱボタンではなく「×」が表示されます。
- CSS
style.css
:root {
--bg: #0d0d0d;
--text: #eee;
--card-bg: rgba(255, 255, 255, 0.05);
--accent: #d1bfa3;
--shadow: rgba(0, 0, 0, 0.5);
--radius: 16px;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Noto Sans JP', sans-serif;
background-color: var(--bg);
color: var(--text);
line-height: 1.7;
}
section {
padding: 100px 20px;
max-width: 1200px;
margin: 0 auto;
}
/* --- 予約-メニュー選択 --- */
.reserve-box h3 {
font-family: 'Playfair Display', serif;
font-size: 2rem;
margin-bottom: 30px;
color: var(--accent);
}
.reserve-box button {
font-family: 'Playfair Display', serif;
font-size: 2rem;
width: 120px;
border-radius: 10px 10px 10px 10px;
color:#000;
background-color: var(--accent);
align-items: center;
}
/* --カレンダー-- */
.calender a {
text-decoration: none;
}
.calender table {
color:#000;
background-color: #fff;
border-width: 0.5rem;
table-layout: fixed;
width: 90%;
margin:auto;
}
.calender th {
height: 30px;
text-align: center;
}
.calender td {
height: auto;
text-align: center;
}
.calender button {
height: auto;
width: 100%;
border: transparent;
background: transparent;
}
.calender-date {
width:12%;
}
.sunday {
color:red !important;
}
.saturday {
color:blue!important;
}