FuelPHPでTwig Extension #FuelPHPAdvent2013

4日目の@さんのFuelphpのエラーハンドリングがなんか今ひとつ物足りなかったのでなんとかしてみた話 - どうにもならない日々@mkknに引き続き、FuelPHP Advent Calendar 2013の5日目です。


ここ数年はアドベントカレンダーの時にしか技術的な内容を書いていない気がするのが恐ろしいところですが、気にせずいきましょう。

FuelPHPのParserパッケージ

FuelPHPは、基本的にはビューに生のPHPスクリプトを使うことになっていますが、標準バンドルされているParserパッケージを用いることで、様々なテンプレートエンジンを用いることができます。現在サポートされているエンジンは以下の通り。

このうち自分ではTwigを愛用しています。何か機能を追加するにも簡単にできるところが良いですね。

Parserパッケージが標準で用意してくれるFuelPHP向けExtension

ParserパッケージでTwigを使用すると、Uri, Config, Form, Input, Html, Asset などの便利そうなFuel coreのメソッドを、あらかじめTwig Extensionとしてロードしてくれます。これを行っているのは

fuel/packages/parser/classes/twig/fuel/extension.php

にある\Parser\Twig_Fuel_Extensionクラスで、これ自体も標準的なTwig Extensionです。

これのおかげで、例えば

Asset::js('hogehoge.js');

を呼びたい場所では

{{ asset_js('hogehoge.js') }}

と書くことができるわけです。

アプリ独自のTwig Extensionを使う

とはいえ、ただ単にTwigを使ってHTMLテンプレートを書くだけではなく、アプリケーション独自のTwig Extensionをがしがし登録して使いこなしてこそTwigの便利さが際立つというもの。早速やってみましょう。


独自のTwig Extensionを登録するには、まずTwig_Extensionクラスを継承したクラスを作ります。クラス名は他とぶつからなければ何でも良いですが、ここではHogeアプリ向けにHoge_Twig_Extensionという名前にすることにしましょう。FuelPHPのファイル名規則に則り以下の場所に作ります。

fuel/app/classes/hoge/twig/extension.php

中身はこんな感じ。

<?php

class Hoge_Twig_Extension extends Twig_Extension
{
    /**
     * Gets the name of the extension.
     *
     * @return  string
     */
    public function getName()
    {
        return 'hoge';
    }

    /**
     * Sets up all of the functions this extension makes available.
     *
     * @return  array
     */
    public function getFunctions()
    {
        return array(
            new Twig_SimpleFunction('swap_empty', array($this, 'swapEmpty')),
        );
    }

    /**
     * Sets up all of the filters this extension makes available.
     *
     * @return  array
     */
    public function getFilters()
    {
        return array(
            new Twig_SimpleFilter('json', 'json_encode'),
        );
    }

    public function swapEmpty($value)
    {
        return empty($value)? '-' : $value;
    } 
} 


ここではTwigの関数とフィルターを一つずつ登録しています。

swap_empty関数
もし引数がempty()で真だったら「-」を出力、そうでなければそのまま。
jsonフィルター
引数をPHPjson_encodeに渡した結果を出力。

テンプレート上では以下のように使います。

