8-2:予約機能追加

2019/05/30

概要

カレンダーが作成できたので、ユーザーがカレンダーから予約申し込みができるように機能を追加していきます。
カレンダーから日付をクリックして予約申し込み画面に遷移し、予約申し込みができる機能を実装します。
※今回は、フォームの確認画面を作成しません。

フォルダ階層

完成イメージ

カレンダー

予約フォーム

予約完了

全体の手順

手順は以下のとおりです

  1. データベースにテーブルの追加
  2. 予約申し込み画面作成
  3. データベースに貯める
  4. 過去日付の予約を受け付けないように実装

データベースにテーブルの追加

予約申し込み内容をデータベースにためられるようにします。
今回は予約日・予約者名・電話番号・メールアドレス・来訪人数を保存します。
予約テーブルなのでreservationsという名前でテーブルを作成します。

項目 内容 オプション オプション
id ID int primary key auto_increment
reserve_date 予約日時 date
name 氏名 varchar(64)
tel 電話番号 varchar(13)
email email varchar(256)
number 予約人数 int
created_at 作成日時 datetime
updated_at 更新日時 dateimte

console

mysql> use corporate_db;
Database changed
mysql>create table reservations(id int primary key auto_increment,reserve_date date,name varchar(64),tel varchar(13),email varchar(256),number int, created_at datetime, updated_at datetime);
Query OK, 0 rows affected (0.06 sec)

Query OKと表示されればOKです。

予約申し込み画面作成

予約申し込み画面へのリンク追加

calendar.phpに予約申し込み画面へのリンクを追加します。
予約申し込み画面はreserve.phpを作成する予定なのでリンク先はreserve.phpです。
reserve.phpには、予約日をGETパラメータで送ります。
$yというパラメータに予約したい日の年、$mに予約したい日の月、$dに予約したい日の日を入れて送ります。
calendar.php

    if ($comp->eq($comp_now)) {
-           $calendar .= '<td class="day" style="background-color:#008b8b;">'.$dt->day.'</td>';
+           $calendar .= '<td class="day" style="background-color:#008b8b;"><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
        }else{
        // $calendar .= '<td class="day">'.$dt->day.'</td>';
            switch ($dt->format('N')) {
                case 6:
-                  $calendar .= '<td class="day" style="background-color:#b0e0e6">'.$dt->day.'</td>';
+                  $calendar .= '<td class="day" style="background-color:#b0e0e6"><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
                    break;
                case 7:
-                  $calendar .= '<td class="day" style="background-color:#f08080">'.$dt->day.'</td>';
+                  $calendar .= '<td class="day" style="background-color:#f08080"><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
                    break;
                default:
-                  $calendar .= '<td class="day" >'.$dt->day.'</td>';
+                  $calendar .= '<td class="day" ><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
                    break;
            }
    }

日付にリンクが付きました。

日付をクリックすると、まだreserve.phpを作成できていないのでNot Foundになりますが、URLを確認すると年月日が送られているのが確認できます。

reserve.phpを作成する

calendar.phpと同じ階層にreserve.phpファイルを作成します。

パラメータ受け取り

年月日を$_GETで受け取ります。
reserve.php

<?php

    $y = isset($_GET['y'])? htmlspecialchars($_GET['y'], ENT_QUOTES, 'utf-8') : '';
    $m = isset($_GET['m'])? htmlspecialchars($_GET['m'], ENT_QUOTES, 'utf-8') : '';   
    $d = isset($_GET['d'])? htmlspecialchars($_GET['d'], ENT_QUOTES, 'utf-8') : '';   
?>

申し込みフォーム作成

calendar.phpのhtmlをコピーしてreserve.phpを作成します。
<?php echo renderCalendar($dt); ?>を削除します。
titleとwrapper-titleのh3を「RESERVATION」に変更します。pタグは「ご予約」と追加しました。
パンくずリストはTOP>無料ご相談会予約>ご予約となるようにします。
reserve.php

<!DOCTYPE html>
<html>

<head>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-13xxxxxxxxx"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'UA-13xxxxxxxxx');
    </script>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>RESERVATION|SQUARE, inc.</title>

    <link rel="icon" href="favicon.ico">

    <!-- css -->
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="responsive.css">

    <!-- icon -->
    <link href="https://use.fontawesome.com/releases/v5.0.6/css/all.css" rel="stylesheet">
</head>

