はじめに
今回はFullCalendarを利用して、イベントを登録しカレンダーに表示する簡単なWebアプリケーションを作成してみます。
(スケジュールアプリの作成)
Laravelプロジェクトで作成し、イベントはデータベースに保存します。
そうすることにより、ブラウザを再度表示した際に、イベントを再表示することが出来ます。
Laravel Sailでの開発環境の構築方法は以下をご覧ください。
他にも私のブログで、JavaScriptについて解説している記事がありますのでご覧ください。
【紹介】個人開発
私の個人開発ですがQuiphaというサービスを開発しました。(Laravel, Vue3など)
良かったら、会員登録して動作を試してみて下さい。
また、Laravel 9 実践入門という書籍を出版しました。
Kindle Unlimitedを契約している方であれば、読み放題で無料でご覧いただくことができます。
余談ですが、Django向けに解説した記事もございますので参考にしてください。
FullCalendarとは
FullCalendarのインストール方法や、実装は以下の記事をご覧ください。
本記事は、以下の記事の続きになります。
VS Codeの用意
VS Codeのインストール方法は、以下の記事にまとめましたのでご覧ください。
設定方法は以下を参考にしてください。
イベントの登録機能の実装
Laravelの登録処理の実装
前回の記事では、カレンダーにイベントを登録することが出来ました。
ただし、ブラウザの再描画を行うと、イベントはクリアされてしまいます。
ここからは実践でも使えるように、イベントをサーバーサイドで受信し、データベースに登録する処理をLaravelプロジェクトで実装していきます。
app.phpの修正
日付を操作しますので、Laravelのタイムゾーンの設定を変更してください。
'timezone' => 'Asia/Tokyo',
テーブルの用意
以下のコマンドでmigrationファイルを用意します。
イベントを格納するテーブルになります。
$ sail 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;
return new class 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');
}
};
マイグレーションを実行し、テーブルを作成します。
$ sail php artisan migrate
モデルの作成
先ほど作成したテーブルに対するモデルクラスを作成します。コマンドを実行します。
$ sail php artisan make:model Schedule
クラスファイルが作成されますが、特に変更の必要はありません。
コントローラの作成
以下のコマンドでコントローラを作成します。
$ sail php artisan make:controller ScheduleController
web.phpを修正し、ルーティングを追加します。
use App\Http\Controllers\ScheduleController;
// イベント登録処理
Route::post('/schedule-add', [ScheduleController::class, 'scheduleAdd'])->name('schedule-add');
イベントを登録するための処理を追加します。
リクエストのバリデーションと、DBへの登録処理を追加しました。
<?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;
}
}
calendar.jsを開き、非同期通信を行うためのaxiosを追加します。
import axios from 'axios';
さらにイベントを送信する処理を追加します。
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";
import axios from 'axios';
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("登録に失敗しました");
});
}
},
});
calendar.render();
jsファイルをビルドします。開発時ですのでdevを指定しました。
(ViteでもMixでも同様)
$ sail npm run dev
Viteの場合で、本番用にJS/CSSを出力する場合は、以下のコマンドを実行します。
$ sail npm run build
Viteについては以下の記事にもまとめました。
これで登録処理の流れができました。実際に試してみましょう。
以下のURLにアクセスします。
http://localhost/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');
イベントを取得するための処理を追加します。
カレンダーが表示されている期間のみ、イベントを取得するようにします。
<?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を開き、イベントを取得する処理を記述します。
import { Calendar } from "@fullcalendar/core";
...省略
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) => {
// 追加したイベントを削除
calendar.removeAllEvents();
// カレンダーに読み込み
successCallback(response.data);
})
.catch(() => {
// バリデーションエラーなど
alert("登録に失敗しました");
});
},
});
calendar.render();
これでプログラムは完成です。
イベントを登録してみましょう。DBにも格納されますので、ブラウザを閉じて再度カレンダーを表示してもイベントは表示されます。(永続化)
ソースの全容
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";
import axios from 'axios';
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) => {
// 追加したイベントを削除
calendar.removeAllEvents();
// カレンダーに読み込み
successCallback(response.data);
})
.catch(() => {
// バリデーションエラーなど
alert("登録に失敗しました");
});
},
});
calendar.render();
<?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();
}
}
その他
初学者へ
Laravelを初めて触る方へ向け、手順やアドバイスをまとめました。
外部サーバーへ公開
作成したアプリは公開して使ってもらいましょう!
Laravelアプリケーションを外部公開する方法をまとめました。
脆弱性対策
脆弱性を抱えたアプリケーションの場合、攻撃を受ける可能性があり大変危険です。
作成したアプリケーションは、脆弱性対策も意識しましょう。
GitHubと連携
GitHubと連携する方法を解説しました。
プロジェクトの管理はGitHubを活用しましょう。
GitHub Copilot
GitHub Copilotを導入し、AIにコーディングをサポートしてもらうこともできます。
さいごに
簡単なスケジュールを登録するWebアプリケーションを作成しました。
カレンダーを利用するケースはよくあると思いますが、活用してみましょう。
他にも私のブログで、JavaScriptについて解説している記事がありますのでご覧ください。
コメント
こちらのブログ記事の方法で実装を試みましたが、下記のJSエラーが発生しますが、何が原因でしょうか。
Fullcallenderの読み込みが正常にできていないようですが、npmでのインストールは行いました。
「resources\js\calendar.js」ファイルの先頭に、以下のimport文が足りないためにエラーが発生していると思われます。
すみません、記事の解説にあたり余計かなと思い、敢えて上記のimport文を省略していました。
(ソースの全容は最後に記載していました)
それが誤解を与えてしまったのだと思います。
記事は修正しましたが、ご確認お願いいたします。
FullCalendarのプラグインの導入については、以下の記事を参考にしてください。
https://chigusa-web.com/blog/fullcalendar/
あ、すみません npm run devをよく見たら実行時にエラーが出ており、
moduleがないといわれました。
installしたつもりだったのですが、再度インストールしなおしたところ表示されました!
下記の方の記事の応用編だとは理解しているのですが、
こちらではinstallには触れられていなかったので、もしかすると見逃していたのかもしれません。
https://chigusa-web.com/blog/fullcalendar/
お手数おかけいたしました。