PHPでカレンダーを作ってみる②
前月や翌月のカレンダー

こんにちは、ゆんつです。

前回、PHPを使って今月分のカレンダーを作成しました。

「PHPでカレンダーを作ってみる①」

作成したカレンダーには前月と翌日へのリンクがありましたが、見た目だけで機能は実装していないので、クリックしても何も起こりません。

カレンダー

今回はカレンダーの前月へのリンクをクリックすると前月のカレンダーが表示され、翌月へのリンクをクリックすると翌月のカレンダーが表示されるようにしたいと思います。

リンクを作成するために必要なもの

前月のカレンダーと翌月のカレンダーを表示するためには、前月と翌月のリンクにクエリ情報を設定して、カレンダー表示月の前月または翌月の西暦と月の情報を渡す必要があります。

そして、そのクエリ情報を設定したリンクがクリックされたら、$_GETで西暦と月の情報を取得して表示すべき月のカレンダーを作成することになります。

作ってみよう

早速リンクに機能を実装してみましょう。

完成形のコードを記載しておきます。

<?php
//現在のDateTimeインスタンスを作成
$today = new DateTime();

/*---------------------------------------------------
追加部分
----------------------------------------------------*/
if(isset($_GET['t']) && preg_match('/\A\d{4}-\d{2}\z/', $_GET['t'])) {
  //クエリ情報を基にしてDateTimeインスタンスを作成
  $start_day = new DateTime($_GET['t'] . '-01');
} else {
  //当月初日のDateTimeインスタンスを作成
  $start_day = new DateTime('first day of this month');
}

//カレンダー表示月の前月の年月を取得
$dt = clone($start_day);
$prev_month =  $dt->modify('-1 month')->format('Y-m');

//カレンダー表示月の翌月の年月を取得
$dt = clone($start_day);
$next_month =  $dt->modify('+1 month')->format('Y-m');
/*---------------------------------------------------
追加部分終了
----------------------------------------------------*/

//カレンダー表示月の年と月を取得
$year_month = $start_day->format('Y-m');

//表示月初日の曜日を数値で取得
$w = $start_day->format('w');

//表示月初日をカレンダーの開始日に変更する
$start_day->modify('-' . $w . ' day');

/*---------------------------------------------------
修正部分
----------------------------------------------------*/
//表示月末日のDateTimeインスタンスを作成
$end_day = new DateTime('last day of ' . $year_month);
/*---------------------------------------------------
修正部分終了
----------------------------------------------------*/

//カレンダーの終了日を取得するため月末の曜日を数値で取得
$w = $end_day->format('w');

//土曜日を数値にすると6。そこから月末の曜日に対応する数を引いてやれば、カレンダー末尾に追加すべき日数が判明する。
//+1しているのはDatePeriodの特性を考慮するため
$w = 6 - $w + 1;

//月末をカレンダーの終了日の翌日に変更する
$end_day->modify('+' . $w . ' day');

//カレンダーに表示する期間のインスタンスを作成する
$period = new DatePeriod(
  $start_day,
  new DateInterval('P1D'),
  $end_day
);

//htmlに描写するための変数
$body = '';

foreach ($period as $day) {
  //当月以外の日付はgreyクラスを付与してCSSで色をグレーにする
  $grey_class = $day->format('Y-m') === $year_month ? '' : 'grey';
  
  //本日にはtodayクラスを付与してCSSで数字の見た目を変える
  $today_class = $day->format('Y-m-d') === $today->format('Y-m-d') ? 'today' : '';
  
  //その曜日が日曜日なら<tr>タグを挿入する
  if ($day->format('w') == 0) {
    $body .= '<tr>';
  }
  
  //sprintfを使って整形しながらhtml部分を作成する
  $body .= sprintf(
    '<td class="youbi_%d %s %s">%d</td>',
    $day->format('w'),
    $today_class,
    $grey_class,
    $day->format('d')
  );
  
  //その曜日が土曜日なら</tr>タグを挿入する
  if ($day->format('w') == 6) {
    $body .= '</tr>';
  }
}