<body>
    <header>
        <div class="container">
            <div class="header-logo">
                <h1><a href="index.php"><img src="img/square_logo.png" id="logo"></a></h1>
            </div>

            <!-- ハンバーガーメニューボタン -->
            <div class="toggle">
                <div>
                    <span></span>
                    <span></span>
                    <span></span>
                </div>
            </div>
            <div class="cart">
                <a href="cart.php"><i class="fas fa-shopping-cart"></i></a>
            </div>

            <nav class="sp-menu menu">
                <ul>
                    <li><a href="index.php#service">サービス</a></li>
                    <li><a href="shop.php">商品一覧</a></li>
                    <li><a href="index.php#news">お知らせ</a></li>
                    <li><a href="index.php#about">会社概要</a></li>
                    <li><a href="index.php#contact">お問合せ</a></li>
                    <li><a href="ブログのURL">ブログ</a></li>
                    <li><a href="calendar.php">無料ご相談会</a></li>
                    <?php if($user_login==true): ?>
                    <li><a href="logout.php">ログアウト</a></li>
                    <?php else: ?>
                    <li><a href="login.php">ログイン</a></li>
                    <?php endif; ?>
                </ul>
            </nav>

            <nav class="pc-menu menu-left menu">
                <ul>
                    <li><a href="index.php#service">サービス</a></li>
                    <li><a href="shop.php">商品一覧</a></li>
                    <li><a href="index.php#news">お知らせ</a></li>
                    <li><a href="index.php#about">会社概要</a></li>
                    <li><a href="index.php#contact">お問合せ</a></li>
                    <li><a href="ブログのURL">ブログ</a></li>
                    <li><a href="calendar.php">無料ご相談会</a></li>
                </ul>
            </nav>
            <nav class="pc-menu menu-right menu">
                <ul>
                    <li><a href="cart.php"><i class="fas fa-shopping-cart"></i></a></li>
                    <?php if($user_login==true): ?>
                    <li><a href="logout.php">ログアウト</a></li>
                    <?php else: ?>
                    <li><a href="login.php">ログイン</a></li>
                    <?php endif; ?>
                </ul>
            </nav>
        </div>
    </header>
    <main>
        <div class="breadcrumbs">
            <div class="container">
                <ul>
                    <li><a href="index.php">TOP</a></li>
                    <li><a href="calendar.php">無料ご相談会予約</a></li>
                    <li>ご予約</li>
                </ul>
            </div>
        </div>
        <div class="wrapper last-wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3>RESERVATION</h3>
                    <p>ご予約</p>
                </div>
            </div>
        </div>
    </main>
    <footer>
        <div class="container">
            <p>Copyright @ 2018 SQUARE, inc.</p>
        </div>
    </footer>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script>
        $(function () {
            // ハンバーガーメニューの動作
            $('.toggle').click(function () {
                $("header").toggleClass('open');
                $(".sp-menu").slideToggle(500);
            });
        });        
    </script>
</body>

</html>

また、メニューバーにログイン機能がついているのでphpでログイン機能の対応を記述しておきます。
reserve.php

    <?php

+       session_start();
+       $user_login = isset($_SESSION['user_login'])? $_SESSION['user_login']:false;

        $y = isset($_GET['y'])? htmlspecialchars($_GET['y'], ENT_QUOTES, 'utf-8') : '';
        $m = isset($_GET['m'])? htmlspecialchars($_GET['m'], ENT_QUOTES, 'utf-8') : '';
        $d = isset($_GET['d'])? htmlspecialchars($_GET['d'], ENT_QUOTES, 'utf-8') : '';

    ?>

フォームを作成します。
予約日は、calendar.phpから受け取った日付を表示し変更できないようにします。
reserve.php

        <div class="wrapper last-wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3>RESERVATION</h3>
                    <p>ご予約</p>
                </div>
+               <form class="reserve-form">
+                   <div class="form-group">
+                       <label for="reserveDate">予約日</label>
+                       <input type="text" class="form-control" id="reserveDate" value="<?php echo $y;?>年<?php echo $m; ?>月<?php echo $d; ?>日" disabled="disabled">
+                   </div>
+                   <div class="form-group">
+                       <label for="name">氏名 *</label>
+                       <input type="text" class="form-control" name="name" required>
+                   </div>
+                   <div class="form-group">
+                       <label for="tel">電話番号 *</label>
+                       <input type="text" class="form-control" name="tel" required>
+                   </div>
+                   <div class="form-group">
+                       <label for="email">メールアドレス *</label>
+                       <input type="text" class="form-control" name="email" required>
+                   </div>
+                   <div class="form-group">
+                       <label for="email">来訪人数 *</label>
+                       <input type="text" class="form-control" name="number" required>
+                   </div>
+                   <button type="submit" class="btn btn-submit">予約する</button>
+               </form>
            </div>
        </div>

申し込みを実行するファイルをreserved.phpという名前で作成する予定なので、formの送信先とmethodを追加します。
reserve.php

-   <form class="reserve-form">
+   <form class="reserve-form" method="POST" action="reserved.php">

また、予約日時は、$y,$m,$dを使って、hiddenでreserve_dateという名前で送ることにします。
reserve.php

    <div class="form-group">
        <label for="reserveDate">予約日</label>
        <input type="text" class="form-control" id="reserveDate" value="<?php echo $y;?>年<?php echo $m; ?>月<?php echo $d; ?>日" disabled="disabled">
