ytake Hatena

Web Application Developer

Lumen with Aspect

Lumen使ってますか?

APIなどのセッションや、テンプレートを必要としないアプリケーションには、
Laravelのマイクロフレームワーク版でもあるLumenを選択する方も多いのではないでしょうか。

このフレームワークはLaravelと同様にファサードを使うかどうかの選択が可能で、
もちろん一切使わず、Packagistなどで公開されているライブラリをデータベースに利用したりと
変更することも容易です。(現在でしたら、組み替えのしやすさではzend-expressiveの方が軍配があがるでしょう。)
ファサードを利用しない場合の利用方法は過去のエントリを参考にしてください。

ytake.hateblo.jp

ちょっとの工夫

手軽なアプリケーションでもトランザクションや、キャッシュ、ログなどいろんなものを記述することが多いでしょう。
そんな場合に、拙作のLaravel向けのパッケージではありますが、
アスペクトを取り入れることができます。

github.com

install

そのままです

    "require": {
        "php": ">=5.5.9",
        "laravel/lumen-framework": "5.2.*",
        "vlucas/phpdotenv": "~2.2",
        "ytake/laravel-fluent-logger": "~1.0",
        "ytake/laravel-aspect": "~1.0"
    },

install後に、vendor/ytake/laravel-aspect/src/config/ytake-laravel-aop.phpファイルを
プロジェクト配下にconfigディレクトリを作成して設置します。
Lumenのconfigファイル設置と同じです。

register ServiceProvider

パッケージのサービスプロバイダそのままでは、Laravelを前提としているので動きません。
Lumen用に継承して下記の通りに変更します。

<?php

namespace App\Providers;

use Ytake\LaravelAspect\AspectManager;
use Ytake\LaravelAspect\AnnotationManager;
use Ytake\LaravelAspect\AspectServiceProvider as Aspect;


/**
 * Class AspectServiceProvider
 */
class AspectServiceProvider extends Aspect
{
    /**
     * @return void
     */
    public function boot()
    {

    }

    /**
     * {@inheritdoc}
     */
    public function register()
    {
        /**
         * for package configure
         */
        $this->app->configure('ytake-laravel-aop');
        $this->app->singleton('aspect.annotation.reader', function ($app) {
            return (new AnnotationManager($app))->getReader();
        });
        $this->app->singleton('aspect.manager', function ($app) {
            // register annotation
            return new AspectManager($app);
        });
    }
}

次にbootstrap/app.phpにこのサービスプロバイダと、パッケージのartisanコマンドのサービスプロバイダを追加します。

<?php
// 省略
$app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AspectServiceProvider::class);
$app->register(Ytake\LaravelAspect\ConsoleServiceProvider::class);

$app->group(['namespace' => 'App\Http\Controllers'], function ($app) {
    require __DIR__.'/../app/Http/routes.php';
});

return $app;

php artisanコマンドでパッケージのコマンドが追加されているはずです。
php artisan ytake:aspect-module-publishでパッケージがサポートしているアスペクトのモジュールを設置できますが、
Lumenでは動かないためプロジェクト内で継承して利用します。
ここでは例としてCacheを作成する @Cacheable を取り上げましょう。
利用するキャッシュは通常のファイルを指定しておきましょう。

@Cacheable利用手引き

app配下にModulesディレクトリを作成します(なんでも良いです)。
以下の通りにCacheableModuleクラスを作成します。

<?php

namespace App\Modules;

/**
 * Class CacheableModule
 */
class CacheableModule extends \Ytake\LaravelAspect\Modules\CacheableModule
{
    /** @var string[] */
    protected $classes = [
        
    ];
}

次にこのアスペクトを利用するクラスを用意してみましょう。

App\Repository\CustomerRepositoryInterface

インターフェースと具象クラスをバインドする場合でも正しく動きますので、
これらのクラスを作成していきましょう

<?php

namespace App\Repository;

/**
 * Interface CustomerRepositoryInterface
 */
interface CustomerRepositoryInterface
{
    /**
     * @return string[]
     */
    public function getAll();
}

App\Repository\CustomerRepository

このクラスのgetAllメソッドの戻り値をキャッシュするように、@Cacheableアノテーションを記述します。
このアノテーションではキャッシュ名、タグ、キャッシュキーに使う引数や保存時間を指定できます。
キャッシュ名を指定しなかった場合は、メソッド名をキャッシュ名として利用します。

