fullcallendarに記録できる予約システムを作ってみました。
ボタンをクリックして、ポップアップでHTMLフォームで予約して、フルカレンダーに表示されます。
予約のデータベースをつくる
My SQL
CREATE TABLE reservations (
id INT AUTO_INCREMENT PRIMARY KEY,
reservation_date DATE,
reservation_time TIME,
advisor_name VARCHAR(50)
);
ALTER TABLE reservations ADD COLUMN user_id INT;
ALTER TABLE reservations
ADD CONSTRAINT fk_user_id
FOREIGN KEY (user_id) REFERENCES user(id)
ON DELETE SET NULL
ON UPDATE CASCADE;
veiw.php
ポップアップの入力フォームとfullcalendarを作成します。
<head>
<link href='https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.css' rel='stylesheet' />
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.2/fullcalendar.min.js'></script>
</head>
<body>
<button id="popupBtn" style="margin-top:20px;">ポップアップボタン</button>
<div id="popup" class="popup">
<form action="" method="POST" class="form-container">
<p style="margin-top:30px;"><label>日時:</label><input type="date" name="date"></p>
<p><label>時間:</label><input type="time" name="time"></p>
<p><label>担当:</label>
<select name="advisor">
<option>田中</option>
<option>山田</option>
</select>
</p>
<input type="submit" value="予約" style="margin-bottom:20px;margin-top:20px;">
</form><!-- fullcalendar --><div id='calendar'></div>
<button id="closeBtn">閉じる</button>
</div>
</body>
css
<!--ポップアップ-->
<style>
.popup {
width: 100%; /* ポップアップの幅を画面の80%に */
height: 80%; /* ポップアップの高さを画面の80%に */
overflow: auto; /* 内容がオーバーフローした場合にスクロール可能に */
display: none;
justify-content: space-between;
align-items: flex-start;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
background-color: #fff;
z-index: 1000;
}
.form-container {
margin-right: 20px;
}
#popupBtn {
margin-top: 20px;
}
</style>
<!--フルカレンダー-->
<style>
#eventPopup {
display: none;//ポップアップをまず非表示にしておく
position: absolute;
z-index: 100;
top: 100px; /* 必要に応じて調整 */
left: 100px; /* 必要に応じて調整 */
background: white;
border: 1px solid #ccc;
padding: 10px;
}
</style>
javascript
ポップアップの表示と閉じる機能とフルカレンダーで表示
FullCalendarにイベントデータを供給するには、正しいJSON形式のデータを提供する必要があります。eventオプションはURLを受け取り、そのURLからイベントデータをフェッチしてカレンダーに描画します。
<script>
function togglePopup(popupId, displayStyle) {
document.getElementById(popupId).style.display = displayStyle;
}
document.getElementById('popupBtn').addEventListener('click', function() {
togglePopup('popup', 'flex');
});
document.getElementById('closeBtn').addEventListener('click', function() {
togglePopup('popup', 'none');
});
//フルカレンダー表示
$(document).ready(function() {
$('#calendar').fullCalendar({
// 他のオプション
initialView: 'dayGridMonth', // FullCalendarのオプションとしてここに移動
events: 'events.php', // PHPスクリプトのURLを指定
eventClick: function(calEvent, jsEvent, view) {
$('#eventDetails').text(calEvent.title + ' - ' + moment(calEvent.start).format('YYYY-MM-DD'));
$('#eventPopup').css({
display: 'block',
top: jsEvent.pageY, // イベントの位置に応じてポップアップを表示
left: jsEvent.pageX // イベントの位置に応じてポップアップを表示
});
}
});
// ポップアップを閉じる
$('#closePopup').on('click', function() {
$('#eventPopup').hide();
});
});
</script>
サーバーサイド
フォームからポストされた値をデータベースに保存します。
すでに予約されていたり、前日に予約されないかなどのバリデーションをかけています。
バリデーションをクリアしたら、データベースに保存できます。
popup.php
//予約システム機能
try {
if (isset($_POST['date']) && isset($_POST['time']) && isset($_POST['advisor'])) {
$date = $_POST['date'];
$time = $_POST['time'];
$advisor = $_POST['advisor'];
// 予約日が今日以降か確認
if ($date < date('Y-m-d')) {
echo "今日より前の日付には予約できません。";
exit;
}
// 予約日が祝日・休日か確認
/*$sql_holiday_check = "SELECT COUNT(*) FROM holidays WHERE holiday_date = :date";
$stmt_holiday_check = $dbh->prepare($sql_holiday_check);
$stmt_holiday_check->bindParam(':date', $date);
$stmt_holiday_check->execute();
if ($stmt_holiday_check->fetchColumn() > 0) {
echo "選択された日は祝日または休日のため予約できません。";
exit;
}*/
// 重複チェックのSQL文を準備 同じ人が同じ時間に同じ面談医を指定してないか
$sql_check = "SELECT COUNT(*) FROM reservations WHERE reservation_date = :date AND reservation_time = :time AND advisor_name = :advisor AND user_id = :user_id";
$stmt_check = $dbh->prepare($sql_check);
$stmt_check->bindParam(':date', $date);
$stmt_check->bindParam(':time', $time);
$stmt_check->bindParam(':advisor', $advisor);
$stmt_check->bindParam(':user_id', $user_id);
$stmt_check->execute();
if ($stmt_check->fetchColumn() > 0) {
// 重複がある場合、エラーメッセージを表示
echo "指定された日時には既に予約が存在します。別の日時またはアドバイザーを選択してください。";
} else {
// 重複がない場合、予約をデータベースに挿入
$sql_insert = "INSERT INTO reservations (reservation_date, reservation_time, advisor_name,user_id) VALUES (:date, :time, :advisor,:user_id)";
$stmt_insert = $dbh->prepare($sql_insert);
$stmt_insert->bindParam(':date', $date);
$stmt_insert->bindParam(':time', $time);
$stmt_insert->bindParam(':advisor', $advisor);
$stmt_insert->bindParam(':user_id', $user_id);
$stmt_insert->execute();
//echo "予約が完了しました。";
// リダイレクトする際にログイン維持のため、idをクエリストリングに含める
header('Location: popup.php?id=' . urlencode($user_id));
exit;
}
}
} catch (PDOException $e) {
echo "接続エラー: " . $e->getMessage();
}
events.phpという外部ファイルを作成します。
このPHPスクリプトはデータベースからイベントデータを取得し、FullCalendarが解釈できる形式のJSONを出力する。
FullCalendarにイベントデータを供給するには、正しいJSON形式のデータを提供する必要があります。javascriptのeventsオプションはURLを受け取り、そのURLからイベントデータをフェッチしてカレンダーに描画します。
PHPのコードでイベントデータを生成し、JSONとして出力する場合は、それをHTMLページ内に直接書くのではなく、外部のPHPファイルとして作成し、そのファイルのURLを eventsオプションに指定する必要があります。
サーバーサイドにJSON出力のコードを置いてもajaxは機能しないので、そのため別にファイルを作る必要がある。
events.php
<?php
session_start();
include "../config/com.php";
$dbh = db_open();
// ログインチェック
if(!isset($_SESSION['id'])){
// ログインページへリダイレクト
header('Location: login/index.php');
exit;
}
// データベースから予約データを取得
$stmt = $dbh->prepare("SELECT * FROM reservations WHERE reservation_date >= CURDATE()");
$stmt->execute();
$reservations = $stmt->fetchAll(PDO::FETCH_ASSOC);
// FullCalendarが必要とする形式に変換
$events = array_map(function ($reservation) {
// 12時間形式の時間を24時間形式に変換する
$time24h = date("H:i", strtotime($reservation['reservation_time']));
return [
'title' => $reservation['advisor_name'],
'start' => $reservation['reservation_date'] . 'T' . $time24h
// 'end' => ... 予約の終了時間があればここに追加
];
}, $reservations);
// JSONとして出力
header('Content-Type: application/json');
echo json_encode($events);