+       <input type="hidden" name="reserve_date" value="<?php echo $y; ?>-<?php echo $m; ?>-<?php echo $d; ?>">
    </div>

calendar.phpから確認してみます。
クリックした日付が予約日に入ってフォームが表示されていればOKです。

データベースにためる

reserve.phpと同じ階層にreserved.phpを作成します。

パラメータ受け取り

reserved.php

<?php
    $reserve_date = isset($_POST['reserve_date'])? htmlspecialchars($_POST['reserve_date'], ENT_QUOTES, 'utf-8'):'';
    $name = isset($_POST['name'])? htmlspecialchars($_POST['name'], ENT_QUOTES, 'utf-8'):'';
    $email = isset($_POST['email'])? htmlspecialchars($_POST['email'], ENT_QUOTES, 'utf-8'):'';
    $tel = isset($_POST['tel'])? htmlspecialchars($_POST['tel'], ENT_QUOTES, 'utf-8'):'';
    $number = isset($_POST['number'])? htmlspecialchars($_POST['number'], ENT_QUOTES, 'utf-8'):'';

DBにためる

データベースに接続して、受け取ったデータをresevationsテーブルにinsertします。
reserved.php

    $reserve_date = isset($_POST['reserve_date'])? htmlspecialchars($_POST['reserve_date'], ENT_QUOTES, 'utf-8'):'';
    $name = isset($_POST['name'])? htmlspecialchars($_POST['name'], ENT_QUOTES, 'utf-8'):'';
    $email = isset($_POST['email'])? htmlspecialchars($_POST['email'], ENT_QUOTES, 'utf-8'):'';
    $tel = isset($_POST['tel'])? htmlspecialchars($_POST['tel'], ENT_QUOTES, 'utf-8'):'';
    $number = isset($_POST['number'])? htmlspecialchars($_POST['number'], ENT_QUOTES, 'utf-8'):'';

+   //DB接続
+   try{
+       $dbh = new PDO("mysql:host=localhost;dbname=corporate_db","root","root");
+   }catch(PDOException $e){
+       var_dump($e->getMessage());
+       exit;
+   }

+   $stmt = $dbh->prepare("INSERT INTO reservations(
+           reserve_date,
+           name,
+           tel,
+           email,
+           number,
+           created_at,
+           updated_at
+       )values(
+           :reserve_date,
+           :name,
+           :tel,
+           :email,
+           :number,
+           now(),
+           now()
+       )");

+   $stmt->bindParam(":reserve_date",$reserve_date);
+   $stmt->bindParam(":name",$name);
+   $stmt->bindParam(":tel",$tel);
+   $stmt->bindParam(":email",$email);
+   $stmt->bindParam(":number",$number);
+   $stmt->execute();
+   ?>

予約完了画面表示

phpの下にhtmlで予約完了画面を作成します。
reserve.phpのhtmlをコピーして、<form>〜</form>を削除します。
titleとwrapper-titleのh3を「ご予約完了」に変更します。pタグは削除します。
パンくずリストはTOP>無料ご相談会予約>ご予約完了となるように変更します。
reserved.php

?>
<!DOCTYPE html>
<html>

<head>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-13xxxxxxxxx"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'UA-13xxxxxxxxx');
    </script>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>ご予約完了|SQUARE, inc.</title>

    <link rel="icon" href="favicon.ico">

    <!-- css -->
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="responsive.css">

    <!-- icon -->
    <link href="https://use.fontawesome.com/releases/v5.0.6/css/all.css" rel="stylesheet">
</head>