<?php

namespace App\Repository;

use Ytake\LaravelAspect\Annotation\Cacheable;

/**
 * Class CustomerRepository
 */
class CustomerRepository implements CustomerRepositoryInterface
{
    /**
     * @var string[]
     */
    private $customers = [
        [
            'name' => 'laravel'
        ],
        [
            'name' => 'lumen'
        ],
    ];

    /**
     * @Cacheable(cacheName="customers",lifetime=20)
     * @return string[]
     */
    public function getAll()
    {
        return $this->customers;
    }
}

このクラスを利用するサービスクラスを用意して、インターフェースと具象クラスを束縛します。
サービスクラスなどを利用しない方は、
コントローラなどの任意のクラスにインターフェースをタイプヒンティングしましょう

App\Services\CustomerService

<?php

namespace App\Services;

use App\Repository\CustomerRepositoryInterface;

/**
 * Class CustomerService
 */
class CustomerService
{
    /** @var CustomerRepositoryInterface  */
    protected $customerRepository;

    /**
     * CustomerService constructor.
     *
     * @param CustomerRepositoryInterface $customerRepository
     */
    public function __construct(CustomerRepositoryInterface $customerRepository)
    {
        $this->customerRepository = $customerRepository;
    }

    /**
     * @return array|\string[]
     */
    public function getAllCustomers() : array
    {
        return $this->customerRepository->getAll();
    }
}

App\Providers\AppServiceProvider

インターフェースと利用する具象クラスを記述します

<?php

namespace App\Providers;

use App\Repository\CustomerRepository;
use App\Repository\CustomerRepositoryInterface;
use Illuminate\Support\ServiceProvider;

/**
 * Class AppServiceProvider
 */
class AppServiceProvider extends ServiceProvider
{
    /**
     * {@inheritdoc}
     */
    public function register()
    {
        $this->app->bind(CustomerRepositoryInterface::class, CustomerRepository::class);
    }
}

キャッシュなし動作

この状態でコントローラからクラスを利用します。

<?php

namespace App\Http\Controllers;

use App\Services\CustomerService;

/**
 * Class CacheController
 */
class CacheController extends Controller
{
    /** @var \App\Services\CustomerService  */
    protected $customer;

    /**
     * CacheController constructor.
     *
     * @param \App\Services\CustomerService $customer
     */
    public function __construct(CustomerService $customer)
    {
        $this->customer = $customer;
    }

    /**
     * @return \string[]
     */
    public function index()
    {
        return $this->customer->getAllCustomers();
    }
}

routes.phpに任意のURIを追加してアクセスしてもキャッシュは作成されません。
これから実装したクラスには一切手を加えず、アスペクトが作用するように動作を拡張します。

App\Modules\CacheableModule

作成したCacheableModuleにアスペクトを利用するクラスを記述します。

<?php

namespace App\Modules;

use App\Repository\CustomerRepository;

/**
 * Class CacheableModule
 */
class CacheableModule extends \Ytake\LaravelAspect\Modules\CacheableModule
{
    /** @var string[] */
    protected $classes = [
        CustomerRepository::class,
    ];
}

次に先に作成したAspectServiceProviderにこのモジュールクラスを登録します。

<?php

namespace App\Providers;

use App\Modules\CacheableModule;
use Ytake\LaravelAspect\AspectManager;
use Ytake\LaravelAspect\AnnotationManager;
use Ytake\LaravelAspect\AspectServiceProvider as Aspect;

/**
 * Class AspectServiceProvider
 */
class AspectServiceProvider extends Aspect
{
    /**
     * @return void
     */
    public function boot()
    {
        /** @var \Ytake\LaravelAspect\AspectManager $aspect */
        $aspect = $this->app['aspect.manager'];
        $aspect->register(CacheableModule::class);
        $aspect->dispatch();
    }

    /**
     * {@inheritdoc}
     */
    public function register()
    {
        /**
         * for package configure
         */
        $this->app->configure('ytake-laravel-aop');
        $this->app->singleton('aspect.annotation.reader', function ($app) {
            return (new AnnotationManager($app))->getReader();
        });
        $this->app->singleton('aspect.manager', function ($app) {
            // register annotation
            return new AspectManager($app);
        });
    }
}

コンテナに登路したaspect.managerサービスにアクセスして、アスペクトカーネルクラスに登録します。
登録が完了したら再度URIにアクセスしてみましょう。

