Laravel でWebアプリのインストーラーを作ってみる
このエントリはLaravel Advent Calendar 2013の23日目の記事です。
実はパッケージを作った話をしようと思ったのですが、死ぬほど地味で Laravel ほとんど関係なくなった*1ので別のネタで。
20日目でこんな記事がありました。
laravel4を使ったアプリケーション配布時の工夫 - Qiita [キータ]
これをもうちょっとカジュアルにLaravelっぽくやってみようという試みです。WordPress のインストーラーを思い浮かべると処理としては大体以下のような感じ。
- インストールされているかチェック
- DB につながっているかつ、テーブルが作成されていればインストール済みとみなす
- インストール画面から接続情報を取得して DB に接続できるように設定ファイルを書き換える
- DB に繋がったらマイグレーションファイルからテーブルを作成
- シーダーから初期データをインポート
みたいな感じになると思います。
では、まずインストールされているかどうかのチェックを行いましょう。これは routes.php
よりは filters.php
に書くほうがいいでしょう。
<?php App::before(function($request) { // パスチェック. インストール時はチェックしない if (strpos($request->path(), 'install') !== false) { return; } $installed = false; try { // データベースにつながるならOK // あるいはインストール後に設定ファイルに書き込んで // それをチェックするのもありかも $connection = DB::connection(); $connection->table('posts'); $installed = true; } catch (Exception $exc) { return Redirect::to('install'); } });
Laravel の場合、コネクションが取得できなかった場合、例外が発生しますので catch 節に達した場合は install にリダイレクトします。ここにインストール画面を表示させます。
<?php Route::get('install', function() { return View::make('install'); });
インストール画面はこんなかんじで
<!DOCTYPE HTML> <html lang="ja-JP"> <head> <title>install</title> <meta charset="UTF-8"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> <style type="text/css" media="screen"> .container { max-width: 400px; } </style> </head> <body> <div class="container"> <div class="page-header"> <h1>install</h1> <?= Form::open(['url' => 'install/execute']) ?> <div class="form-group"> <label for="db">DB</label> <select id="db" name="db" class="form-control"> <option value="mysql">MySQL</option> <option value="pgsql">PostgreSQL</option> <option value="sqlite">SQLite</option> <option value="sqlsrv">SQLServer</option> </select> </div> <div class="form-group"> <label for="host">HOST</label> <input type="text" id="host" name="host" class="form-control" value="<?= Input::old('host') ?>" /> </div> <div class="form-group"> <label for="database">DB</label> <input type="text" id="database" name="database" class="form-control" value="<?= Input::old('database') ?>" /> </div> <div class="form-group"> <label for="username">UserName</label> <input type="text" id="username" name="username" class="form-control" value="<?= Input::old('username') ?>" /> </div> <div class="form-group"> <label for="password">Password</label> <input type="password" id="password" name="password" class="form-control" value="" /> </div> <div class="form-group"> <input type="submit" class="btn btn-primary" value="Submit" /> </div> <?= Form::close() ?> </div> </div> </body> </html>
で、ここからが本処理。やることは
です。設定ファイルの書き換えはvar_export 関数を使って設定ファイルを書き換えてみる - localdiskを参考にしてください。今回の肝は Artisan::call
を使用して SQL ファイルを用意することなくちゃちゃっとデータを整えちゃおうというところです。ここまで長かった…。
<?php Route::post('install/execute', function() { $rules = [ 'db' => 'required', 'host' => 'required', 'database' => 'required', 'username' => 'required', 'password' => 'required' ]; $val = Validator::make(Input::all(), $rules); if ($val->fails()) { return Redirect::back()->withInput()->withErrors($val); } // 設定ファイルを書き換える $config = Config::get('database'); $config['default'] = Input::get('db'); $config['connections'][Input::get('db')]['host'] = Input::get('host'); $config['connections'][Input::get('db')]['database'] = Input::get('database'); $config['connections'][Input::get('db')]['username'] = Input::get('username'); $config['connections'][Input::get('db')]['password'] = Input::get('password'); $file = '<?php' . "\n" . var_export($config, true) . ';'; File::put(app_path('config') . '/database.php', $file); try { // マイグレーション Artisan::call('migrate:install'); // マイグレーション導入 Artisan::call('migrate'); // マイグレーション実行 // 初期データ投入 Artisan::call('db:seed'); } catch (Exception $e) { return Response::make($e->getMessage(), 500); } return View::make('install/complete'); });
まとめ
作りがすごい甘かったり、ちゃんと動かしてないコードですがおおよその流れは掴めたかと思います。年内にはちゃんと書いて github にあげておきます。
*1:ServiceProvider と Facade 作るだけ