<body>
    <header>
        <div class="container">
            <div class="header-logo">
                <h1><a href="index.php"><img src="img/square_logo.png" id="logo"></a></h1>
            </div>

            <!-- ハンバーガーメニューボタン -->
            <div class="toggle">
                <div>
                    <span></span>
                    <span></span>
                    <span></span>
                </div>
            </div>
            <div class="cart">
                <a href="cart.php"><i class="fas fa-shopping-cart"></i></a>
            </div>

            <nav class="sp-menu menu">
                <ul>
                    <li><a href="index.php#service">サービス</a></li>
                    <li><a href="shop.php">商品一覧</a></li>
                    <li><a href="index.php#news">お知らせ</a></li>
                    <li><a href="index.php#about">会社概要</a></li>
                    <li><a href="index.php#contact">お問合せ</a></li>
                    <li><a href="ブログのURL">ブログ</a></li>
                    <li><a href="calendar.php">無料ご相談会</a></li>
                    <?php if($user_login==true): ?>
                    <li><a href="logout.php">ログアウト</a></li>
                    <?php else: ?>
                    <li><a href="login.php">ログイン</a></li>
                    <?php endif; ?>
                </ul>
            </nav>

            <nav class="pc-menu menu-left menu">
                <ul>
                    <li><a href="index.php#service">サービス</a></li>
                    <li><a href="shop.php">商品一覧</a></li>
                    <li><a href="index.php#news">お知らせ</a></li>
                    <li><a href="index.php#about">会社概要</a></li>
                    <li><a href="index.php#contact">お問合せ</a></li>
                    <li><a href="ブログのURL">ブログ</a></li>
                    <li><a href="calendar.php">無料ご相談会</a></li>
                </ul>
            </nav>
            <nav class="pc-menu menu-right menu">
                <ul>
                    <li><a href="cart.php"><i class="fas fa-shopping-cart"></i></a></li>
                    <?php if($user_login==true): ?>
                    <li><a href="logout.php">ログアウト</a></li>
                    <?php else: ?>
                    <li><a href="login.php">ログイン</a></li>
                    <?php endif; ?>
                </ul>
            </nav>
        </div>
    </header>
    <main>
        <div class="breadcrumbs">
            <div class="container">
                <ul>
                    <li><a href="index.php">TOP</a></li>
                    <li><a href="calendar.php">無料ご相談会予約</a></li>
                    <li>ご予約完了</li>
                </ul>
            </div>
        </div>
        <div class="wrapper last-wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3>ご予約完了</h3>
                </div>

            </div>
        </div>
    </main>
    <footer>
        <div class="container">
            <p>Copyright @ 2018 SQUARE, inc.</p>
        </div>
    </footer>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script>
        $(function () {
            // ハンバーガーメニューの動作
            $('.toggle').click(function () {
                $("header").toggleClass('open');
                $(".sp-menu").slideToggle(500);
            });
        });        
    </script>
</body>

</html>

ログイン機能がついているのでphpにログイン機能用のパラメータの定義を追加します。
reserved.php

    <?php

+       session_start();
+       $user_login = isset($_SESSION['user_login'])? $_SESSION['user_login']:false;

htmlを編集します。
reserved.php

        <div class="wrapper last-wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3>ご予約完了</h3>
                </div>
+               <div class="wrapper-body">
+                   <div class="thanks">
+                       <h4>ご相談会のご予約いただきありがとうございます。</h4>
+                   </div>
+                   <button type="button" class="btn btn-gray" onclick="location.href='./index.php'">トップページに戻る</button>
+               </div>
            </div>
        </div>

ここまでできたらcalendar.phpから確認してみます。
うまく行けば予約完了画面が表示されます。

データベースに登録されているか確認します。
console

mysql> use corporate_db
Database changed
mysql>select * from reservations;
+----+--------------+------+------------+------------------------+--------+---------------------+---------------------+
| id | reserve_date | name | tel        | email                  | number | created_at          | updated_at          |
+----+--------------+------+------------+------------------------+--------+---------------------+---------------------+
|  1 | 2019-05-21   | test | 0312345678 | test@test.com |      1 | 2019-05-20 15:13:53 | 2019-05-20 15:13:53 |
+----+--------------+------+------------+------------------------+--------+---------------------+---------------------+
1 row in set (0.01 sec)

上記のように入力した内容が反映されていればOKです。

過去日付の予約を受け付けないように実装

これでほぼほぼ完成ですが、過去日付で予約ができてしまうのはよくありません。
カレンダーの過去日付はグレーアウトして、予約不可にしておきます。

今日より昔はグレーアウト

過去の日付は予約できないようにするため、今日より昔かどうかの分岐を付けます。
背景をグレー、文字を白に設定しました。
比較は$comp->lt($comp_now)を使っています。ltは比較対象より小さいかどうかを判断するときに使います(less than)。小さい場合trueとなります。
calendar.php

+   if($comp->lt($comp_now)){
+       $calendar .= '<td class="day" style="background-color:#ddd;">'.$dt->day.'</td>';
+   }else{
        //ループの日と今日を比較
        if ($comp->eq($comp_now)) {
            //同じなので緑色の背景にする
            $calendar .= '<td class="day" style="background-color:#008b8b;"><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
        } else {
            switch ($dt->format('N')) {
            case 6:
                $calendar .= '<td class="day" style="background-color:#b0e0e6"><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
                break;
            case 7:
                $calendar .= '<td class="day" style="background-color:#f08080"><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
                break;
            default:
                $calendar .= '<td class="day" ><a href="./reserve.php?y='.$dt->year.'&&m='.$dt->month.'&&d='.$dt->day.'">'.$dt->day.'</a></td>';
                break;
            }
        }
+   }

確認すると、過去はグレーアウトされ予約できなくなりました。

これで予約を受け付ける機能が完成しました。

コード

https://github.com/bluecode-io/web-basic/tree/basic8-2