storage/framework/cache配下にキャッシュが作成されているのが確認できると思います。
このLaravel-Aspectは様々な処理に対して横断的に処理を追加することが簡単に行えます。
ライブラリではデフォルトでCacheの追加、削除が可能なアスペクト、アノテーション
データベースのトランザクションや、ロギングといったものを用意していますので、
これらを利用してアプリケーション開発に役立ててみてください。

ytake/gardening HomesteadライクなCentOS

ytake/gardening という、
HomesteadのCentOS版みたいなものを公開中です。

laravel/homestead との違いは、
OSはUbuntu14.04ではなく、CentOS7となっています。

またwebサーバが、ApacheとNginxが切り替えて利用できるようになっています。
この環境ではデフォルトで用意していませんが、リバースプロキシなども利用できると思います。

またPHPはPHP7が標準となっており、
hhvmは3.9が利用できます。

hhvmを利用する場合は、プロジェクト直下に.hhconfigも設置されますので、
hackもすぐに利用できます。

インストール済みのものは下記の通りです。

  • Git
  • PHP 7.0(remi repository)
  • HHVM(3.9)
  • Apache(2.4.6)
  • Nginx(1.8)
  • MySQL(5.6)
  • Sqlite3
  • PostgreSQL(9.4)
  • Composer
  • Node.js (With Grunt, and Gulp)
  • Redis
  • Memcached
  • Elasticsearch
  • MongoDB
  • Java(1.8)
  • fluentd
  • Couchbase

PHPはremiリポジトリとなっていますので、アップデート時などにはremiリポジトリを指定してください。

Homesteadと利用方法はほとんど同じですが、
上記のもののうち、
MongoDB、Elasticsearch、fluentd、couchbaseはvagrant起動時にオフにするなど、
利用状況に合わせてオンオフができるようになっています。

詳しい利用方法や、設定項目はGitHubでご確認ください。
タイムゾーンは日本に設定してありますので、ほとんどなにもせずに開発環境が利用できます。

急ぎでCentOSの開発環境が必要な方でHomesteadのようなものが必要であれば、利用してみてください。

2015年ytakeまとめ

本年は特にたくさんの方とご一緒する機会が多く、
周りの環境も多く変わる一年となりました。

今年作ったもの

今年はLaravel関連のパッケージを作ることが多かった一年でした。
後悔しているパッケージの他にも自作フレームワーク作りを行い、
何度も作っては削除、作っては削除・・の繰り返しですが、
作ることで学べることがたくさんありますので、来年度も引き続き何かしら作っていこうと思っています。

Laravel.Smarty

LaravelでBladeと併用してSmartyを使用可能にするパッケージです。
海外の開発者が作った同種のパッケージは、テストコードもなく、
パッケージにSmarty自体が内包されていたり、ほとんど拡張性がないものであったりと、
実際に使う上で頭を悩ますことも多く、当時自分で利用していたものをパッケージとして切り出したのが始まりです。

このパッケージ自体は去年作ったものですが、
Smartyを根強く使い続けている海外の方からの問い合わせも多く、
テンプレートのキャッシュをファイル以外にmemcachedやredisなどにも対応させて、
色々改良を加えました。

github.com

Laravel-Aspect

これはLaravelでAOPを利用可能にするパッケージで、
文字通りMVC(Model, View, Controller)としてフレームワークを利用している方にはあまり利用する機会がないかもしれませんが、
PHPにおいてもコンポーネント指向や、設計パターンなどに注力される方も増え、
特にドメイン駆動などで利用できるアスペクトによる関心の分離などをLaravelでサポートするものです。

ドメイン駆動開発ではアスペクトは必須ではありませんが、
多くのヒントや、実際に適所に使うとさらに考え方を広めてくれると思います。
これは後述するアスペクト指向の書籍で色々考えさせられることが多かったため、
実際の開発でも利用することが多くなり、来年度も引き続き利用していこうと思っています。
個人的には自分で作ったライブラリの中で一番使っているものかもしれません。
改良点はまだ多くありますので、引き続きバージョンアップを行う予定です。

github.com

Laravel-FluentLogger

LaravelのログをFluentdと連携するためのパッケージです。
大規模開発や、ログ解析などを行うことも多くなり、
Laravel向けのパッケージもなかったのでパッケージとして切り出したものです。

