【サンプル有り】Laravelでカレンダーを作成する

侍エンジニア塾で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>

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です