ytake Hatena

Web Application Developer

Laravel データベース拡張のヒント

これは Laravelリファレンス発売記念、販売促進アドベントカレンダー www.adventar.org の2015年12月16日分です。

データベース拡張

開発時に、Laravelがサポートしていないデータベースを使う必要がある場合や、
クエリビルダなどの挙動を変えたい場合があるかもしれません。

サポートしていないデータベースを使うためのパッケージやライブラリは、
packagitやpackalyst、GitHubなどでも簡単に見つけることができます。

ここではこうしたライブラリ開発や、特定の要件を満たせるように拡張する方法を紹介します。

データベースドライバを追加する場合

Illuminate\Database\Connectionクラスを継承して、対応するコネクションクラスを作成します。
Illuminate\Database\ConnectionInterfaceインターフェースを実装して、クラスを独自に作成してもかまいません。

継承したクラスは、サービスプロバイダなどで次のように記述します。

/**
 * {@inheritdoc}
 */
public function register()
{
    // add couchbase extension
    $this->app['db']->extend('couchbase', function ($config) {
        /** @var \CouchbaseCluster $cluster */
        return new CouchbaseConnection($config);
    });
}

上記の例ではcouchbaseという名前のデータベースドライバを追加する、という処理になります。
それぞれの処理に合わせて各メソッドをオーバーライドしていきましょう。

insert

insertの挙動を変えたい場合は、内部でコールされているstatementメソッドを変更します。

public function statement($query, $bindings = [])

update, deleteなど

insert同様に、これらは内部でaffectingStatementが利用されています。

public function affectingStatement($query, $bindings = [])

selectはselectのままです。

クエリビルダの拡張

クエリビルダのSQLや、独自の機能を持たせたい場合があるかもしれません。
この場合はドライバに対応するProcessor,Grammerクラスを作成します。
queryメソッドをオーバーライドします。

    /**
     * Get a new query builder instance.
     *
     * @return \Illuminate\Database\Query\Builder
     */
    public function query()
    {
        return new QueryBuilder(
            $this, $this->getQueryGrammar(), $this->getPostProcessor()
        );
    }

$this->getQueryGrammar()$this->getPostProcessor()
データベースに対応したクラスのインスタンスが取得されるようにしておきましょう。

クエリビルダは、Grammerクラスを継承して動作を変えることができます。
クエリビルダは内部でcompileXXXXというメソッドがコールされ、
SQLがビルドされていきます。

たとえば、例に挙げたcouchbaseに対応させるため、
このデータベースがもつ独自のupsertをクエリビルダで実装する場合は、 次のようになります。

    /**
     * supported N1QL upsert query
     *
     * @param Builder $query
     * @param array   $values
     *
     * @return string
     */
    public function compileUpsert(Builder $query, array $values)
    {
        $table = $this->wrapTable($query->from);

        if (!is_array(reset($values))) {
            $values = [$values];
        }

        $columns = $this->columnize(array_keys(reset($values)));

        $parameters = [];

        foreach ($values as $record) {
            $parameters[] = '(' . $this->parameterize($record) . ')';
        }

        $parameters = implode(', ', $parameters);

        return "UPSERT into $table ($columns) values $parameters RETURNING *";
    }

こうすることで簡単にクエリビルダメソッドが追加できます。

同じ要領でバッククォートを外すなど、オーバーライドするだけで、
フレームワーク本体に手を加えることなく簡単にドライバ追加、または挙動変更が行えます。

データベースの基本は、Laravelリファレンスでも解説しています。

Laravel リファレンス[Ver.5.1 LTS 対応] Web職人好みの新世代PHPフレームワーク