LogのデフォルトをFluentdに変更することや、pushHandlerで追加なども簡単にできるようになっています。
実際の開発でも使っています。

github.com

上記のパッケージのうち、Laravel-FluentLoggerとLaravel.SmartyはともにLumenでも利用できるようになっており、
どのパッケージも最新のLaravel5.2でも利用できるようになっています。

Laravel-Couchbase

データベースのドライバ拡張と、SessionやCacheでCouchbaseを利用するパッケージです。
このデータベースがサポートしているN1QLにも対応したもので、
Laravelのクエリービルダで利用できるようにしました。

<?php 

$this->app['db']->connection('couchbase')
    ->table('testing')->key($key)
    ->returning(['*'])
    ->where('click', 'to edit')->update(
        ['click' => 'testing edit']
    );

github.com

書籍

今年は2冊執筆させていただく機会がありました。
初めての執筆でいろんなアドバイスを頂いたり、うまく進まず迷惑をかけたりなどもあり、
反省するとともに貴重な経験となり、今後の糧としていきたいと思います。

Laravelリファレンス

www.amazon.co.jp

Laravelエキスパート養成読本

www.amazon.co.jp

嬉しいことに来年も引き続き執筆させていただける機会をいただいており、
嬉しい悲鳴が続きそうです。
Laravelリファレンス執筆時に掲載から漏れたスピンオフ電子版書籍は近いうちに詳細をお伝えできるかもしれません。

発表

今年はPHP勉強会をはじめ、PHPカンファレンス福岡、PHPカンファレンスなどで発表させていただきました。
いろんな方との交流も増え、参加して学ぶことも多くあり大変有意義に過ごしました。

php開発で使うタスクランナー gulp

今のバージョンでは動かないと思いますが、一応・・

www.slideshare.net

Laravel / Lumen 次の一歩

中級者へのヒントとなるような内容を発表しました

www.slideshare.net

Laravel5.1 Release

Laravel5.1発表直前に発表したものです。

www.slideshare.net

phpspecで始めるBDD

www.slideshare.net

LaravelとMVCの先へ

www.slideshare.net

PHPデプロイツールの世界

www.slideshare.net

zend-expressiveを触ってみよう

今年の後半に発表されたzend expressiveを実際の開発に利用した時の話をまとめたものです

www.slideshare.net

後半になるにつれてLaravel以外のもに変わっていってるのも面白いところです。
執筆時期と重なっていたため、あまりLaravel関連のことを発表しませんでした。

今年できなかったもの

LaravelJp Recipe

Laravelレシピサイトの5.1、もしくは5系以降のサポートサイトが途中まで進めたにもかかわらず、
書籍執筆に注力していたため、あまり進捗がない状態となってしまいました。

recipes.laravel.jp

来年は、このレシピサイトを5系以降にも対応させるか、
Laravel学習サイトとして、初心者から中上級者向けのサイトへと変更するかを検討しているところです。
さすがに古くなってきたので何かしないと・・・

仕事、その他

今年は転職したこともあり(去年もしたではないか!)、
身の回りも大きく変わり、いろんなチャレンジができる良い環境となりました。 また、今年はPHPに加えてgolangも取り入れることになり、幾つかに導入したりしていました。

家も建ち、ローンを返済する身となりました。

まとめ

今年はいろんな方に声をかけてもらうことが多く、
なかなか応えられないこともありましたが、大変貴重な体験を多くさせていただきありがとうございました。
2016年はさらに加速させて、いろんな物事にチャレンジしていこうと思います。

2015年ありがとうございました。

Lumen活用

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

今回は書籍では取り上げていませんが、Lumenについてです。 弊社のAPIでもLumen(とgolang)を活用していたりします。

Lumenおさらい

LumenはLaravelのilluminateコンポーネントを組み合わせて構成されているフレームワークで、
マイクロフレームワークともいわれていますが、多くの機能を有していて、
通常のフレームワークと言っても差し支えないのかもしれません。

Laravelとの違いは

  • RouterはfastRouteを利用
  • configなどは必要なものしか読み込まない(コンテナから取得時に読み込まれる)
  • サービスプロバイダは単純にコンテナに登録するのみ
  • ファサードを利用するかしないか選択可
  • APP_KEY生成コマンドなし

ぐらいでしょうか。

