好みのライブラリに入れ替える(DB編

Laravelはデフォルトで様々コンポーネントが用意されていますが、
それらのほとんどはユーザーの好みによって好きなものに入れ替える事が出来ます。

中には入れ替えるのに若干難易度が高いものもありますが(routerとか)、
基本的には自由に組み合わせる事が出来ます。
入れ替えについてはあまり記述を見かけないと思いますので、
ここではDBファサードを通じて利用されている
**illuminate/database(Eloquent, クエリービルダー, basic)** を
**doctrine/dbal** に変更してみます

Laravelの内部までソースを追っている方はだいたい分かると思いますが、
変更してもデフォルトで用意されてるものを継承して、
使うライブラリに併せて少しだけ変更する程度ですのでビビらずに好きなものに変えてしまいましょう

まずは **doctrine/dbal** を入れます

```json:composer.json
"require": {
    "php": ">=5.4.0",
    "laravel/framework": "4.2.*",
    "doctrine/dbal": "2.*"
}
```
次に **doctrine/dbal** を利用するクラスを用意しましょう
サービスプロバイダーの仕組みを理解しましょう！
アプリケーション起動時にこれらのサービスプロバイダーが読み込まれてから、
それぞれのコードが実行されます
フレームワークの実装コードを見れば分かりますが、db関連はregisterで登録されます

```php:Illuminate\Database\DatabaseServiceProvider
    public function register()
    {
        $this->app->bindShared('db.factory', function($app) {
                return new ConnectionFactory($app);
            }
        );

        $this->app->bindShared('db', function($app) {
                return new DatabaseManager($app, $app['db.factory']);
            }
        );
    }
```

bindShareはLaravelのコンテナライブラリである **illuminate/container** で実装されている機能です
bindと同じ様にコンテナに登録する名前を指定し、
実行時に作られたインスタンスはコンテナがそのまま保持して、同じインスタンスを返します
(static $object;)

では同じ様に実装してみます

```php
namespace App\Providers;

use App\Database\Manager as DB;
use Illuminate\Support\ServiceProvider;

class ApplicationServiceProvider extends ServiceProvider
{
    /**
     * doctrine/dbal register
     * @return void
     */
    public function register()
    {
        $this->app->bindShared('dbal', function($app) {
                return new DB($app['config']);
            }
        );
    }
}
```

こんな感じになります。
今回はとりあえずコンテナに登録されている'db'はそのままに、
新しく'dbal'として登録します
return で返却されるものは **doctrine/dbal** のインスタンスを返すクラスです

```php
$this->app;
```
は **\Illuminate\Foundation\Application** インスタンスで、
コンテナを継承しています。
それぞれのコンポーネントはコンテナにそれぞれ名前が付けられて登録されています
[コンテナに登録されてる名前リスト](http://laravel.com/docs/4.2/facades#facade-class-reference)
コンフィグ関連はconfigの **Illuminate\Config\Repository** を利用します
コンテナはArrayAccessが利用されていますので、
配列でもオブジェクトでもどちらでもいいです。お好みでどうぞ

**doctrine/dbal** のインスタンスを返すクラスは下記の様に実装してみます

```php
namespace App\Database;

use Doctrine\DBAL\DriverManager;
use Illuminate\Config\Repository;

class Manager
{

    /** @var Repository  */
    protected $config;

    /**
     * @param Repository $config
     */
    public function __construct(Repository $config)
    {
        $this->config = $config;
    }

    /**
     * @param null $name
     * @return \Doctrine\DBAL\Connection
     * @throws \Doctrine\DBAL\DBALException
     */
    public function connection($name = null)
    {
        $configure = $this->config->get('database');
        $connection = DriverManager::getConnection($configure['connections'][$name]);
        $connection->setFetchMode($configure['fetch']);
        return $connection;
    }
} 
```
**Illuminate\Config\Repository** をタイプヒントで指定します。
Laravel4系の場合はこの様になりますが、次期バーションの5はより拡張性が強化されていますので、
コンストラクタにタイプヒントする場合は、contractsをタイプヒントで指定します
5から利用できます(現時点ではまだdevelopのみ)

```php
public function __construct(\Illuminate\Contracts\Config\Repository $config)
{
    $this->config = $config;
}
```
独自のものや好みのものに簡単に自由自在に変更できる様になります
connectionは接続先をかえるためのメソッドです
これでコンテナから'dbal'でいつでも利用できる準備が整いました
これがLaravelのFacade(デザインパターンのProxy)となります
そこにアクセスするためのコードを追加します

```php
namespace App\Database;

use Illuminate\Support\Facades\Facade;

class DatabaseFacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'dbal';
    }
}
```

これでアクセスもバッチリ！
あとはDBファサードの指定をこれに変更するだけです。

```php:app.php
    'aliases' => [
        //'DB' => 'Illuminate\Support\Facades\DB',
        'DB' => 'App\Database\DatabaseFacade',
        // 続く
    ],
```
今回はDBのみを変更したので、migrateなどもそのまま利用できる状態で、
ユーザーが実装するコードのみが影響されます
これでユーザーが実装する場合に **doctrine/dbal** が利用できる様になります

```php
$result = \DB::connection('dbal_mysql')->fetchAll("SELECT NOW() as now");
```

この様な感じでそれぞれの好きなものに入れ替える事が出来ます
使い辛いなと感じるものがあれば入れ替えて自分好みにカスタマイズしてしまいましょう！
登録されている名前との関連を学習すると、
よりテストし易いコードになりますのでオススメです