{# 変数の設定、本来はPHP側から渡される #}
{% set foo = 0 %}
{% set bar = {'fuga': 'hoge', 'move': 'puge'} %}

{{ swap_empty(foo) }}
{{ bar|json }}

ただファイルを置いただけではParserパッケージはそのExtensionの存在を知らないので、Parserのconfigを通して教えてやります。FuelPHPのConfigは大変に賢くて、追加・変更したい部分だけapp以下に書けば良いので、

fuel/app/config/parser.php

に以下の内容を記述します。

<?php
return array(
    'View_Twig' => array(
        'extensions' => array(
            'Hoge_Twig_Extension',
            ),
        ),
); 


Twigは非常に柔軟性の高いテンプレートエンジンで、上記で紹介した関数・フィルターの他にも

などを独自に拡張できます。詳しく知りたい方は、Extending Twig を読むとよいでしょう。


明日のアドベントカレンダーも引き続き私ですw


12/8追記:
Twig_Function_Method, Twig_Filter_Function はすでに古いインターフェースだと @ さんからご指摘を受けたので、現在推奨されている Twig_SimpleFunction, Twig_SimpleFilter に書き換えました。

「PHPエンジニア養成読本」が9月13日に出版されます


来月9月13日(金)に技術評論社より「PHPエンジニア養成読本」というムックが発売されます。新原さんのエントリ増永さんのエントリがすでにホッテントリ入りしているので、もうご存知の方も多いかもしれません。大きく変わりつつある PHP 開発のイマドキの常識を、可能な限りピックアップした本です。


内容についてはすでに上記の2エントリで的確に解説されていますので、ここでは視点を変えて、きっかけを作った一人としてこのムックが生まれた背景などを書いておこうと思います。

企画の相談が来たのは4月中旬

私は以前にWEB+DB PRESSで「PHPこども電話相談室」というふざけたタイトルの連載をしていました。その時からお世話になっている技評の編集者の細谷さんから、「PHPエンジニア養成読本」というムックの企画があるので相談に乗ってもらえないかというメールが来たのは4月中旬でした。PHP を取り巻く開発環境が大きく変わりつつある中で、それらの情報がまとまっている出版物はほぼ無いという状況で、たぶん需要もあるだろうし出版する価値も大きいと思った私は、二つ返事で OK しました。


その後、わりかしのんびりとしたメールのやりとりでネタ出し等をおこなったあと、5月22日に細谷さんとお会いして打合せをしました。その場では色んな話をしましたが、今回のムックの出版日ターゲットとして、その時にはすでに開催日が決まっていた PHPカンファレンス2013 に合わせる形にしたい、という要望を聞きました。それを聞いた時に私は「そりゃ無理ですよー」と返事をしたのを覚えています。その時に自分が想定していた執筆者候補は、たいてい PHPカンファレンスのスタッフになっているので、カンファレンス前のテンパっている時期に執筆時記を重ねるのはリスク高え、と思ってました。

PHPカンファレンス関西の飲み会で新原さんに相談

その打合せの直後にPHPカンファレンス関西2013が開催されました。私は毎年参加しているので今回も参加したわけですが、カンファレンス前日の宴会で「このムックの執筆陣を関西 PHP コミュニティで確保できないか?」という相談を新原さんにしてみました。新原さんも幸い興味を持ってくれて、ここから一気に企画が具体化し始めます。


執筆者の Facebook グループが作られて、そこで企画内容を揉んだり、執筆原稿は github で管理することが決まったり、様々な物事がどんどん詰められていきました。github での原稿を共同執筆という経験は自分は初めてで、他の執筆陣から徐々に上がってくる原稿を見ながら、高まるプレッシャーを感じていました。


自分はというと、別口の原稿依頼がもう一本あってそちらに時間が取られたり、ちょっとサボり癖がでたりして、最初の〆切を大幅にオーバーしてからエンジンが回り始めて一気に書き上げました。ちなみにその別口の原稿というのが、@IT で公開された以下の記事です。

Symfony, FuelPHP の紹介記事を3ページずつ書きました

さてそういうわけで、他の方々に心配をかけながらも、無事に原稿は書き上がりました。SymfonyFuelPHP の紹介記事をそれぞれ 3 ページずつ執筆しました。


MVC がどうなっているとか、基本的なことはどのフレームワークも大して変わらないので、自分なりにそれぞれのフレームワークを使ってみて感じた、そのフレームワークならではの特徴を抽出して執筆したつもりです。その意味では、自分のパートは入門者には実用性は全くありませんが、そのフレームワークのキモの考え方をパッと知りたいというニーズには合ってるんじゃないかと思います。

PHPカンファレンス2013の会場で是非ご購入下さいw

PHPカンファレンス2013は、今年もWordCamp Tokyo 2013と共催で、大田区蒲田産業会館 PiO にて、9月14日(土) に開催されます。そうです、「PHPエンジニア養成読本」の発売日の翌日です。PHPCon には今年もジュンク堂さんが出展して書籍販売します。当然、本ムックも販売リストの中に入っています。会場内には私も含め執筆陣も多数いるはずですので、サインを集めるには最適かもしれません。



fuelphp-dynamoutilを公開した

さて、FuelPHP 勉強会 東京 vol.3 : ATND で発表したスライドの中で、FuelPHPAmazon DynamoDB を使いやすくする SDK のラッパーを OSS で公開したいと予告していたのですが、先ほど github で公開しました。

ドキュメントはまだないです。クラス 4 つしかない小さなものなので、ソース読んだだけでも使い方は分かるかもしれません。

FuelPHP勉強会東京 vol.3に参加してきた

ここ数ヶ月間は会社のプロジェクトでは FuelPHP を使っています。丁度よいタイミングで勉強会が開催されたので参加しました。

申し込んだ時点では参加者全員 LT という約束だったので、ここ数ヶ月 FuelPHP を使った実感を簡単にまとめてスライドにしました。


昼の勉強会も面白い発表をたくさん聞けて、夜の懇親会もさらに楽しくて、とても良い時間を過ごさせて頂きました。

知ってる人が一人もいない勉強会も新鮮でいいなぁ〜。もっと色んなところに出て行かないといけないなと実感しました。

PHP-5.4でのZip Extension

PHPMatsuri 2012 に来ている時に、何故か自分のワーク環境の一つのPHP-5.4を整備することになって、5.3の時と同様に Zip extension を PECL から入れようとしてハマったのでメモ。


PECL Zip はすでにメンテナンスされていない。PHP-5.4 でビルドしようとすると、zend_object_handlerにセットされるハンドラ関数の引数が変更されているので、コンパイルエラーになる。


PHP-5.4 本体に Zip extension がバンドルされているのでそちらを使う。

月の最後の日をPHPで簡単に知る方法

集計系の処理のプログラムを開発していると、その月の最後の日を求める必要がちょくちょくあったりしませんか? 私はあります。さてそういう時にどうやって求めるでしょう。答えは一発↓

<?php
$d = date('Y-m-t');

これだけですw

書式「t」って何ですか?

恥ずかしながら date() 関数の書式に使える「t」の存在を今日まで知りませんでした。意味としては以下になっています。

t : 指定した月の日数。

t は DateTime クラスにも使えます。
例えば今年の各月に対して最終日を求めるのには、以下のようにします。

<?php
$d = new DateTime();
$year = 2012;
foreach (range(1, 12) as $month) {
    $d->setDate($year, $month, 1);
    echo $d->format('Y-m-t') . "\n";
}

従来はどうやっていた?

t フォーマットを知る前の従来のセオリーはこうでした。

  1. その月の最初の日(1日)を求める
  2. それに "+1 month" する
  3. それにさらに "-1 day" する

コードで書くとこんな感じ。

<?php
$d = new DateTime();
$d->setDate($d->format('Y'), $d->format('m'), 1);
$d->modify('+1 month -1 day');
echo $d->format('Y-m-d');

おまけ

PHPマニュアル「相対的な書式」をつらつら見てたら

<?php
$d = new DateTime('last day of 2012-06');
echo $d->format('Y-m-d');

とかでもいいんじゃね? とか思った。ダメじゃんオレw

「あにみた!」ができるまで

6月5日(火)にAMNは新サービス「あにみた!」をリリースしました。あにみたは、アニメの各話単位でソーシャルチェックインできるサービスです。


「なぜソーシャルマーケティングのAMNが?」みたいな反応が結構ありますが、今回のあにみたはエンジニア主導で企画・開発されたサービスでして、私も含めアニオタ率の高いAMNエンジニアとしては至極当然の流れだったりします。

アニメの各話単位でチェックインできるサービスが欲しかった

そもそもの発端は、昨年の11月1日に開催された、AMN新サービスのアイディア出し社内ブレストミーティング、通称「AMN Developer Day (ADD)」でした。そこでAMNエンジニア全員で20以上のサービスアイディアを出し合った訳ですが、その中の一つに私が提案した「アニメの各話ごとにチェックインできるサービス」というものがありました。


これは自分の経験として、TwitterFacebookでTVアニメの感想をつぶやいた時に思いもよらない反応があったことが何回かあって、この機能に特化して自分のポストをアーカイブしつつ、ソーシャルメディアに流せるサービスがもしあれば、自分はハードに使うだろうなぁと考えたのがそもそものきっかけでした。

AMNとしてバズらせるサービスを作りたい

新サービスの話はその後しばらくは水面下に潜っていたのですが、AMN CTOの福田さんが作った昨年末の「私の漢字2011」がうまく話題になったこともあって、エンジニア主導でインパクトのあるサービスを立ちあげようという話になりました。開発リソースとしてその時点で最も融通がきいた石山さんがメイン開発者となることが決まって、本人に一番作りたいサービスを決めてもらったところ「アニメチェックイン」をやりたいということで、「あにみた!」の開発が本格的にスタートしたのでした。

開発者の頑張り

石山さんはここ数ヶ月「あにみた!」の開発をほとんど一人で行なってきました。私達周囲のエンジニアは、コンセプトや仕様を決める議論には深く参加してきましたが、曲がりなりにもサービスとしてリリースできるところまで来たのは、ひとえに石山さんの頑張りによるものです。AMNのプレスリリースにも石山さんのコメントが載っていますが、自らが使って楽しいサービスをゼロから作るという経験は、モチベーションの維持に大変重要だったようです。

デザインワークはピチカートデザイン

「あにみた!」のデザインワークは白坂翔さん率いるピチカートデザインさんにお願いしています。そこはかとなく猫テイストなデザインコンセプトは、可愛くも有りほのぼのでも有り、皆大変気に入っています。どうもありがとうございます。

「あにみた!」のインフラ構成について

調べた人には簡単に分かることですが、「あにみた!」は全面的にアマゾンウェブサービスEC2上で動いています。正にクラウドさまさまと言ったところです。


現状のインフラ構成は

  • m1.large の Webフロントエンド
  • m1.large 3台の MongoDB バックエンド

となっています。このうち3台の MongoDB サーバは AMN の広告配信サービスと共有しています。サービスイン前に負荷テストを行ったところMongoDB の負荷は本当に微々たるものだったので、相乗り可能と判断して共有することにしました。ソフトウェア構成要素としては

となっています。


負荷が問題となるとしたら、現状ではまず最初にネックになるのが Web フロントエンドだと考えられます。その部分はセオリー通りスケールアウトできるように作っていますので、滅茶苦茶ブレイクしない限りは、今のところは負荷問題は気にしなくて良いと思っています。

「あにみた!」の今後について

「あにみた!」をリリースして半日ほど経ちましたが、どうやらこちらの想定以上に多くの人に使っていただけているようです。ただこちらの想定外の使用方法のニーズが多くあることも、様々な反応を追いかけていて分かって来ました。ベータリリースということで、予定している機能で実装されていないものもまだまだたくさんありますし、ユーザの方々からの要望もたくさんいただいています。


より多くの人に満足いただけるように、今後もどんどんサービスを発展させて行きたいとエンジニア一同考えていますので、どうか期待しつつお待ち下さいませ。