簡単な使い方はブログに書かれている方や、公式マニュアルを見るだけで十分理解できると思います。

.env使う場合

bootstrap/app.phpで忘れずにDotenv::loadのコメントアウトを外しておきましょう。

<?php

require_once __DIR__.'/../vendor/autoload.php';

\Dotenv::load(__DIR__.'/../');

.envを利用しない場合は、Laravelと同じように $value = getenv($key); が先に動きますので、
webサーバやphp-fomなどで環境変数を利用できます。
複数台構成の場合は.envで管理するよりもサーバなどで環境変数と組み合わせた方が事故が少ないと思います。

タイムゾーン変更

アプリケーションクラスでAPP_TIMEZONEを利用していますので、
必ず利用したいタイムゾーンを.envまたはsetEnvなどで指定しておきましょう。

APP_TIMEZONE=Asia/Tokyo

アプリケーションクラス継承

アプリケーションに合わせてアプリケーションクラスを継承する場合が多いでしょう。

利用しない機能はLaravel同様に除外できます。
$availableBindingsプロパティを上書きしてコンパクトにすることができます。
Laravel同様いらないものを削除していきましょう。

ルータキャッシュ

Lumenはルータのディスパッチャを変更できますので、fastRouteのキャッシュルータに変更してみましょう。
bootstrap/app.phpなどを利用するといいでしょう。

<?php 

$app->setDispatcher(FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r) use ($app) {
    /** @var \Laravel\Lumen\Application $app */
    foreach ($app->getRoutes() as $route) {
        $r->addRoute($route['method'], $route['uri'], $route['action']);
    }
}, [
    'cacheFile' => storage_path('route.cache'),
]));

ルータにクロージャを利用している場合は利用できませんので注意しましょう。
キャッシュファイルがある場合は/app/Http/routes.phpを読み込まないようにするなどしておきましょう

artisanコマンド削除

デフォルトで用意されているコマンドを利用しない場合は、簡単に除外できます。
App\Console\Kernelクラスの$includeDefaultCommandsプロパティを利用しましょう。

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /** @var bool  */
    protected $includeDefaultCommands = false;
    
    // 省略

綺麗に書く

ファサードを使わずに、データベースなどを綺麗に利用したい場合はサービスプロバイダを利用しましょう。
簡単な例を紹介します。

<?php

namespace App\Repositories;

interface CacheRepositoryInterface
{

    /**
     * @return mixed
     */
    public function getHoge();
}
<?php

namespace App\Repositories;

use Illuminate\Cache\CacheManager;

class CacheRepository implements CacheRepositoryInterface
{
    /** @var CacheManager  */
    protected $cache;

    /**
     * CacheRepository constructor.
     *
     * @param CacheManager $cache
     */
    public function __construct(CacheManager $cache)
    {
        $this->cache = $cache;
    }

    /**
     * @return mixed
     */
    public function getHoge()
    {
        return $this->cache->driver()->get('hoge');
    }
}

Laravelではこのまま動作せることができますが、
Lumenの場合は、CacheManagerの依存を自動で解決できません。
コンテナからcacheを取得してコンフィグなどを読み込ませます。

サービスプロバイダ例

    public function register()
    {
        $this->app->bind('App\Repositories\CacheRepositoryInterface', function ($app) {
            return new CacheRepository($app->make('cache'));
        });
    }

あとは利用したいクラスなどでコンストラクタインジェクションなどを使いましょう。
LaravelでもLumenでも、どんなものでも再利用できるようになります。

Laravel services.jsonのなぞ

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

今回はLaravelに欠かせないファイル、services.jsonについて紹介します。

services.json

Laravel5.1ではbootstrap/cache配下に作成されます。
Laravel4でも存在しています。

このファイルはHttp\Kernel、またはConsole\Kernelのbootstrappersプロパティで指定されている、
Illuminate\Foundation\Bootstrap\RegisterProvidersクラスの内部で利用する、
Illuminate\Foundation\ProviderRepositoryクラスが作成します。

ファイルがない場合はcompileManifestメソッドが作成をしています。
config/app.phpのprovidersに記述されてサービスプロバイダが、配列でこのメソッドに渡され、
各サービスプロバイダのインスタンスを生成して、遅延読み込みかそうでないか、
whenによるregisterが存在するかどうかなどを調べてservices.jsonに書き込みます。

