自分だけのクイズ作成 - Quipha公開中

【Laravel】FullCalendarでスケジュールのDB登録・表示【実践向け】

JavaScript
スポンサーリンク

はじめに

今回はFullCalendarを利用して、スケジュールを登録しカレンダーに表示する簡単なWebアプリケーションを作成してみます。
(スケジュールアプリの作成)

Laravelプロジェクトで作成し、スケジュールはデータベースに保存します。
そうすることにより、ブラウザを再度表示した際に、スケジュールを再表示することが出来ます。

Laravelの構築方法は以下をご覧ください。

使用するバージョン
  • Laravel Framework 8.69.0
  • FullCalendar 5.10.1

Quipha

個人開発ですがQuiphaというサービスを開発しました。
Webアプリケーションであり、LaravelとVue3(Composition APIも使用)で作成しました。
カレンダーの表示には、FullCalendarを利用しています。

良かったら、会員登録して動作を試してみて下さい。

FullCalendarとは

FullCalendarのインストール方法や、実装は以下の記事をご覧ください。
本記事は、以下の記事の続きになります。

スポンサーリンク

スケジュールの登録機能の実装

Laravelの登録処理の実装

前回の記事では、カレンダーにイベントを登録することが出来ました。
ただし、ブラウザの再描画を行うと、イベントはクリアされてしまいます。

ここからは実践でも使えるように、イベントをサーバーサイドで受信し、データベースに登録する処理をLaravelプロジェクトで実装していきます。

app.phpの修正

日付を操作しますので、Laravelのタイムゾーンの設定を変更してください。

'timezone' => 'Asia/Tokyo',

デフォルトでUTCがセットされており、変更しないと9時間ずれます。

テーブルの用意

以下のコマンドでmigrationファイルを用意します。
スケジュールを格納するテーブルになります。

php artisan make:migration create_schedules_table

migrationファイルが作成されましたので、以下のように修正しました。(ファイル名は現在時刻)

database\migrations\2021_11_18_144113_create_schedules_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateSchedulesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('schedules', function (Blueprint $table) {
            $table->id();
            $table->date('start_date')->comment('開始日');
            $table->date('end_date')->comment('終了日');
            $table->string('event_name')->comment('イベント名');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('schedules');
    }
}

マイグレーションを実行し、テーブルを作成します。

php artisan migrate

モデルの作成

先ほど作成したテーブルに対するモデルクラスを作成します。コマンドを実行します。

php artisan make:model Schedule

クラスファイルが作成されますが、特に変更の必要はありません。

コントローラの作成

以下のコマンドでコントローラを作成します。

php artisan make:controller ScheduleController

web.phpを修正し、ルーティングを追加します。

use App\Http\Controllers\ScheduleController;

// スケジュール登録処理
Route::post('/schedule-add', [ScheduleController::class, 'scheduleAdd'])->name('schedule-add');

スケジュールを登録するための処理を追加します。
リクエストのバリデーションと、DBへの登録処理を追加しました。

イベント名は32文字の文字数制限としました。

App\Http\Controllers\ScheduleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Schedule;

class ScheduleController extends Controller
{

    /**
     * スケジュールを登録
     *
     * @param  Request  $request
     */
    public function scheduleAdd(Request $request)
    {
        // バリデーション
        $request->validate([
            'start_date' => 'required|integer',
            'end_date' => 'required|integer',
            'event_name' => 'required|max:32',
        ]);

        // 登録処理
        $schedule = new Schedule;
        // 日付に変換。JavaScriptのタイムスタンプはミリ秒なので秒に変換
        $schedule->start_date = date('Y-m-d', $request->input('start_date') / 1000);
        $schedule->end_date = date('Y-m-d', $request->input('end_date') / 1000);
        $schedule->event_name = $request->input('event_name');
        $schedule->save();

        return;
    }
}

今回は取り敢えず、コントローラに処理を全て実装しています。
入力チェックなども考慮しておりますので、十分実用的に使えると思いますが、お好みでフォームリクエストの作成や、ビジネスロジックの切り出しなどを行うと良いでしょう。

app.jsを修正し、非同期通信を行うためのaxiosを追加します。

