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);