以降はこのファイルを元にフレームワークへサービスコンテナなどの登録が行われます。
このファイルがない場合はどうなるのでしょうか?

App\Http\Kernelクラスで$bootstrappersプロパティを使って上書きます。
といってもコメントアウトするだけです。

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * @var array
     */
    protected $bootstrappers = [
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        'Illuminate\Foundation\Bootstrap\HandleExceptions',
        'Illuminate\Foundation\Bootstrap\RegisterFacades',
        // 'Illuminate\Foundation\Bootstrap\RegisterProviders',
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];

    // 省略

bootstrappersプロパティ

このプロパティを利用してフレームワークの動作を独自のものに変更することもできます。
例えば.envファイルではなく他のものを利用するように変更したり、
前回紹介したファサードの削除、
設定ファイルをphpの配列ではなく別のものにしたり、ということができます。

services.jsonを利用しないように変更すると、
フレームワークデフォルトの状態のままであれば、グローバルミドルウェア通過時にクラスが解決できずに、
エラーとなります。
ミドルウェアを全てコメントアウトしてもフレームワークが依存しているクラスのインスタンスを生成できずに動作できなくなります。

このservices.jsonフレームワークの最もコアとも言えるファイルというわけです。

気をつけること

フレームワークは常にこのserivces.jsonに記述されているprovidersと、config/app.phpのprovidersの個数を比較しているため、
登録済みのサービスプロバイダの一部を遅延や、そうでないものに変更すると反映されません。
この場合はかならずphp artisan clear-compiledを実行して最新のservices.jsonを作成しましょう。

この動作さえ理解していれば、フレームワークを様々な方法で拡張することができるようになるでしょう!
(あまり実用的ではありません)

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フレームワーク

Laravel ファサードを利用しないメリット

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

必ずしも簡単 が重要ではない

Laravelを選ぶ利用の一つとして、
フレームワークが持つ豊富な機能と、
静的メソッドに見えるファサードという記法がみやすく、分かり易い!
EloquentORM
という点が挙げられると思います。

このEloquentとファサードは賛否いろいろ意見はありますが、
アプリケーションのモックや、小規模アプリケーションでは使い勝手が良く、
ある程度動かすところまで開発するには大変便利です。

複数人で開発を行い、長期的に運用、保守していかなければならないような場合に、
この便利な機能たちとどう付き合っていくべきでしょうか?

どこでも利用できるが故に複雑になり易い

ファサードを利用する場合、多くの方はインスタンス生成や、
クラスに依存しているものなどを考えることが少ないかもしれません。

<?php

namespace App\Http\Controllers;

use App\User;
use App\Entry;

class SampleController extends Controller
{
    /**
     * @param $id
     *
     * @return $this
     */
    public function apply($id)
    {
        $validator = \Validator::make(\Input::all(), ['content' => 'required']);
        if ($validator->fails()) {
            return redirect()->route('hoge')->withInput()->withErrors($validator);
        }

        try {
            $result = User::find($id);
            $requests = \Input::all();
            $entry = Entry::create($requests);
            \Log::info('added entry', $requests);

            return view('form')->with('user', $entry);
        } catch (\Exception $e) {
            $session = \Session::get('from_values');
            ...
        }
    }
}

たとえばコントローラで上記のように実装してしまうと、このクラスをテストするのは難しくなります。
このコントローラはデータベースに強く依存しているため、
拡張がなく、使い回すこともできない状態です。

このクラスの依存関係を表すと次のようになります。

    /**
     * SampleController constructor.
     *
     * @param User            $userModel
     * @param Entry           $entryModel
     * @param FactoryContract $validator
     * @param Request         $request
     * @param SessionManager  $session
     * @param LoggerInterface $log
     * @param Redirector      $redirect
     */
    public function __construct(
        User $userModel,
        Entry $entryModel,
        FactoryContract $validator,
        Request $request,
        SessionManager $session,
        LoggerInterface $log,
        Redirector $redirect
    ) {
        $this->userModel = $userModel;
        $this->entryModel = $entryModel;
        $this->validator = $validator;
        $this->request = $request;
        $this->session = $session;
        $this->log = $log;
        $this->redirect = $redirect;
    }

多少極端な例ではありますが、このクラスが依存しているものです。

ここではコントローラクラスを例としていますが、もしかすると、セッションやリダイレクトに依存しているモデルクラス、
データベースに依存しているログクラスなどを実装してしまっているのかもしれません。

