SilexをBootStrapさせてみた

巷で騒がれているFuelPHPを横目にSilexが気になっている@sa2yasuでございませう。

Sinatraみたいに超絶手軽なPHP Frameworkないかなーと思ってネットサーフィンしているうちに見つけました。

Silexの特徴

Slideshareにいい感じのものがあったのでご紹介します。
http://www.slideshare.net/brtriver/php2012-silex
Silex自体はコントローラ部分の実装とDIコンテナの実装しかないのですが、サービスプロバイダと呼ばれるコンテナを登録することで機能拡張が可能です。公式非公式プロバイダもありますし、自分でプロバイダを作ることも可能です。

BootStrapしてみる

ものは試しです。BootStrapしてみます。
Silexユーザガイドで紹介されているSilex Kitchen Editionfabpotは所謂全部乗せ状態なのですが、ほんとに全部というわけではないし、全部乗せならフルスタックと変わらないじゃんと思ったのでもうちょっとコンパクトなBootStrapを見つけてきました。
https://github.com/qpleple/silex-bootstrap

$ git clone git://github.com/qpleple/silex-bootstrap.git
$ cd silex-bootstrap
$ curl -s curl -s http://getcomposer.org/installer | php
$ composer.phar install

インストールはたったこれだけ。
続いて設定。
BootStrapはDBアクセスをするサンプルがあるのでDBの設定をします。
silex-bootstrap/src/config.iniを編集

[production]
db.driver        = pdo_mysql
db.dbname    = dumb
db.host          = localhost
db.user          = root
db.password  = root

[staging]
db.driver        = pdo_mysql
db.dbname    = dumb
db.host          = localhost
db.user          = root
db.password  = root

[development]
db.driver        = pdo_mysql <- ここを使用するDriverに
db.dbname     = mytestdb <- ここを使用するDBのインスタンス名に
db.host           = localhost <- 以下略
db.user           = root
db.password   = 

環境によってDB接続定義を変えられるのが良いですね。
BootStrapのサンプルはdumbというテーブルのa,bカラムに乱数をinsertし、それを参照するサンプルになっています。
silex-bootstrap/src/app.php

<?php

$app = require __DIR__.'/bootstrap.php';

$app->get('/', function() use ($app){
    $app['db.dumb']->insert(array('a' => rand(), 'b' => rand()));
    
    $data = $app['db.dumb']->findAll();
    
    return $app['twig']->render('index.html.twig', array('data' => $data));
});

return $app;

ですので、事前にdumbというテーブルにa,bカラムを追加しとく必要があります。
また、サンプルのViewにはTwigのテンプレートエンジンを使用しているため、Twigテンプレートのcacheフォルダも必要になります。

$ mkdir cache
$ chmod 777 cache

諸々の設定が完了してアプリケーションにアクセスするとこんな結果になります。

ここまででSilexのBootStrapは完了です。せっかくなので少し解説を。

Twitter Boot Strap

画面を見てわかるとおり、TwitterBootStrapが使われています。
silex-bootsrap/webフォルダがDocumentRootになっていて、Twitter Boot Strapが既に置いてあります。
プログラマの皆さんは大概デザインが苦手というか敬遠しているので最初からTwitterBootStrapの恩恵に肖れるのはよいですね。

composer.json

silex-bootstrap以下にcomposer.jsonというファイルがあります。

{
    "minimum-stability": "dev",
    "require": {
        "silex/silex": "1.*",
        "twig/twig": "1.6.0",
        "doctrine/dbal": "2.2.*",
        "doctrine/common": "2.2.*"
    },
    "autoload": {
        "psr-0": { "Repository": "src/"}
    }
}

composerはアプリケーションが必要とする外部ライブラリを、そのアプリケーション固有の状態で一元的に管理してくれるツール(コピペ)。java,Groovy界隈で言うところのMaven, Gradle的アレです。pearだとこうはいきません。
requireに記述されているものはcomposer.pharでインストールできるのでphpunitや他のプロバイダを追加したいときはこちらに追記してcomposer.phar installすればすぐに使用できるようになります。

bootstrap.phpを読む

<?php
require_once __DIR__.'/../vendor/autoload.php'; <- コア、外部ライブラリの読み込み

use Silex\Provider\TwigServiceProvider;
use Silex\Provider\DoctrineServiceProvider;
use Repository\DumbRepository;

$env = getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production';
$ini_config = parse_ini_file(__DIR__.'/config.ini', TRUE);
$config = $ini_config[$env]; <- 環境変数読み込み

$app = new Silex\Application(); <- ここからSilexの定義

$app['debug'] = true; <- debug設定をtrueに

$app->register(new TwigServiceProvider(), array( <- Twigをコンテナに登録
    'twig.path' => __DIR__.'/templates', <- テンプレートはここにあるのを使います
    'twig.options' => array('cache' => __DIR__.'/../cache'), <- キャッシュファイルはここに置くから
));

$app->register(new DoctrineServiceProvider); <- Doctrine使う

$app['db.options'] = array( <- DB接続定義
    'driver'   => $config['db.driver'],
    'dbname'   => $config['db.dbname'],
    'host'     => $config['db.host'],
    'user'     => $config['db.user'],
    'password' => $config['db.password'],
);

$app->before(function() use ($app) { <- コントローラにディスパッチする前に呼ばれる
    $app['db.dumb'] = $app->share(function($app) { <- db.dumbにDumbRepositoryを共有サービスとして使えるようにする
        return new DumbRepository($app['db']);
    });
});

return $app;

ポイントは
・使用サービスプロバイダをSilexのコンテナに登録する
ですかね。
app.phpにも書けますけど、app.phpはコントローラの実装を行う場所なので事前準備はbootstrap.phpにまとめた方がapp.phpがすっきりします。
web/index.phpとかsrc/app.phpは読めばすぐわかると思うので割愛。

簡単ですねー。

自分の使用想定としては、CMSとの抱き合わせ(ちょっとした動的コンテンツ部分)で使用するのが適切かなと思っています。
ある程度ルーティングが増えてくるとapp.phpが大変なことになり、コントローラをルーティング毎に切り出すこととか考えだすと、だったら最初からSilexでなくていいじゃんみたいなことになりますので。

いじょ