resources\js\app.js
// 追加
window.axios = require("axios");
require("./calendar");

calendar.jsに開き、イベントを送信する処理を追加します。

resources\js\calendar.js
let calendar = new Calendar(calendarEl, {
    plugins: [interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin],
    initialView: "dayGridMonth",
    headerToolbar: {
        left: "prev,next today",
        center: "title",
        right: "dayGridMonth,timeGridWeek,listWeek",
    },
    locale: "ja",

    // 日付をクリック、または範囲を選択したイベント
    selectable: true,
    select: function (info) {
        //alert("selected " + info.startStr + " to " + info.endStr);

        // 入力ダイアログ
        const eventName = prompt("イベントを入力してください");

        if (eventName) {
            // Laravelの登録処理の呼び出し
            axios
                .post("/schedule-add", {
                    start_date: info.start.valueOf(),
                    end_date: info.end.valueOf(),
                    event_name: eventName,
                })
                .then(() => {
                    // イベントの追加
                    calendar.addEvent({
                        title: eventName,
                        start: info.start,
                        end: info.end,
                        allDay: true,
                    });
                })
                .catch(() => {
                    // バリデーションエラーなど
                    alert("登録に失敗しました");
                });
        }
    },
});
calendar.render();

ソースの全容は、最後に掲載しています。

これで登録処理の流れができました。実際に試してみましょう。
以下のURLにアクセスします。

http://localhost:8000/calendar

プロンプトに任意のイベント名を入力します。

データベースに正しく登録されました。

エラー処理も確認してみましょう。
イベント名は32文字の文字数制限をかけましたので、32文字以上のイベント名を登録してみます。

失敗アラートが表示され、カレンダー上にスケジュールは表示されませんし、当然DBにも登録されません。

エラーメッセージは簡易的にしましたが、バリデーション結果を表示するのも良いでしょう。
今回は不正な値が登録されないように、バリデーション処理の実装を行いました。

スポンサーリンク

スケジュールの表示

スケジュールの登録が完了しました。今度はカレンダーの表示時に、データベースに登録されているスケジュールを表示します。

web.phpを修正し、スケジュールを取得するためのルーティングを追加します。

use App\Http\Controllers\ScheduleController;

// スケジュール登録処理
Route::post('/schedule-add', [ScheduleController::class, 'scheduleAdd'])->name('schedule-add');
// スケジュール取得処理
Route::post('/schedule-get', [ScheduleController::class, 'scheduleGet'])->name('schedule-get');

スケジュールを取得するための処理を追加します。
カレンダーが表示されている期間のみ、スケジュールを取得するようにします。

基本的にカレンダーは1ヶ月分表示されています。
表示されている期間のみのデータを返却するようにしましょう。
そうしないと、毎回全スケジュールを返却することになり、効率が悪いです。

App\Http\Controllers\ScheduleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Schedule;

class ScheduleController extends Controller
{
...

    /**
     * スケジュールを取得
     *
     * @param  Request  $request
     */
    public function scheduleGet(Request $request)
    {
        // バリデーション
        $request->validate([
            'start_date' => 'required|integer',
            'end_date' => 'required|integer'
        ]);

        // カレンダー表示期間
        $start_date = date('Y-m-d', $request->input('start_date') / 1000);
        $end_date = date('Y-m-d', $request->input('end_date') / 1000);

        // 登録処理
        return Schedule::query()
            ->select(
                // FullCalendarの形式に合わせる
                'start_date as start',
                'end_date as end',
                'event_name as title'
            )
            // FullCalendarの表示範囲のみ表示
            ->where('end_date', '>', $start_date)
            ->where('start_date', '<', $end_date)
            ->get();
    }
}

calendar.jsを開き、スケジュールを取得する処理を記述します。

「events」プロパティを追加します。
カレンダーが表示された時や、前の月・次の月のように表示が切り替わる度に呼ばれます。

