PHP
CentOS
PostgreSQL
laravel5
laravel5.2

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

More than 1 year has passed since last update.


はじめに

メンテナンスモードを即時実行

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>