30
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel5でメンテナンス画面を実装する

Last updated at Posted at 2016-10-19

はじめに

メンテナンスモードを即時実行
resources/views/errors/503.blade.php の内容を表示する

php artisan down

メンテナンスモードを即時解除

php artisan up

以下の手順をする際、手違いでメンテナンスモードになったらupしてください

要件

  • 管理画面でメンテナンス画面に切り替えれるスイッチをつける
  • オンにすると全ページで503ページが表示される
  • ただし、許可したIPアドレスからのアクセスのみ、オンにしていても全ページが通常通り表示される
  • 管理画面でメンテナンス画面に表示するメッセージを入力できる
  • 入力した内容はメンテナンス画面で表示される

実装

必要ファイルの用意
touch resources/views/admin/maintenance/index.blade.php
php artisan make:controller MaintenanceController
php artisan make:model Maintenance
php artisan make:migrate create_maintenances
php artisan make:middleware CheckForMaintenanceMode
ルーティング
app/Http/routes.php
Route::resource('maintenance', 'MaintenanceController', ['only' => ['index', 'store']]);
View

※ここではLaravelCollectiveを使用しています。
使用していない場合はふつうにHTMLの書き方でformタグとか書いていけばいいです。
やってるのはラジオボタンとテキストエリアの作成です。

resources/views/admin/maintenance/index.blade.php
{{ Form::open(['url' => route('admin.maintenance.store')]) }}
{{ Form::radio('mode', 1, $maintenance->mode, ['class' => 'maintenance', 'id' => 'mode_1']) }}
{{ Form::label('mode_1', 'オン') !!}
{{ Form::radio('mode', 0, !$maintenance->mode, ['class' => 'maintenance', 'id' => 'mode_0']) }}
{{ Form::label('mode_0', 'オフ') !!}
@if($errors -> maintenance -> has('mode'))
{{ $errors -> maintenance -> first('mode') }}
@endif
{{ Form::textarea('body', $maintenance -> body, ['class' => 'maintenance', 'id' => 'body']) }}
@if($errors -> maintenance -> has('body'))
{{ $errors -> maintenance -> first('body') }}
@endif
{{ Form::submit('設定') }}
{{ Form::close() }}

普通にLaravelを構築してたら最初から503のViewファイルがあるはずです。なかったら作って

resources/views/errors/503.blade.php
<h1>メンテナンス中</h1>
<p>{!! nl2br($maintenance -> body) !!}</p>
Controller
app/Http/Controllers/MaintenanceController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Maintenance;

class MaintenanceController extends Controller
{
    public function index() {
        if(count(Maintenance::all()) == 0) {
            $maintenance = new Maintenance();
        }
        else {
            $maintenance = Maintenance::orderBy('updated_at','desc')->first();
        }

        $this -> mode();

        return view('admin.maintenance.index')->with(['maintenance' => $maintenance]);
    }

    public function store(Request $request)
    {
        if(count(Maintenance::all()) == 0) {
        	$maintenance = new Maintenance();
        }
        else {
        	$maintenance = Maintenance::orderBy('updated_at','desc')->first();
        }

        $rules = [
            'mode' => 'required|boolean',
            'body' => 'required|string',
        ];

        $validator = \Validator::make($request->all(), $rules);
        if ($validator->fails()) {
            return back()->withErrors($validator,'maintenance');
        }

        $maintenance -> mode = $request -> mode;
        $maintenance -> body = $request -> body;
        $maintenance -> save();
        return redirect()->back();
    }

    public function mode()
    {
        $maintenance = Maintenance::orderBy('updated_at','desc')->first();

        if($maintenance -> mode == 1){
            return \Artisan::call('down');
        }
        else {
            return \Artisan::call('up');
        }
    }
}
Model

app/Maintenance.php

何もしない

Migrate
database/migrations/2016_10_19_100000_create_maintenances.php
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateMaintenances extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('maintenances', function($table) {
            $table->increments('id');
            $table->boolean('mode');
            $table->text('body');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('maintenances');
    }
}

DBにテーブル情報を登録

php artisan migrate
Middleware

ここを参考にしました。
http://www.larajapan.com/2016/01/10/%E3%83%A1%E3%83%B3%E3%83%86%E3%83%8A%E3%83%B3%E3%82%B9%E7%94%BB%E9%9D%A2%E3%81%AE%E8%A3%8F%E5%8F%A3/

app/Http/Middleware/CheckForMaintenanceMode.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Foundation\Application;
use Symfony\Component\HttpKernel\Exception\HttpException;

class CheckForMaintenanceMode
{
    /**
     * The application implementation.
     *
     * @var \Illuminate\Contracts\Foundation\Application
     */
    protected $app;
    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
    }
 
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $allow = ['***.***.***.***']; // ここにアクセス許可したいIPアドレスを書く。複数の場合は['hoge','hoge']のように区切る

        if ($this->app->isDownForMaintenance()) {
            if (!in_array($request->getClientIp(), $allow)) {
                throw new HttpException(503);
            }
        }
 
        return $next($request);
    }
}
Kernel
app/Http/Kernel.php
    protected $middleware = [
        \App\Http\Middleware\CheckForMaintenanceMode::class,
    ];
503画面に変数を持たせる

404画面や503画面などの例外処理のページは、Controllerでwithメソッドで
どうこうするみたいなやり方で変数を渡すことができません。(やり方あったら教えてください)

これらの例外処理のページは以下のやり方で変数を持たせることができます。

これを参考にしました。
http://stackoverflow.com/questions/39217513/how-to-pass-variables-to-http-error-layouts-in-laravel

app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        view()->composer('errors.503', function($view)
        {
            $maintenance = \App\Maintenance::orderBy('updated_at','desc')->first();

            $view->with(['maintenance' => $maintenance]);
        });
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

おわり

おわり

おまけ

上記のやり方でメンテナンス画面の実装は完了しましたが、
許可したIPアドレスでは503ページが表示されない仕様なので、
実際にユーザーから503ページがどのように見えてるかが確認できません。
なので、503ページのプレビュー機能を追加します。

ルーティングを修正
app/Http/routes.php
Route::resource('maintenance', 'MaintenanceController', ['only' => ['index', 'store']]);
Route::get('maintenance/preview', function(){
    return view('errors.503');
});
Viewを修正

これをどっか適当なところに入れてください。これで終わり。簡単ですね

resources/views/admin/maintenance/index.blade.php
<a href="/admin/maintenance/preview" target="_blank">プレビュー</a>
30
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?