resources\js\calendar.js
let calendar = new Calendar(calendarEl, {
    plugins: [interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin],
    initialView: "dayGridMonth",
    headerToolbar: {
        left: "prev,next today",
        center: "title",
        right: "dayGridMonth,timeGridWeek,listWeek",
    },
    locale: "ja",
...

    events: function (info, successCallback, failureCallback) {
        // Laravelのスケジュール取得処理の呼び出し
        axios
            .post("/schedule-get", {
                start_date: info.start.valueOf(),
                end_date: info.end.valueOf(),
            })
            .then((response) => {
                successCallback(response.data);
            })
            .catch(() => {
                // バリデーションエラーなど
                alert("登録に失敗しました");
            });
    },

});
calendar.render();

これでプログラムは完成です。

スケジュールを登録してみましょう。DBにも格納されますので、ブラウザを閉じて再度カレンダーを表示してもスケジュールは表示されます。(永続化)

ソースの全容

resources\js\calendar.js
import { Calendar } from "@fullcalendar/core";
import interactionPlugin from "@fullcalendar/interaction";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import listPlugin from "@fullcalendar/list";

var calendarEl = document.getElementById("calendar");

let calendar = new Calendar(calendarEl, {
    plugins: [interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin],
    initialView: "dayGridMonth",
    headerToolbar: {
        left: "prev,next today",
        center: "title",
        right: "dayGridMonth,timeGridWeek,listWeek",
    },
    locale: "ja",

    // 日付をクリック、または範囲を選択したイベント
    selectable: true,
    select: function (info) {
        //alert("selected " + info.startStr + " to " + info.endStr);

        // 入力ダイアログ
        const eventName = prompt("イベントを入力してください");

        if (eventName) {
            // Laravelの登録処理の呼び出し
            axios
                .post("/schedule-add", {
                    start_date: info.start.valueOf(),
                    end_date: info.end.valueOf(),
                    event_name: eventName,
                })
                .then(() => {
                    // イベントの追加
                    calendar.addEvent({
                        title: eventName,
                        start: info.start,
                        end: info.end,
                        allDay: true,
                    });
                })
                .catch(() => {
                    // バリデーションエラーなど
                    alert("登録に失敗しました");
                });
        }
    },
    events: function (info, successCallback, failureCallback) {
        // Laravelのスケジュール取得処理の呼び出し
        axios
            .post("/schedule-get", {
                start_date: info.start.valueOf(),
                end_date: info.end.valueOf(),
            })
            .then((response) => {
                successCallback(response.data);
            })
            .catch(() => {
                // バリデーションエラーなど
                alert("登録に失敗しました");
            });
    },
});
calendar.render();
App\Http\Controllers\ScheduleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Schedule;

class ScheduleController extends Controller
{

    /**
     * スケジュールを登録
     *
     * @param  Request  $request
     */
    public function scheduleAdd(Request $request)
    {
        // バリデーション
        $request->validate([
            'start_date' => 'required|integer',
            'end_date' => 'required|integer',
            'event_name' => 'required|max:32',
        ]);

        // 登録処理
        $schedule = new Schedule;
        // 日付に変換。JavaScriptのタイムスタンプはミリ秒なので秒に変換
        $schedule->start_date = date('Y-m-d', $request->input('start_date') / 1000);
        $schedule->end_date = date('Y-m-d', $request->input('end_date') / 1000);
        $schedule->event_name = $request->input('event_name');
        $schedule->save();

        return;
    }

    /**
     * スケジュールを取得
     *
     * @param  Request  $request
     */
    public function scheduleGet(Request $request)
    {
        // バリデーション
        $request->validate([
            'start_date' => 'required|integer',
            'end_date' => 'required|integer'
        ]);

        // カレンダー表示期間
        $start_date = date('Y-m-d', $request->input('start_date') / 1000);
        $end_date = date('Y-m-d', $request->input('end_date') / 1000);

        // 登録処理
        return Schedule::query()
            ->select(
                // FullCalendarの形式に合わせる
                'start_date as start',
                'end_date as end',
                'event_name as title'
            )
            // FullCalendarの表示範囲のみ表示
            ->where('end_date', '>', $start_date)
            ->where('start_date', '<', $end_date)
            ->get();
    }
}

さいごに

簡単なスケジュールを登録するWebアプリケーションを作成しました。
カレンダーを利用するケースはよくあると思いますが、活用してみましょう。

コメント

タイトルとURLをコピーしました