laravel4を使ったアプリケーション配布時の工夫

再び3回目の登場です。

ぼちぼち日本語情報も多くなってきましたので、
laravel4を採用して構築している企業や個人の方も多いのではないでしょうか？(すてき！)

アプリケーションをパッケージにして配布したい時に、
是非組込みたいものがあります。

##migrate
laravel4はDBのセットアップも全てフレームワークがやってくれます。
それをコマンドから実行ではなく、
アプリケーションの中にセットアップ項目として取り込みます、というサンプルです。
**ただし、先にDBとユーザー名、パスワードは作ってください！** (4.1で追加された機能でできたりするのかな？)


まずmigrationsを作っていきます
ファイル名はテーブル名になります。
configuresという設定用テーブルを作るとします

```php:app/database/migrations/YYYY_MM_DD_123456_configures.php
use Illuminate\Database\Migrations\Migration;

class Configures extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		//
		//create
		Schema::create('configures', function($table)
		{
			$table->increments('configure_id');
			$table->string('configure_name', 255);
			$table->text('configure_value');
			$table->timestamps();
			$table->index('configure_name');
		});
	}

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
		//
	}
}

```

定義は上記の様に指定したとします。
routesも作ってしまいます

```php:app/routes.php
Route::get('/setup', 'SetUpController@getSetup');
Route::get('/setup/start', 'SetUpController@getSetupStart');
```

セットアップ確認画面とセットアップ実行的なものをつくっておきましょう
最初はもちろんテーブル自体が存在しない為エラーになります。
とりあえずexception extendsします

```php:適当なところ/DatabaseConfigException.php
class DatabaseConfigException extends \Exception{}
```

それではいざ実装！
大体みなさんDBだと思いますが、色んなパターンがあり得るでしょう！
より実務的にinterfaceから実装していきます。
場所はどこでも構いません。
例えばロジックはmodelsにまとめるのであれば・・

##interface
```php:app/models/Interfaces/DatastoreInterface.php
namespace Model\Interfaces;
interface DatastoreInterface {
	
	public function get();
}
```

##model
```php:app/models/DbMigrate.php
namespace Model;
use Illuminate\Support\Facades\DB;

class DbMigrate implements Interfaces\DatastoreInterface
{
	public function get()
	{
		try{
			// 
			return DB::connection()->table('configures')->get();

		}catch(\Exception $e){
			// configureテーブルが見つからない場合にthrow
			if(strpos($e->getMessage(), 'SQLSTATE[42S02]') !== false)
			{
				throw new \Extensions\DatabaseConfigException('configures data not found', 900);
			}
		}
	}
}
```

configuresテーブルが無ければ、アプリケーションに必要なテーブルが無い！
と扱います。

とりあえずmysql向けにしましたが、
アプリケーション利用者が必ずしもmysqlとは限らないはずなので、
他のdbの場合はimplementsして同じ様に実装してもらえればいいでしょう

##controller実装
```php:SetupController.php
use Illuminate\Support\Facades\Artisan;
class SetupController extends BaseController {

	private $_datastore;
	
	public function __construct(Model\Interfaces\DatastoreInterface $data)
	{
		$this->_datastore = $data;
	}
	
	public function getSetup()
	{
		try { 
			$this->_datastore->get();
		
		}catch(\Extensions\DatabaseConfigException $e){
			
			$configure = Config::get('database');
			$data = [
				'default' => $configure['default'],
				'connections' => $configure['connections'][$configure['default']]
			];
			var_dump($data);
			var_dump(app_path() ."/config/". app()->environment() . "/database.php");
		}
	}
	
	/**
	 * 
	 */
	public function getSetupStart()
	{
		Artisan::call('migrate');

	}
}
```

DBが存在しない場合は、exceptionを投げてきますので、
catchして現在の環境を表示してみました。
database 1台環境のソースですので
databaseを複数使用されている場合は、driverとdefaultから見つけてあげましょう
環境ファイルのパスは恐らくそこにあるでしょう、ということで
利用者にそこのファイル内容を変更してくださいと促してみましょう。

完了後に/setup/startに遷移すれば、migrateが実行される様にしました。
コマンドが苦手なユーザーも、これで安心です

もちろん、このままではエラーですので、
**App::bind('Model\Interfaces\DatastoreInterface', 'Model\DbMigrate');**
を忘れずに！

という実装は如何でしょうか？\
明日は、websocket+redis pub/sub + laravel4です