侍エンジニア塾でLaravelを学び始めた私が先生にカレンダーの作り方を教えてもらったので紹介したいと思います♪
完成イメージ画像
サンプルは今月分のカレンダーを表示させるものです
※「<」「>」で先月・来月を表示させるものは記載していません(web.phpで表示させたい月のデータを渡してください)
特にデザインにはこだわっていないのでCSSは載せていません(*´ω`*)
Controller
public function showCalendar(Request $request, $month)
{
$calendar = calendar($section, $patient, $month);
$month = new CarbonImmutable($month);
return view('calendar', compact( 'calendar', 'month'));
}
helpers.php
独自のヘルパー関数を作成してcalendar関数を使えるようにする
①app/Helperなどの適切なディレクトリを作成し、helpers.phpファイルを作成
カレンダーを表示させるためには、3つの月の日付を配列に入れなければならない。その配列をview側で一週間分(7日)を1ブロックとして表示させる。
- 前月の最後の週
- 今月
- 来月の最初の週
<?php
use App\Helpers\DayFrame;
use App\Patient;
use App\Section;
use Carbon\CarbonImmutable;
$WEEK_DAYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
define('WEEK_DAYS', $WEEK_DAYS);
function dates($month)
{
// 今月の日付を取得(取得例: 2020-5)
$month = date('Y-m');
// 月初の曜日を数値で取得(0[日]から6[土]の数値)
// (取得例: date('w', strtotime('2020-05-01')) → 5(金曜日))
$weekDay = date('w', strtotime($month));
$dates = [];
// 前月最終週の日付
for ($weekDay; $weekDay >= 1; $weekDay -= 1) {
// 取得例: $weekDay=5 の場合 $dateには 2020−5から5日引いた2020-4-26、2020−5から4日引いた2020-4-27...
$dates[] = new CarbonImmutable("$month -$weekDay day");
}
// 月末日(取得例: 2020-5の末日 → 31日)
$lastDay = date('d', strtotime("last day of $month"));
// その月の日付(取得例: 2020-5の初日〜末日まで → 2020-1 ~ 2020-31を配列に入れる)
for ($day = 1; $day <= $lastDay; $day += 1) {
$dates[] = new CarbonImmutable("$month-$day");
}
// 月末の曜日(date('w', strtotime('2020-05-31')) → 0(日曜日))
$weekDay = date('w', strtotime("$month-$lastDay"));
// 来月最初の週の日付
for ($day = 1; $day <= 6 - $weekDay; $day += 1) {
// 取得例: $weekDay=0(日曜日) の場合 6日分ループを回す
// $dateには 2020−5-31に1日足した2020-6-1、2020−5-31に2日足した2020-6-2、...
$dates[] = new CarbonImmutable("$month-$lastDay +$day day");
}
return $dates;
}
function calendar(Section $section, Patient $patient, String $month)
{
$dates = dates($month);
// 今日
$start = CarbonImmutable::today();
// 現在時間 + sectionの予約可能時間
$end = CarbonImmutable::now()->add($section->reservable_hours, 'hour');
for ($i = 0; $i < count($dates); $i += 7) {
$week = [];
foreach (array_slice($dates, $i, 7) as $date) {
$hasThisMonthDate = date('m', strtotime($month)) == $date->month;
// 今日の0:00以上かつ、現在時間 + sectionの予約可能時間以内
if ($date >= $start && $date <= $end) {
$week[] = new DayFrame($section, $patient, $date, $hasThisMonthDate);
} else {
// stdClassは中身のない定義済みクラス
$frame = new stdClass();
$frame->date = $date;
$frame->hasThisMonthDate = $hasThisMonthDate;
if ($date > $end && $patient->reservedDate($section, $date)) {
$frame->state = 'patient_reserved_date';
} else {
$frame->state = 'disable';
}
$week[] = $frame;
}
}
yield $week;
}
}
②composer.jsonのautoloadに追加
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
],
"files": [
"app/helpers.php"
]
},
composer dump-autoload
blade
<div class="card"> <div class="card-header" style="text-align: center;"> - 予約 - </div> <div class="card-body"> <ul> <li>カレンダーより、ご希望の予約日をお選びください。</li> <li>予約日は次回予約のみお取りいただけます。</li> <li>予約日時を変更される場合は、いったんキャンセルしてから予約をお取りなおしください。</li> </ul> <div class="calender"> <form class="prev-next-form"></form> <table class="table"> <tr> <td colspan="2"> <button class="btn btn-outline-secondary prev-next-btn" data-month="{{ $month->add(-1, 'month')->format('Y-m') }}"><</button> </td> <th colspan="3"> <div class="text-center"> {{ $month->year }}年{{ $month->month }}月 </div> </th> <td colspan="2"> <div class="text-right"> <button class="btn btn-outline-secondary prev-next-btn" data-month="{{ $month->add(1, 'month')->format('Y-m') }}">></button> </div> </td> </tr> <tr> <th class="sun" style="color: red"><div class="text-center">日</div></th> <th class="mon"><div class="text-center">月</div></th> <th class="tue"><div class="text-center">火</div></th> <th class="wed"><div class="text-center">水</div></th> <th class="thu"><div class="text-center">木</div></th> <th class="fri"><div class="text-center">金</div></th> <th class="sat" style="color: blue"><div class="text-center">土</div></th> </tr> @foreach ($calendar as $week) <tr> @foreach ($week as $date) <td> <div class="text-center"> @if($date->date->weekDay() === 0) <span class="sun" style="color: red">{{ $date->date->day }}</span> @elseif($date->date->weekDay() === 6) <span class="sat" style="color:blue;">{{ $date->date->day }}</span> @else <span class="other">{{ $date->date->day }}</span> @endif </div> </td> @endforeach </tr> @endforeach </table> </div> </div>