![見出し画像](https://assets.st-note.com/production/uploads/images/34339565/rectangle_large_type_2_f4f4cb51dff7c6b465b24a2306d3860a.png?width=1200)
カレンダーアプリを作ろう(#2) #Laravel基礎
本稿はカレンダーアプリを作ろうの2回目です。
前回カレンダーの表示部分を作りました。今回は「営業日(定休日)」を設定し、カレンダーに表示するようにします。
# はじめに
「会社・レストランのサイトに営業している日を載せたい」という要件があった時、どのように作るのが良いでしょうか?
土日、祝日が休みの場合、休みが特に決まっていない場合、週に1日しか営業しない場合、様々なパターンが考えられます。
休みが特に決まっていない場合は、休みになる日を入力してもらう形が簡単でしょうし、週に1日しか営業しない場合は営業する日だけを選ぶ方が簡単です。
パターンが無限に発生するような要件の場合、ある程度要望を絞って決める必要があります。
今回は「定休日を曜日・祝日で選んで貰う」形で作成を行います。その後「例外的に休業日・営業日」を決めることが出来れば、ほとんどの場合、運用で対応できます。
・週に1日しか営業しない→すべての曜日を休み、例外で営業日を設定
・休みが特に決まっていない→すべての曜日を営業、例外で休みを設定
# モデルの作成
定休日を設定するためのモデルを「HolidaySetting」とします。
HolidaySettingは次の項目を持てば、営業日設定が上手くできそうです。
・月曜日の設定(営業or休み)= flag_mon
・火曜日の設定(営業or休み)= flag_tue
・水曜日の設定(営業or休み)= flag_wed
・木曜日の設定(営業or休み)= flag_thu
・金曜日の設定(営業or休み)= flag_fri
・土曜日の設定(営業or休み)= flag_sat
・日曜日の設定(営業or休み)= flag_sun
・祝日の設定(営業or休み) = flag_holiday
各項目がどんな値を取るのか、という点について考えたのですが、1の時営業、0の時休みとするのが正解なのか0の時営業、1の時休みにするのか悩んだのですがどの形を取っても混乱しそうです。
今回は「1=営業、2=休み」というロジックに設定しました。
これにあわせて、マイグレーションを作成していきましょう。
php artisan make:migration create_holiday_setting_table
Created Migration: 2020_07_09_145144_create_holiday_setting_table
作成されたマイグレーションファイルを編集していきます。ファイル名は実行段階で生成されます。今回は「2020_07_09_145144_create_holiday_setting_table.php」が作成されました。
database/migrations/2020_07_09_145144_create_holiday_setting_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateHolidaySettingTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('holiday_setting', function (Blueprint $table) {
$table->id();
$table->integer("flag_mon");
$table->integer("flag_tue");
$table->integer("flag_wed");
$table->integer("flag_thu");
$table->integer("flag_fri");
$table->integer("flag_sat");
$table->integer("flag_sun");
$table->integer("flag_holiday");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('holiday_setting');
}
}
マイグレーションファイルの作成が終わったら「artisan migrate」コマンドを入力してマイグレーションを実行します。
php artisan migrate
マイグレーションは実行できましたら、モデルを作成します。
定休日設定はCalendarの中に入れた方が整理しやすいので、次のようにmake:modelコマンドを実行します。
php artisan make:model Calendar/HolidaySetting
作成されたHolidaySetting.phpを編集して、作成したテーブルとの関連付を行います。
app/Calendar/HolidaySetting.php
<?php
namespace App\Calendar;
use Illuminate\Database\Eloquent\Model;
class HolidaySetting extends Model
{
const OPEN = 1;
const CLOSE = 2;
protected $table = "holiday_setting";
protected $fillable = [
"flag_mon",
"flag_tue",
"flag_wed",
"flag_thu",
"flag_fri",
"flag_sat",
"flag_sun",
"flag_holiday",
];
function isOpenMonday(){
return $this->flag_mon == HolidaySetting::OPEN;
}
function isOpenTuesday(){
return $this->flag_tue == HolidaySetting::OPEN;
}
function isOpenWednesday(){
return $this->flag_wed == HolidaySetting::OPEN;
}
function isOpenThursday(){
return $this->flag_thu == HolidaySetting::OPEN;
}
function isOpenFriday(){
return $this->flag_fri == HolidaySetting::OPEN;
}
function isOpenSaturday(){
return $this->flag_sat == HolidaySetting::OPEN;
}
function isOpenSunday(){
return $this->flag_sun == HolidaySetting::OPEN;
}
function isOpenHoliday(){
return $this->flag_holiday == HolidaySetting::OPEN;
}
function isCloseMonday(){
return $this->flag_mon == HolidaySetting::CLOSE;
}
function isCloseTuesday(){
return $this->flag_tue == HolidaySetting::CLOSE;
}
function isCloseWednesday(){
return $this->flag_wed == HolidaySetting::CLOSE;
}
function isCloseThursday(){
return $this->flag_thu == HolidaySetting::CLOSE;
}
function isCloseFriday(){
return $this->flag_fri == HolidaySetting::CLOSE;
}
function isCloseSaturday(){
return $this->flag_sat == HolidaySetting::CLOSE;
}
function isCloseSunday(){
return $this->flag_sun == HolidaySetting::CLOSE;
}
function isCloseHoliday(){
return $this->flag_holiday == HolidaySetting::CLOSE;
}
}
コードが長いですが、中身はよく見るとただの繰り返しになっています。各曜日毎にOpenかCloseかを判定する関数を追加しています。
const OPEN = 1;
const CLOSE = 2;
営業日、休みを定数で管理するための設定値です。
protected $fillable = [
"flag_mon",
"flag_tue",
"flag_wed",
"flag_thu",
"flag_fri",
"flag_sat",
"flag_sun",
"flag_holiday",
];
$fillableはModelの機能で値を更新する際に使われる、許可リストです。
update()関数で更新する時に、指定したカラムだけを更新することができます。$fillableを指定することでフォームの値からの更新をシンプルに書くことができます。
//fillableに指定したもの以外は更新されないので安心
$setting->update($request->all());
各曜日毎に営業、休みの関数を用意しているため、コードが長くなっています。
# 定休日設定画面の作成
テーブルの作成、モデルの作成が終わったので次に定休日を設定する画面を作成します。
このような月曜日〜日曜日、祝日それぞれをラジオボタンで営業日と休みに設定出来る画面を作っていきます。
まずはテンプレートを作成していきます。
テンプレートは次の仕様を想定して作成します。
・ControllerからHolidaySettingオブジェクトを「$setting」で貰う
・営業に設定する時の値を「$FLAG_OPEN」、休みに設定する時の値を「$FLAG_CLOSE」で貰う
・遷移先は「route('update_holiday_setting')」とする
ファイル名はcalendar周りをディレクトリにまとめておくと後で管理しやすいので、calendar/holiday_setting_form.blade.phpとしています。
resources/views/calendar/holiday_setting_form.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">定休日設定</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<form method="post" action="{{ route('update_holiday_setting') }}">
@csrf
<table class="table table-borderd">
<tr>
<th>月曜日</th>
<td>
<input type="radio" name="flag_mon" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenMonday()) ? 'checked' : '' }} id="flag_mon_open" />
<label for="flag_mon_open">営業日</label>
<input type="radio" name="flag_mon" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseMonday()) ? 'checked' : '' }} id="flag_mon_close" />
<label for="flag_mon_close">休み</label>
</td>
</tr>
<tr>
<th>火曜日</th>
<td>
<input type="radio" name="flag_tue" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenTuesday()) ? 'checked' : '' }} id="flag_tue_open" />
<label for="flag_tue_open">営業日</label>
<input type="radio" name="flag_tue" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseTuesday()) ? 'checked' : '' }} id="flag_tue_close" />
<label for="flag_tue_close">休み</label>
</td>
</tr>
<tr>
<th>水曜日</th>
<td>
<input type="radio" name="flag_wed" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenWednesday()) ? 'checked' : '' }} id="flag_wed_open" />
<label for="flag_wed_open">営業日</label>
<input type="radio" name="flag_wed" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseWednesday()) ? 'checked' : '' }} id="flag_wed_close" />
<label for="flag_wed_close">休み</label>
</td>
</tr>
<tr>
<th>木曜日</th>
<td>
<input type="radio" name="flag_thu" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenThursday()) ? 'checked' : '' }} id="flag_thu_open" />
<label for="flag_thu_open">営業日</label>
<input type="radio" name="flag_thu" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseThursday()) ? 'checked' : '' }} id="flag_thu_close" />
<label for="flag_thu_close">休み</label>
</td>
</tr>
<tr>
<th>金曜日</th>
<td>
<input type="radio" name="flag_fri" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenFriday()) ? 'checked' : '' }} id="flag_fri_open" />
<label for="flag_fri_open">営業日</label>
<input type="radio" name="flag_fri" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseFriday()) ? 'checked' : '' }} id="flag_fri_close" />
<label for="flag_fri_close">休み</label>
</td>
</tr>
<tr>
<th>土曜日</th>
<td>
<input type="radio" name="flag_sat" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenSaturday()) ? 'checked' : '' }} id="flag_sat_open" />
<label for="flag_sat_open">営業日</label>
<input type="radio" name="flag_sat" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseSaturday()) ? 'checked' : '' }} id="flag_sat_close" />
<label for="flag_sat_close">休み</label>
</td>
</tr>
<tr>
<th>日曜日</th>
<td>
<input type="radio" name="flag_sun" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenSunday()) ? 'checked' : '' }} id="flag_sun_open" />
<label for="flag_sun_open">営業日</label>
<input type="radio" name="flag_sun" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseSunday()) ? 'checked' : '' }} id="flag_sun_close" />
<label for="flag_sun_close">休み</label>
</td>
</tr>
<tr>
<th>祝日</th>
<td>
<input type="radio" name="flag_holiday" value="{{ $FLAG_OPEN }}" {{ ($setting->isOpenHoliday()) ? 'checked' : '' }} id="flag_holiday_ope" />
<label for="flag_holiday_open">営業日</label>
<input type="radio" name="flag_holiday" value="{{ $FLAG_CLOSE }}" {{ ($setting->isCloseHoliday()) ? 'checked' : '' }} id="flag_holiday_clos" />
<label for="flag_holiday_close">休み</label>
</td>
</tr>
</table>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
こちらもコードが長いですが、曜日毎の繰り返しです。ラジオボタンのコードは複雑ですが、細かく分割して解説していきます。
<input type="radio" name="flag_mon" value="{{ $FLAG_OPEN }}" ... />
<input type="radio" name="flag_mon" value="{{ $FLAG_CLOSE }}" ... />
ラジオボタンはどちらかが選択されることを要求するため、営業日と休日のname属性を揃える必要があります。月曜日はどちらもflag_monとしています。
{{ ($setting->isOpenMonday()) ? 'checked' : '' }}
{{ ($setting->isCloseMonday()) ? 'checked' : '' }}
モデルの作成で大量に関数を作っていたことで営業中か休みかを判定してcheckedを出す部分がシンプルに書けています。
<input ... id="flag_mon_open" />
<label for="flag_mon_open">営業中</label>
<label>要素はforで指定した要素をクリックで選べるようにするために使っています。<label>要素が無いとクリック出来る範囲が狭くて使いにくいので設定するようにしましょう。
あとは月曜日〜日曜日、祝日まで繰り返すだけなので長いようでそこまで難しくはありません。
◆
次に、Controllerを作成します。
make:controllerコマンドを使ってHolidaySettingControllerを作成しましょう。今後の機能拡張を考えて、こちらもCalendarディレクトリ以下に作成していきます。
php artisan make:controller Calendar/HolidaySettingController
作成されたHolidaySettingController.phpを編集していきましょう。HolidaySettingControllerクラスはフォームを表示するためのform()関数、フォームの遷移先のupdate()関数の2個を持ちます。
app/Http/Controllers/Calendar/HolidaySettingController.php
<?php
namespace App\Http\Controllers\Calendar;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Calendar\HolidaySetting;
class HolidaySettingController extends Controller
{
function form(){
//取得
$setting = HolidaySetting::firstOrNew();
return view("calendar/holiday_setting_form", [
"setting" => $setting,
"FLAG_OPEN" => HolidaySetting::OPEN,
"FLAG_CLOSE" => HolidaySetting::CLOSE
]);
}
function update(Request $request){
//取得
$setting = HolidaySetting::firstOrNew();
//更新
$setting->update($request->all());
return redirect()
->action("Calendar\HolidaySettingController@form")
->withStatus("保存しました");
}
}
use App\Calendar\HolidaySetting;
HolidaySettingクラスを使うための設定です。
$setting = HolidaySetting::firstOrNew();
Modelの機能で1件目を取得し、なかったら新規に作成しています。HolidaySettingがデーターベースになかっても問題が無いように作っています。
次のように書いても同じ意味になります。
$setting = HolidaySetting::first();
if(!$setting)$setting = new HolidaySetting();
firstOrNew()関数使った書き方の方がシンプルで後で見た時にわかりやすいですね。
$setting->update($request->all());
Modelで$fillableを指定していたおかげで安心して更新できます。うっかり違う値を更新してしまう失敗もなく、個別に値を入力してしまう心配もありません。
return redirect()
->action("Calendar\HolidaySettingController@form")
->withStatus("保存しました");
リダイレクトでクラス名を使うことでルーティングがどうなっているかを気にする必要がありません。リダイレクトのパターンについては記事にまとめようと思います。
@TODO リダイレクトの記事を作ったらここに書く
最後にルーティングの設定を行い、ブラウザで表示確認を行います。
routes/web.php
//祝日設定
Route::get('/holiday_setting', 'Calendar\HolidaySettingController@form')
->name("holiday_setting");
Route::post('/holiday_setting', 'Calendar\HolidaySettingController@update')
->name("update_holiday_setting");
Viewで{{ route("update_holiday_setting") }}を使ってフォームの遷移先を指定しているので、忘れないようにname()でルーティングに名前をつけておきましょう。
http://localhost:8000/holiday_setting
ブラウザで定休日設定画面を開いて上手く定休日は保存できるか、確認してみてください。
特定の曜日だけ保存できない場合はname属性やfillableで指定している値が間違っている可能性があります。
# 祝日データの読み込み
その日が祝日かどうか判断する方法ですが、内閣府に「国民の祝日」のデータがあります。
これを使うのも一つの手ですが、あまり便利ではありません。
実はPHPで祝日を扱う場合、とても良いライブラリが既に存在しています。
「Yasumi」というとてもわかりやすい名前です。
今回はこれを使っていきます。まずはcomposer経由でインストールを行います。
composer require azuyalabs/yasumi
インストールには少し時間がかかります。
Yasumiを使った祝日の情報はこのように読み込みます。
$holidays = Yasumi::create("Japan", "2020", "ja_JP");
では、HolidaySettingクラスを修正し、Yasumi経由で祝日判定ができるようにしましょう。
app/Calendar/HolidaySetting.php
use Yasumi\Yasumi;
class HolidaySetting extends Model
{
(略)
private $holidays = null;
function loadHoliday($year){
$this->holidays = Yasumi::create("Japan", $year,"ja_JP");
}
function isHoliday($date){
if(!$this->holidays)return false;
return $this->holidays->isHoliday($date);
}
}
use Yasumi\Yasumi;
Yasumiを使うためにuse句を追加します。
private $holidays = null;
読み込んだYasumiオブジェクトを保持するためにプロパティを追加します。
function loadHoliday($year){
$this->holidays = Yasumi::create("Japan", $year,"ja_JP");
}
指定した年の祝日を読み込んで、$holidaysに保持します。
function isHoliday($date){
if(!$this->holidays)return false;
return $this->holidays->isHoliday($date);
}
isHoliday()はYasumiオブジェクトが初期化されていないと判定できないため、初期化済みかをまずは判断します。
読み込みできていればYasumi#isHoliday()関数を使って祝日かどうかを判定できます。
Yasumiは取得も祝日かどうか判定するのも簡単で良いですね。
# カレンダー表示側に対応する
作成した定休日情報をカレンダーに反映していきましょう。
「日カレンダーのクラスに、休みであればday-closeクラスを追加する」というやり方で定休日を表現していきます。
例えば2020年7月23日は祝日なので「day-thu day-close」の2個のクラスが設定されるようにします。
<td class="day-thu day-close"><p class="day">23</p></td>
定休日用のクラスに背景色を設定するためにCSSを編集します。
public/css/calendar.css
.day-close {
background-color: #FF7F50;
}
CalendarViewクラスを修正して、HolidaySettingを取得する処理を追加します。(*が変更箇所)
app/Calendar/CalendarView.php
class CalendarView {
/**
* カレンダーを出力する
*/
function render(){
+ //HolidaySetting
+ $setting = HolidaySetting::firstOrNew();
+ $setting->loadHoliday($this->carbon->format("Y"));
$html = [];
$html[] = '<div class="calendar">';
$html[] = '<table class="table">';
$html[] = '<thead>';
$html[] = '<tr>';
$html[] = '<th>月</th>';
$html[] = '<th>火</th>';
$html[] = '<th>水</th>';
$html[] = '<th>木</th>';
$html[] = '<th>金</th>';
$html[] = '<th>土</th>';
$html[] = '<th>日</th>';
$html[] = '</tr>';
$html[] = '</thead>';
$html[] = '<tbody>';
$weeks = $this->getWeeks();
foreach($weeks as $week){
$html[] = '<tr class="'.$week->getClassName().'">';
* $days = $week->getDays($setting);
foreach($days as $day){
$html[] = '<td class="'.$day->getClassName().'">';
$html[] = $day->render();
$html[] = '</td>';
}
$html[] = '</tr>';
}
$html[] = '</tbody>';
$html[] = '</table>';
$html[] = '</div>';
return implode("", $html);
}
実際にHTMLのクラスを設定しているのはCalendarWeekDayクラスなのでCalendarView -> CalendarWeek -> CalendarWeekDayと順にHolidaySettingオブジェクトを渡していくという形で実装していきます。
CalendarWeek#getDays()関数にHolidaySettingを渡す形が一番無駄がなさそうです。
app/Calendar/CalendarWeek.php
class CalendarWeek {
/**
* @return CalendarWeekDay[]
*/
* function getDays(HolidaySetting $setting){
$days = [];
//開始日〜終了日
$startDay = $this->carbon->copy()->startOfWeek();
$lastDay = $this->carbon->copy()->endOfWeek();
//作業用
$tmpDay = $startDay->copy();
//月曜日〜日曜日までループ
while($tmpDay->lte($lastDay)){
//前の月、もしくは後ろの月の場合は空白を表示
if($tmpDay->month != $this->carbon->month){
$day = new CalendarWeekBlankDay($tmpDay->copy());
$days[] = $day;
$tmpDay->addDay(1);
continue;
}
//今月
$day = new CalendarWeekDay($tmpDay->copy());
* $day->checkHoliday($setting);
$days[] = $day;
//翌日に移動
$tmpDay->addDay(1);
}
return $days;
}
}
CalendarWeekからCalendarWeekDay#checkHoliday()関数へHolidaySettingオブジェクトを渡して、定休日判定を行います。
CalendarWeekDayクラスで定休日の判定を行います。コードは少し長めです。(*が変更箇所)
app/Calendar/CalendarWeekDay.php
class CalendarWeekDay {
protected $carbon;
* protected $isHoliday = false;
function __construct($date){
$this->carbon = new Carbon($date);
}
* function getClassName(){
* $classNames = [ "day-" . strtolower($this->carbon->format("D")) ];
*
* //祝日フラグを出す
* if($this->isHoliday){
* $classNames[] = "day-close";
* }
*
* return implode(" ", $classNames);
* }
/**
* @return
*/
function render(){
return '<p class="day">' . $this->carbon->format("j"). '</p>';
}
/**
* 休みかどうかを判定する
*/
function checkHoliday(HolidaySetting $setting){
if($this->carbon->isMonday() && $setting->isCloseMonday()){
$this->isHoliday = true;
}
else if($this->carbon->isTuesday() && $setting->isCloseTuesday()){
$this->isHoliday = true;
}
else if($this->carbon->isWednesday() && $setting->isCloseWednesday()){
$this->isHoliday = true;
}
else if($this->carbon->isThursday() && $setting->isCloseThursday()){
$this->isHoliday = true;
}
else if($this->carbon->isFriday() && $setting->isCloseFriday()){
$this->isHoliday = true;
}
else if($this->carbon->isSaturday() && $setting->isCloseSaturday()){
$this->isHoliday = true;
}
else if($this->carbon->isSunday() && $setting->isCloseSunday()){
$this->isHoliday = true;
}
//祝日は曜日とは別に判定する
if($setting->isCloseHoliday() && $setting->isHoliday($this->carbon)){
$this->isHoliday = true;
}
}
}
protected $isHoliday = false;
checkHolidays()メソッドを使って休みかどうかを判定した結果を保持するプロパティです。
function getClassName(){
$classNames = [ "day-" . strtolower($this->carbon->format("D")) ];
//祝日フラグを出す
if($this->isHoliday){
$classNames[] = "day-close";
}
return implode(" ", $classNames);
}
getClassName()関数は祝日の時だけday-closeを追加するようにしています。
function checkHoliday(HolidaySetting $setting){ ... }
休みかどうかを判定する関数です。
if($this->carbon->isMonday() && $setting->isCloseMonday()){
$this->isHoliday = true;
}
まずは月曜日〜日曜日までを判定しています。Carbonの関数とHolidaySettingの関数で曜日をしっかりチェックしているのでバグや漏れが発生しにくいですね。このあたりはもう少し違う書き方も出来そうです。
//祝日は曜日とは別に判定する
if($setting->isCloseHoliday() && $setting->isHoliday($this->carbon)){
$this->isHoliday = true;
}
祝日は曜日と別に判定する必要があります。今回は省略しますが、祝日は営業で曜日では休み、といったパターンを処理することも可能です。今回の処理だと曜日側で休みになっているので休み扱いです。
ブラウザで確認して、休みになっているのかチェックしてみましょう。
2020年は7月23日、24日と連休がありますね。水曜日と土曜日が休みなら5連休です。是非とも臨時休業を土曜日に追加したいものです。
# まとめ
実際の要件からモデルやデーターベースの設計に落とし込むことは難しさがあります。これらの設計はパズルのようなもので紙とペンだけでも考えることが出来ます。
また、データの持ち方だけでなく使いやすいフォームはどういうものがあるのか、プログラマーが考えなければならないことは多岐に渡ります。
例えば、HolidaySettingの保存パターンとロジックによっては「第何週の何曜日は休み」などの複雑なルールにも対応することができます。
その場合、どのような設定画面になるのか、どのようなデータをデータベースに保持すれば良いのか、紙とペンを持って一度挑戦してみてください。
今回のようにYassumiなどの便利なライブラリを組み合わせた開発が出来るようになるとぐっと出来ることが広がります。色々なライブラリの知識があれば、祝日をどうやって表現したら良いのか悩む必要はなく「Yasumiを使えば簡単」だとすぐにわかります。
このようなライブラリの知識も技術力です。
TwitterやQiita、はてなブックマークなど色々な人が話題にしているので読んだりブックマークしておくことも技術力アップに繋がります。
次回はこのカレンダーの定休日に対して例外の営業、例外の休みが設定出来るようにしていきます。
おつかれさまでした!
完成まで突っ走る意気込みです。サポートしていただけると非常に嬉しいです。応援よろしくお願いします。