?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Calendar</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <table class="calendar">
    <thead class="calendar-head">
      <tr class="calendar-row">
        <!-- リンクにクエリ情報を設定する -->
        <th><a href="?t=<?php echo $prev_month ?>">&laquo;</a></th>
        <th colspan="5"><a href=""><?php echo $year_month ?></a></th>
        <th><a href="?t=<?php echo $next_month ?>">&raquo;</a></th>
      </tr>
    </thead>
    <tbody>
      <tr class="calendar-row">
        <td>日</td>
        <td>月</td>
        <td>火</td>
        <td>水</td>
        <td>木</td>
        <td>金</td>
        <td>土</td>
      </tr>
      <?php echo $body ?>
    </tbody>
    <tfoot>
      <tr class="calendar-row">
        <th colspan="7"><a href="./calendar02.php">today</a></th>
      </tr>
    </tfoot>
  </table>
</body>
</html>

追加部分や修正部分にはコメントを入れています。

コードは前回の「PHPでカレンダーを作ってみる①」で作成したものと、ほとんど同じなので追加部分や変更部分に絞って説明をしていきます。

追加部分について

/*---------------------------------------------------
追加部分
----------------------------------------------------*/
if(isset($_GET['t']) && preg_match('/\A\d{4}-\d{2}\z/', $_GET['t'])) {
  //クエリ情報を基にしてDateTimeインスタンスを作成
  $start_day = new DateTime($_GET['t'] . '-01');
} else {
  //当月初日のDateTimeインスタンスを作成
  $start_day = new DateTime('first day of this month');
}

//カレンダー表示月の前月の年月を取得
$dt = clone($start_day);
$prev_month =  $dt->modify('-1 month')->format('Y-m');

//カレンダー表示月の翌月の年月を取得
$dt = clone($start_day);
$next_month =  $dt->modify('+1 month')->format('Y-m');

「PHPでカレンダーを作ってみる①」では当月分のカレンダーだけを作ったので当月のDateTimeインスタンスを作成すればOKでした。

でも任意の月のカレンダーを作成するためには、クエリ情報に応じたDateTimeインスタンスを作成する必要があります。

ですので追加部分では、クエリ情報がある場合にはそのクエリ情報に基づいた年月のDateTimeインスタンスを作成するようにしています。

クエリ情報がない場合またはクエリ情報があっても「西暦-月」の正規表現に一致しない場合は当月初日のDateTimeインスタンスを作成するようにしています。

そして$start_dayのオブジェクトのクローンを作って、表示月の前月と翌月のDateTimeオブジェクトを作成し、その「年月」を取得しておきます。

この取得した前月と翌月の年月を、カレンダーのリンクのhref属性においてクエリ情報として利用します。

修正部分について

/*---------------------------------------------------
修正部分
----------------------------------------------------*/
//表示月末日のDateTimeインスタンスを作成
$end_day = new DateTime('last day of ' . $year_month);

「PHPでカレンダーを作ってみる①」では当月分のカレンダーだけを作ったので、末日のDateTimeインスタンスの作成コードは

$end_day = new DateTime('last day of this month');

となっていました。

でも今回作成するカレンダーは表示月が当月とは限らないため、表示月に応じた月末のDateTimeオブジェクトを作成するために

$end_day = new DateTime('last day of ' . $year_month);

としました。

$year_monthにはカレンダー表示月の「年-月」が代入されているので、これによりカレンダー表示月の末日のDateTimeオブジェクトが作成できます。

HTML部分の変更

<!-- リンクにクエリ情報を設定する -->
<th><a href="?t=<?php echo $prev_month ?>">&laquo;</a></th>
<th colspan="5"><a href=""><?php echo $year_month ?></a></th>
<th><a href="?t=<?php echo $next_month ?>">&raquo;</a></th>

「PHPでカレンダーを作ってみる①」ではカレンダーの先月、前月のリンクには具体的なリンク先を設定していませんでした。

今回はリンクをクリックしたら前月、来月のカレンダーが表示ができるように、href属性にカレンダー表示月の前月や翌月に該当するクエリ情報を設定しています。

CSS

CSSは「PHPでカレンダーを作ってみる①」と同じなので省略します。

デモページ

下記のリンクは今回作成したカレンダーのデモページです。

デモページ

カレンダーの見出しの両横にある「<<」や「>>」のリンクをクリックすると前月または翌月のカレンダーが表示されます。

次回は祝日の判定を行います

「PHPでカレンダーを作ってみる①」では当月分のカレンダーを作成しました。

そして今回はリンクをクリックすると前月や翌月のカレンダーが表示されるカレンダーを作成しました。

これまで作成したカレンダーには祝日の表示がありません。

というわけで、次回はカレンダーの各日付について祝日の判定を行い、祝日だった場合にはほかの日付とは見た目を変えるようにしていきたいと思います。

ゆんつ
それでは、またー