【Laravel】特定の期間だけ終日メンテナンスモードにする

8月に入りいよいよ暑さのピークも迎えてきました。
それと同時に、そろそろ夏休みに入り始める時期でしょうか?
それに付随して、システムもお休みにする事があるかもしれません。

さて、 今回は、特定の期間だけサイトの表示を切り替える方法を記載します。

設定条件

  • 8/1から8/20までの間、サイトを訪れた時にメンテナンスページ(503)を表示 。
  • 通常のメンテナンスページの内容を一部変更して、特殊なメッセージを表示する。
    • 停止期間をテキストで表示します。
  • 既に登録されている、定時メンテナンスのスケジュールの機能は削除しない(一時的も無し)

MiddleWareを作成

ページを表示させる前に必ず実行させたいので、現在日時を評価するためのミドルウェアを作成します。 ミドルウェア名は、適当にCloseSiteとします。

$ php artisan make:middleware CloseSite

実行すると、app/Http/Middleware/CloseSite.phpが出来ます。

処理内容

期間の判定と、メンテンナンス画面に変数を渡す処理を記述します。
また、この機能は冬季休業や、長期メンテナンスの時など別の時にも使えそうなので、日時やページに表示する文言のような動的要素は外部ファイルにします。

コンフィグファイルの作成

前述したように、動的要素を外部ファイル化します。
外部ファイルは、app/config配下にコンフィグファイルとして設置します。

app/config/closesite.php

<?php

return [
    'date' => [
        'start' => '2018-08-06',
        'end' => '2018-08-20'
    ],
    'messageTitleFormat' => 'システム停止',                                       
    'messageBody' => '%s~%sの間はシステム停止中です。'
];

CloseSiteミドルウェアの設定

ミドルウェアの設定は以下のように記述します。

<?php

namespace App\Http\Middleware;

use Closure;
use Carbon\Carbon;    // 日時比較を行うのでCarbonクラスを追加

class CloseSite
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        // 先ほど作成したコンフィグファイルを取得
        $config = \Config::get('closesite');

        // 指定した日付をCarbon型変更します。
        $start = Carbon::parse($config['date']['start']);       // 2018-08-01 00:00:00として扱われます
        $end = Carbon::parse($config['date']['end']);         // 2018-08-20 00:00:00として扱われます

        // 期間判定をします。  
        // 終了日は、このままだと当時の0時として扱われてしまうため終日として扱えません。   
        // addDay()で次の日を指定します。
        if((new Carbon())->between($start, $end->addDay())){

            // ビューに追加する配列を定義します。
            //
            // それぞれ、下記のような用途で使用します。
            // messageTitle: タイトルに使用
            // messageBody: 本文に使用
            $maintenanceSubstitute = [
                'messageTitle' => sprintf($config['messageTitleFormat'],
                    $start->format('n月j日'),
                    $end->subDay()->format('n月j日')      // 先ほど、addDayを行ったため内部的には1日増えた状態です。そのため、1日減らします。
                ),
                'messageBody' => $config['messageBody']
            ];

            // Viewに変数を流し込みます。 
            // View::share()を行うと、以降どのViewを読み込んだとしても指定した変数を使用できるようになります。
            \View::share(
                'maintenanceSubstitute',
                $maintenanceSubstitute
            );

            // 503ページにリダイレクトします。
            abort(503);
        }
        
        // 次の処理に移動
        return $next($request);
    }
}

503ページをはじめとしたエラーページには、viewに直接変数を渡すことが出来ません。
そのため、あらかじめView::share()で全てのビューに変数を共有します。

ビュー 5.3 Laravel

Viewを用意

メンテナンスモードで表示されるページはHTTPステータスコードの503に当たります。
そのため、viewディレクトリに503.blade.phpを追加します。

共有した変数を利用する記述を記載します。 通常のメンテナンスと共存できるようにする前提ですので、下記のように設定します。

      <h2>
        @if(isset($maintenanceSubstitute['messageTitle']) 
            && $maintenanceSubstitute['messageTitle'] != '')
            {{$maintenanceSubstitute['messageTitle']}}
        @else
        ただいまメンテナンス中です。
        @endif
      </h2>
      <p>
        @if(isset($maintenanceSubstitute['messageBody']) 
            && $maintenanceSubstitute['messageBody'] != '')
            {{$maintenanceSubstitute['messageBody']}}
        @else
        大変申し訳ありません。メンテナンス中です。<br>
        恐れ入りますが、しばらく置いてから再度お試しください。
        @endif
      </p>

Karnelに登録する

middlewareを追加したので、Karnelに追加します。

app/Http/Kernel.php

// 省略
    protected $routeMiddleware = [
        'closeSite' => \App\Http\Middleware\CloseSite::class
    ];

Routeに登録する

カーネルに追加したミドルウェア名で、対象のミドルウェアを呼び出します。
ルート一軒一軒にミドルウェアを指定してもよいですが、全ページに対象ですので下記のようにRoute::group()に追加します。

Route::group([
     'middleware' => [
         'closeSite'
     ]
 ], function(){
     // 対象ルート
}


以上で、特定の日時だけメンテナスページを出せるようになりました。