はじめに
メンテナンスモードを即時実行
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
ルーティング
Route::resource('maintenance', 'MaintenanceController', ['only' => ['index', 'store']]);
View
※ここではLaravelCollectiveを使用しています。
使用していない場合はふつうにHTMLの書き方でformタグとか書いていけばいいです。
やってるのはラジオボタンとテキストエリアの作成です。
{{ 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ファイルがあるはずです。なかったら作って
<h1>メンテナンス中</h1>
<p>{!! nl2br($maintenance -> body) !!}</p>
Controller
<?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
<?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
<?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
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
<?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ページのプレビュー機能を追加します。
ルーティングを修正
Route::resource('maintenance', 'MaintenanceController', ['only' => ['index', 'store']]);
Route::get('maintenance/preview', function(){
return view('errors.503');
});
Viewを修正
これをどっか適当なところに入れてください。これで終わり。簡単ですね
<a href="/admin/maintenance/preview" target="_blank">プレビュー</a>