実際にファサードを使っているクラスに対して、どんなものが依存しているか確認してみてください。

ファサードを使わないメリット

メリットとしては、上記の例のようにクラスの依存関係がわかりやすくなり、
テストがしやすくなるのはもちろん、再利用性が高くなるのがあげられます。

たとえばこれから開発していくもので、明らかにモジュールとして用意できる機能や、
拡張して実装していけば良い、といったものを実現するには疎結合なアプリケーション作りを心がけていなければ難しくなります。
これはパッケージ開発も同じです。
(Laravelを主に考えたものであってもインターフェースなどに依存させていれば、Laravel以外でも利用できます)

ファサードを利用すれば簡単に開発できるのかもしれません。
ですがこのファサードはそれぞれのプロジェクトで自由に変更できます。
モジュールとして提供するものにファサードが含まれている場合、それは実装に制約をあたえ、
かつLaravel以外の選択肢を与えないことになります。

    'aliases' => [

        'AppLication'       => Illuminate\Support\Facades\App::class,
        'ArtisanConsole'   => Illuminate\Support\Facades\Artisan::class,
        'Db'        => Illuminate\Support\Facades\DB::class,
    // 省略

config/app.phpで上記のようにファサードが変更されているプロジェクトがあれば、すでに利用できません。
また不特定多数の方に提供するパッケージも同様にファサードに依存してはいけません。
(peclのEventエクステンションを利用している環境ではEventファサードを変更しなければスムーズに動きません)

ファサードの仕組み、実態を知る

これについては書籍でも扱っています。
また公式のリファレンスでもファサードと実クラス、コンテナのサービス名の一覧が用意されています。

データベースの例

よく利用する機会が多いDBファサードを利用しない場合は次のようになります。

<?php

namespace App\DataAccess;

use Illuminate\Database\DatabaseManager;

class Sample
{
    /** @var DatabaseManager */
    protected $db;

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

    /**
     * @param array $attributes
     *
     * @return int
     */
    public function add(array $attributes)
    {
        return $this->db->connection()->insertGetId($attributes);
    }
// 省略

このデータベースを利用するクラスに依存する抽象レイヤは次のようになります。

<?php

namespace App\Repositories;

use App\DataAccess\Sample;

/**
 * Class SampleRepository.
 */
class SampleRepository
{
    /** @var Sample */
    protected $sample;

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

    /**
     * @param array $attributes
     *
     * @return int
     */
    public function add(array $attributes)
    {
        return $this->sample->add($attributes);
    }
// 省略
}

ファサードを使う場合はDBファサードと、ファサードを解決するための仕組みに強く依存していましたが、
上記のようにすると、DatabaseManagerのみに依存したクラスとなります。
極端なことを言うと、Laravelでなくても上記のコードはどんなフレームワークでも、フレームワークではなくても動作します。

Laravelのサービスコンテナは、コンストラクタインジェクションによる解決ができますので、
DatabaseManagerやSessionManagerなどのクラスの他に、インターフェースを記述して利用できます。
インターフェースに依存するように記述することで、よりフレームワークから分離されたコードになり、
汎用性も高く、どんなシステムにも組み込めるコードになります。

Laravelを使う上で一通りの機能を理解して、中級者へステップアップする際にはこうした実装方法を必ず覚えておきましょう。

ファサードを無効にして少しの高速化

ファサードを利用しないことで、コンテナへのアクセサを利用しなくなりますので、
多少なりとも高速に動作させれるようになるかもしません。  

ファサード自体を無効にする場合は、config/app.phpのaliases配列を空にするだけでも問題ありませんが、
このalasesを利用しているのは、Illuminate\Foundation\Bootstrap\RegisterFacadesクラスです。
このクラスは、App\Http\Kernel、App\Console\Kernelで利用されますので、
両クラスの基底クラスのbootstrappersプロパティからRegisterFacadesを利用しないように上書きましょう。

ファサードを無効にした場合はide_helperは生成してもクラスなどは出力されません。
ですが、こうしたプラグインがなくても、全て補完できるようになってます。

コード例をたくさん載せようと思っていたら、前振りだけで長くなってしまいました・・・。
この続きはまた今度・・。

Laravelリファレンスにはファサードを利用しない場合のサンプルも多く載っています。
アプリケーション作りの参考にもなると思いますので、
書店などで手にとってみてください。

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