[Symfony2]入出力の文字エンコードを変換してみよう Symfony Advent Calender JP 2011 – 6日目-

Written by uechoco 12月 06
この記事を読む時間:229くらい

@uechocoです。Symfony Advent Calendar JP 2011の6日目の記事です。@fivestrさんからのバトンタッチです。

日本Symfonyユーザー会に所属するスタッフとして、勢いで申し込んでみたものの、
普段職場でSymfonyを使ってないのでネタ探しに苦労しました。

そういえば去年のSymfony Advent 2010 : ATNDでは[Symfony2]PEAR::Net_UserAgent_MobileをDIコンテナから呼び出すという記事を書きました。
今年も似たような領域で、ガラケー向けのWebサイト開発で使えるかもしれないテクニックとして、入出力される値やコンテンツの文字コードを変換する方法をご紹介します。

symfony 1.x系ではMojavi由来のフィルタチェインの機構がありましたので、
MobileEncodingFilterなどのクラスを作って、入出力の前後でエンコードの変換をかませるというのが一般的だったかと思います。

Syfmony2系ではフィルタチェインという概念はなくなってしまいました。
代わりに処理の所々にイベントが定義されていて、リスナーを登録しておくと自動的にディスパッチしてくれるようなイベントドリブン方式に変わりました。

今回はSymfony2のHttpKernel機構に標準で設定されているkernel.requestイベントとkernel.responseイベントのリスナークラスとしてMobileEncodingListenerを作り、入出力のエンコード処理を行なっています。今回はSymfonyに標準で同梱されているAcme\DemoBundleの中に作成する前提です。

MobileEncodingListenerクラスの作成

まずはイベントリスナークラスを作成します。Symfony本体のFrameworkBundleやHttpKernelコンポーネントのディレクトリ構造の慣習に従ってAcme\DemoBundleの下にEventListenerディレクトリを作成し、その下にイベントリスナークラスを作成します。以下のようなMobileEncodingListnerクラスを作成してください。まだ中身は実装しません。

[phpcode]

*
*/
class MobileEncodingListener
{
}
[/phpcode]

kernel.responseイベント

まずは簡単なkernel.responseイベントに対するメソッドを記述します。クラスの使用宣言を追加して、MobileEncodingListenerクラスにonKernelResponse()メソッドを実装します。

[phpcode]
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
[/phpcode]

[phpcode]
/**
* Convert output encoding of response.
* @param FilterResponseEvent $event
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}

$response = $event->getResponse();

$response->setContent(mb_convert_encoding($response->getContent(), ‘SJIS-win’, ‘UTF-8’));
}
[/phpcode]

中身の処理としては単純で、Resopnseオブジェクトを取得し、その中のコンテンツの文字コードを変換してまたセットしなおしているだけです。今回は説明の簡略化のために文字コードの部分を直書きしています。最初の行のマスターリクエスト以外なら何もしないという条件文がありますが、HttpKernelではリクエストの種別が2種類あり、マスターリクエストとサブリクエストと呼ばれています。そのマスターリクエストの時だけ処理したいので条件式を記述しています。FilterResponseEventクラスを受け取るというのはkernel.responseイベントとの仕様として決められています。

kernel.requestイベント

次にkernel.requestイベントに対するメソッドを記述します。先ほどと同様にクラスの使用宣言を追加して、MobileEncodingListenerクラスにonKernelRequest()メソッドを実装します。

[phpcode]use Symfony\Component\HttpKernel\Event\GetResponseEvent;[/phpcode]

[phpcode]
/**
* Convert input encoding of request.
* @param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}

$request = $event->getRequest();

// GET
$get = $request->query->all();
mb_convert_variables(‘UTF-8’, ‘SJIS-win’, $get);
$request->query->replace($get);
// POST
$post = $request->request->all();
mb_convert_variables(‘UTF-8’, ‘SJIS-win’, $post);
$request->request->replace($post);
}
[/phpcode]

こちらもマスターリクエストのみ処理する記述が最初にあります。次にRequestオブジェクトを取得し、今回は$_GETと$_POSTに相当する変数だけを文字コード変換しました。$_GETと$POSTはRequestオブジェクトの$queryと$requestというパブリック変数に代入されています。形式としてはParameterBagというクラスでラッピングされて代入されています。ParameterBagクラスのインターフェースとしてall()メソッドで全配列を取得し、replace()メソッドで全配列を総取替しています。

イベントリスナーとして登録する

最後に、先ほど作ったクラスとメソッドをイベントリスナーとして登録します。登録手順はDIコンテナにサービスとして登録するのと同じですが、特別なタグを定義することでイベントリスナーとして認識されるようになっています。src/Acme/DemoBundle/Resources/config/services.xmlを開き、以下のように追記してください。

  1. <!-- 省略 -->
  2.  
  3.     <parameters>
  4.         <parameter key="mobile_encoding_listener.class">Acme\DemoBundle\EventListener\MobileEncodingListener</parameter>
  5.     </parameters>
  6.  
  7.     <services>
  8.         <!-- 省略 -->
  9.         <service id="acme.demo.mobile_encoding_listener" class="%mobile_encoding_listener.class%">
  10.             <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
  11.             <tag name="kernel.event_listener" event="kernel.response" method="onKernelResponse" />
  12.         </service>
  13.     </services>
  14.  
  15.     <!-- 省略 -->

確認する

何事もなければデモ画面が正常に動作すると思います。プロファイラのEvent項を見てみると、リスナーが登録されていることが確認できます。

今回直書きだった文字コードの指定は、config.ymlなどの設定ファイルから取ってくるような仕様にしたり、UserAgentを判別して決定するような仕様にしたほうが汎用性が高いでしょう。

余談

今回の記事の参考にするために他のイベントリスナークラスを見ていましたが、イベントリスナークラスの実装は様々なパターンが存在しているようです。例えば1つのリスナークラスに2つ以上のイベントメソッドをもたせているものや、1クラス1イベントメソッドのもの、他の役割のあるクラスにイベントメソッドを持たせてリスナークラスを兼任させているものなどです。

SymfonyのHttpKernelにどのようなイベントがあるか知りたい方は、Symfonyの内部構造のドキュメントの一節にイベントについて書かれている部分がありますので、そちらを参照してください。

最後に

7日目はMongoDB JPにも所属している@madapajaさんです。よろしくお願いします。

[php]homebrewでintlライブラリが有効なphpをコンパイルする

Written by uechoco 12月 04
[php]homebrewでintlライブラリが有効なphpをコンパイルする はコメントを受け付けていません。
この記事を読む時間:165くらい

Symfony2などを使用する場合、php 5.3のintlという国際化用拡張モジュールがインストールされていないと警告が出たり一部の機能が使用することができません。

私のMacBook Airに標準で入っているphpは5.3.6ですが、intlライブラリは含まれていません。

そこで、今回はMac OSX 10.7 Lionのhomebrewでintlライブラリが有効なphpをコンパイルし、加えてSymfony2のcheck.phpと呼ばれる環境チェックスクリプトで警告が出ないようにしてみます。私のphpは標準のものに対してライブラリを加えているため、皆さんよりも追加でインストールする項目が少ないかもしれません。

intlオプションが有効なphp formula

phpは標準でインストールされているため、homebrewのformulaは有りません。そこで、非公式に作られているformulaを使用します。
ココらへんの手順はいくつかの記事を参考にしました。

[shcode]brew install https://github.com/adamv/homebrew-alt/raw/master/duplicates/php.rb –with-mysql –with-intl[/shcode]

このとき、使用可能なオプションはoptionsコマンドで見ることができます。

  1. brew options https://github.com/adamv/homebrew-alt/raw/master/duplicates/php.rb
  2. php
  3. --with-mysql
  4.     Include MySQL support
  5. --with-mariadb
  6.     Include MariaDB support
  7. --with-pgsql
  8.     Include PostgreSQL support
  9. --with-mssql
  10.     Include MSSQL-DB support
  11. --with-fpm
  12.     Enable building of the fpm SAPI executable (implies --without-apache)
  13. --without-apache
  14.     Build without shared Apache 2.0 Handler module
  15. --with-intl
  16.     Include internationalization support
  17. --without-readline
  18.     Build without readline support
  19. --with-gmp
  20.     Include GMP support

依存関係のあるlibxml2, mcrypt, icu4cなどもコンパイルされたあと、php本体もコンパイルされます。少し時間がかかるので、気長に待ちましょう.。

apacheの設定

phpのコンパイルが終了すると、以下のようなメッセージが出てきます。

  1. For 10.5 and Apache:
  2.     Apache needs to run in 32-bit mode. You can either force Apache to start
  3.     in 32-bit mode or you can thin the Apache executable.
  4.  
  5. To enable PHP in Apache add the following to httpd.conf and restart Apache:
  6.     LoadModule php5_module    /usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so
  7.  
  8. The php.ini file can be found in:
  9.     /usr/local/etc/php.ini
  10.  
  11. 'Fix' the default PEAR permissions and config:
  12.     chmod -R ug+w /usr/local/Cellar/php/5.3.8/lib/php
  13.     pear config-set php_ini /usr/local/etc/php.ini

例えば、Webサーバーがapache であれば「LoadModule php5_module /usr/local/Cellar/php/5.3.8/libexec/apache2/libphp5.so」を/etc/apache2/httpd.confに追加しまししょう。(元々入っているのphp5_moduleの行があるので、そちらは先頭に「#」をつけてコメントアウトしておきましょう。)

また新しいphpのiniファイルは「/usr/local/etc/php.ini」にありますので標準の場所と異なるのを気をつけましょう。

PEARライブラリののパーミッションも直しておくと便利です。「chmod -R ug+w /usr/local/Cellar/php/5.3.8/lib/php」というコマンドはすぐに通るかも知れませんが、「pear config-set php_ini /usr/local/etc/php.ini」のときに「/User/hogehoge/.pearrc」が作れないといったエラーがあった場合は、touchコマンドなどで事前に作成してあげて、パーミッションを777にでもしておいてください。

この時点で「php –version」としても、まだ元々のphpコマンドの方を参照しているでしょう。「which php」とすると「/usr/bin/php」を参照しているためです。コマンドラインが読み込まれた段階でbrew側のコマンド群を優先的に読みこむようにしましょう。ここではシェルがbashの想定で設定ファイルを書きます。

[shcode]vi ~/.bash_profile[/shcode]

としてこの1行を追加しましょう。

  1. export PATH="$(brew --prefix)/bin:$PATH"

最後に、bashの設定を反映させます。

[shcode]source ~/.bash_profile[/shcode]

この時点でphp –versionすると、新しいほうのphpが参照されているでしょう。

  1. PHP 5.3.8 (cli) (built: Dec  4 2011 13:40:01)
  2. Copyright (c) 1997-2011 The PHP Group
  3. Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies

timezoneの設定

新しいphp.iniが作成されたので、最低限の設定としてtimezoneの設定をしておかないと、いずれ警告が出てしまいます。

[shcode]vi /usr/local/etc/php.ini[/shcode]

diff形式でいうと、以下のように変更してください。

  1. -;date.timezone =
  2. +date.timezone = "Asia/Tokyo"

APCのインストール

この時点でintl込のphpが動くのですが、最後にSymfony2用にAPCライブラリもコンパイルして用意しましょう。

[shcode]brew install apc[/shcode]

と打つだけです。

インストール後、以下のようなメッセージが表示されます。

  1. To finish installing APC:
  2.  * Add the following lines to php.ini:
  3.     [apc]
  4.     extension="/usr/local/Cellar/apc/3.1.9/apc.so"
  5.     apc.enabled=1
  6.     apc.shm_segments=1
  7.     apc.shm_size=64M
  8.     apc.ttl=7200
  9.     apc.user_ttl=7200
  10.     apc.num_files_hint=1024
  11.     apc.mmap_file_mask=/tmp/apc.XXXXXX
  12.     apc.enable_cli=1
  13.  * Restart your webserver
  14.  * Copy "/usr/local/Cellar/apc/3.1.9/apc.php" to any site to see APC's usage.

書いてあるとおりに、「/usr/local/etc/php.ini」にapcの設定を追加し、webサーバーを再起動します。最後のスクリプトのコピーは、APCの便利スクリプトなので、今はいりません。

Symfony2のapp/check.phpを見る

Symfony2のapp/check.phpを使って、環境が整っているかチェックしてみましょう。(その前にSymfony2の本体をDLしておいてください。)

Symfony2のルートディレクトリに移動し、以下のコマンドでapp/check.phpを実行します。

[shcode]php app/check.php[/shcode]

  1. ********************************
  2. *                              *
  3. *  Symfony requirements check  *
  4. *                              *
  5. ********************************
  6.  
  7. php.ini used by PHP: /usr/local/etc/php.ini
  8.  
  9. ** WARNING **
  10. *  The PHP CLI can use a different php.ini file
  11. *  than the one used with your web server.
  12. *  If this is the case, please ALSO launch this
  13. *  utility from your web server.
  14. ** WARNING **
  15.  
  16. ** Mandatory requirements **
  17.  
  18.   OK        Checking that PHP version is at least 5.3.2 (5.3.8 installed)
  19.   OK        Checking that the "date.timezone" setting is set
  20.   OK        Checking that app/cache/ directory is writable
  21.   OK        Checking that the app/logs/ directory is writable
  22.   OK        Checking that the json_encode() is available
  23.   OK        Checking that the SQLite3 or PDO_SQLite extension is available
  24.   OK        Checking that the session_start() is available
  25.   OK        Checking that the ctype_alpha() is available
  26.   OK        Checking that the token_get_all() is available
  27.   OK        Checking that the APC version is at least 3.0.17
  28.  
  29. ** Optional checks **
  30.  
  31.   OK        Checking that the PHP-XML module is installed
  32.   OK        Checking that the token_get_all() function is available
  33.   OK        Checking that the mb_strlen() function is available
  34.   OK        Checking that the iconv() function is available
  35.   OK        Checking that the utf8_decode() is available
  36.   OK        Checking that the posix_isatty() is available
  37.   OK        Checking that the intl extension is available
  38.   OK        Checking that the intl ICU version is at least 4+
  39.   OK        Checking that a PHP accelerator is installed
  40.   OK        Checking that php.ini has short_open_tag set to off
  41.   OK        Checking that php.ini has magic_quotes_gpc set to off
  42.   OK        Checking that php.ini has register_globals set to off
  43.   OK        Checking that php.ini has session.auto_start set to off
  44.  
  45. ** Optional checks (Doctrine) **
  46.  
  47.   OK        Checking that PDO is installed
  48.   OK        Checking that PDO has some drivers installed: mysql, sqlite, sqlite2

基本的な警告はなくなりました。これでSymfony2を楽しむ環境が整いましたね!

[勉強会]第4回Symfony2勉強会に参加&講師しました

Written by uechoco 6月 07
[勉強会]第4回Symfony2勉強会に参加&講師しました はコメントを受け付けていません。
この記事を読む時間:104くらい

2011/6/4(土)に、第4回Symfony2勉強会に参加&講師をしました。この記事では、人前での発表経験の乏しい私が講師という貴重な体験をしたことに対して、経緯や個人的な感想を書こうと思います。

当日のスライド一覧

当日発表のあったすべてのスライドをご覧になりたい方は、他の方がブログでまとめているので、そちらを参照してみてください。

講師をやることになった経緯

もともと、Symfony2の勉強会には、東京で開かれた第1回(2010/11)・第2回(2011/01)に参加していました。これらの勉強会には予習した(事前にドキュメントを見ながらSymfony2のコードを触った)上で参加していったので、参加者の中では結構アグレッシブに追っていた感じでした。第2回はフォーム+Doctrine2のワークショップだったのですが、説明を殆ど聞かずにワークショップの課題を完成させていました。また予習の成果があったので、(人生初の)LTを突発でやったりもしました。

本来正式版がリリースされるはずだった3月5日をすぎ、4月に入りました。@hidenorigotoさんから、しばらく間があいたから6月はじめに東京で勉強会を開こうという話が上がり、メーリングリストで基礎編ワークショップと講演・LTの2部構成の提案がなされました。その数日後、@hidenorigotoさんからTwitterで講師のお誘いを受けました

とまぁ、一瞬躊躇したものの、結局やることになりましたw 第2部の実践的な講演のためのいいネタをもってそうな人以外で基礎的な部分をある程度理解している人という感じでお誘いを受けたんでしょうか?

かくして、5分のLTを1回くらいしか経験したことのない私が、2時間近いのワークショップを担当することになりましたww

資料をつくりはじめる前にしたこと

資料を作り始める前に、人前で話すことについて学べる本や、プレゼン資料を作るための本をあさって、以下の3冊を読みました。

この3冊はどれもオススメです。

『パブリックスピーカーの告白』からは、スライド作成にかける時間の考え方、事前練習の重要性、当日準備の重要性などが特に役立ちました。
『プレゼンがうまい人の「図解思考」の技術』からは、つまらなくないプレゼントはなにか、聞き手が何を求めているのか、どういう風にプレゼンのフレームを組み立てていくかを学びました。
『わかりやすく伝える技術』は前述の本の参考資料だったので読んでみました。この本からは、3のマジック、伝えたいことの順番の考え方、気をつけるべき日本語を学びました。

これらの本を読まなかったら、スライドや当日の発表は悲惨なことになっていたのではないかと思います。それくらい、今回のスライド・発表は影響を受けています。

スライドの作成

今回は、ATNDの説明に、どういったことをやるのかを事前に書いてもらっていました。この内容は第3回のSymfony2勉強会で@hidenorigotoさんが行ったワークショップと似たような内容でした。スライドの構成として概要説明編とワークショップ編の2つに分けるのは決めていたので、ワークショップ編は第3回のワークショップの内容を参考にしました。

5月のGWが明けても思うようにはスライド作成は進みませんでした。Symfony2は急ピッチで様々な改変が加えられ続けているので、私が第2回で学んだ時よりは設定などの書き方が変わっていたりしました。今のSymfony2の状況に私の知識が追いついていなかったのです。

そんなこんなで、ある時、Symfonyしゃべりば on Ustreamを聞いていた時、@cakephperさんがSymfony2を学んでいたのですが、「CakePHPみたいなブログチュートリアルくらいのライトなサンプルがほしい」という発言をしていたのを聞いて、スライドそっちのけで「やろう!」と思い立ちました。様々なドキュメントを読みつつ、Symfony2を学びつつ、10日くらいで書き上げました。5月の終わりには日本Symfonyユーザー会のWebページにて、公開されました。

結果的には、ブログチュートリアルの執筆を通じて様々なドキュメントを見たことで、一気に知識が増えました。スライド作成もかなりはかどるようになりました。

せっかくなので、スライド作成が進まなかった頃の手書きのスライド原稿をアップしちゃいます。(symfony2_ws4_handout_before)最終的に作られたスライドとは構成が全然違いますねw

出来上がったスライドはこちらです。

練習

先述した『パブリックスピーカーの告白』では、練習が非常に大事であることが書かれています(にもかかわらず、多く人は練習をしていなくて、あまり良質ではない講演をしているとも)。私は勉強会の前日に有給をとって、家で練習を2回しました。2時間近いの講演なので、1回練習すると、2時間かかりますw 結構しんどいです。

プレゼンのための練習は今までしたことなかったんですが、練習すると、自信がもてます。実際にスライドを動かして説明してみないと気づかないようなスライドの不自然なところとかが見つかります。練習はしたほうがいいです。すべきです。

当日

そんなこんなで、発表当日になり、発表をしました。

3時間の枠で、前後に会場説明と締めの挨拶、真ん中の1時間は昼休憩でした。昼休憩前までは、概要説明をして、ワークショップの冒頭に進めたので、練習通りにいいペースで進んでいるなと思っていました。もしかしたら、ワークショップ編も速く終わっちゃうんじゃないかとも思っていました。

でもそんなことはありませんでした。休憩後、ワークショップを続けていると、スライド中のコードを参加者が写経する時間が思った以上に長いと気づきました。幾つかの深い階層のファイルを編集しつつ、多くのコードを書きつつで、なかなか写し終わらなかったのです。これは練習では気付かなかった誤算でした。説明し切れるぎりぎりの時間まで手を動かしてもらって、結局最後の残り10分はどうしても伝えたかった残りのスライドの要点を説明するだけの次官になってしまいました。それでもなんとか全部のスライドを説明することは出来ました。

振り返り

後から気づいたのは「コードを配布する」ほうがよさそうだということです。私の勝手な思い込みで、説明をしっかり聞きながら順々に進めていけるようにコードの配布はしなかったんですが、コード配っても聞きたい人は説明聞くだろうし、先に進めたい人はどんどん先に進むんだろうなって思いました。これは次に何か機会があれば活かしたいと思います。

しゃべりのほうは、録音したものを聞いてはいないのでよくわかりません。決して良かったとは思っていません。昔からしゃべることが苦手でしたので、聞きづらかったんじゃないかなっと思っています。

最後に

社会に出てまだ2年目に入ったばかりの人間(私)にとって、大人数の前で長い時間講師をするという経験は、なかなかないんじゃないかと思っています。こういう経験をできたこと・機会をもらえたことに感謝しています。またもっと人に教えるという技術を磨きたいなーと率直に思いました。

この記事が、誰かのお役に立てることを願います。みんなも発表とか講師とか、やろうZE☆!

追伸(2011/06/07 00:57): そういえば、立って話しているとき、実は足震えてましたww(マジで

[amazon]487311473X[/amazon]
[amazon]4806139033[/amazon]
[amazon]4062880032[/amazon]

[勉強会]第2回 Symfony2勉強会に参加してきました

Written by uechoco 1月 20
[勉強会]第2回 Symfony2勉強会に参加してきました はコメントを受け付けていません。
この記事を読む時間:137くらい

少し日が経ってしまいましたが、先日2011/01/15(土)に第2回 Symfony2勉強会に参加してきました。会場はZynga Japanさんです。前回に引き続き、今回もワークショップ形式での勉強会です。今回はDoctrine2+MySQLでFormのCRUDを学ぶことがメインでした。

私は前回も今回も1週間前から事前に予習を兼ねてSymfony2を触って勉強会に備えていたので、結構すんなりワークショップの課題を終えることができました。勉強会のために勉強するってすごく理解度が深まるからおすすめですよ!(もちろん、独習するだけど技量と根性と時間を必要としますw)

今回、ワークショップの後にLT大会も行われたのですが、私はその場で飛び入りでLTをすることにしました。題材としては、予習中に作りかけていたSymfony2プロジェクトの紹介です。下部にスライドを貼り付けておきます。

LTってやっぱり緊張しますね。尋常じゃなく緊張しますね。アガリ症な私には大変です。人生初LTをノー準備でやってしまいました(汗。事前準備はしっかりした方がいいですね。そういえば、今年の抱負にLTやるって書いたばかりなので、いい出だしです。今後もLTやあるいはもっと腕を上げてロングトークもやってみたいですね。

[Symfony2]core.requestイベントは2つ以上登録できる?

Written by uechoco 12月 12
[Symfony2]core.requestイベントは2つ以上登録できる? はコメントを受け付けていません。
この記事を読む時間:534くらい

Symfony2でRequestオブジェクトの中身をいじりたいと思っています。入出力の文字エンコードをコントローラ実行の前後で自動的に変換するようなのを作りたいと思っています。RequestオブジェクトはDIコンテナ外のものですが、HttpKernelの内部で引きずり回されてところどころのイベントで使用できます。

ところでcore.requestイベントはEventDispatcher::notifyUntil()で実行されます。メソッド名から判断すると、リスナーが1つでも実行されたらそこで処理が終了してしまうような印象を受けますが、メソッドの説明には「Notifies all listeners of a given event until one returns a non null value.(リスナーの1つがnull以外の値を返すまですべてのリスナーにイベントを通知する)」て書いてあります。どうやらnullを返すリスナーがある(or値を返さないリスナーがある)と次のイベントも実行されるようです。

// /src/vendor/symfony/src/Symfony/Component/EventDispatcher/EventDispatcher.php
[phpcode]
/**
* Notifies all listeners of a given event until one returns a non null value.
*
* @param Event $event An Event instance
*
* @return Event The Event instance
*/
public function notifyUntil(Event $event)
{
foreach ($this->getListeners($event->getName()) as $listener) {
if (call_user_func($listener, $event)) {
$event->setProcessed(true);
break;
}
}

return $event;
}
[/phpcode]

実は’core.request’イベントに標準で登録されているRequestListnerは値を返しません。つまりnotifyUntil()で呼ばれてもイベントがisProceeded()状態になることはありません。ということは、自分で’core.request’イベントにリスナーを追加登録すれば実行出来るってことですね。

実際にHelloRequestListenerを登録してみた

ちなみに、こんなカンジで登録しています。以下のコードを動かす場合はAppKernelへの登録やconfig.ymlへの設定なども必要なので、そこら辺は[Symfony2]PEAR::Net_UserAgent_MobileをDIコンテナから呼び出すなどを参考にしてください。
// /src/Application/HelloBundle/DependencyInjection/HelloExtension.php
[phpcode]

public function configLoad($config, ContainerBuilder $container)
{
$def = new Definition(‘Application\\HelloBundle\\HelloRequestListener’);
$def->addTag(‘kernel.listener’);
$def->addArgument(new Reference(‘service_container’));
$def->addArgument(new Reference(‘router’));
$def->addArgument(new Reference(‘logger’, ContainerInterface::IGNORE_ON_INVALID_REFERENCE));
$container->setDefinition(‘hello.request_listener’, $def);
/** 参考にしたもの:






*/
}
[/phpcode]

HelloRequestListenerのサンプル
// /src/Application/HelloBundle/HelloRequestListener.php
[phpcode]
get(‘request’);
$master = HttpKernelInterface::MASTER_REQUEST === $event->get(‘request_type’);

$this->convertRequestParameters($request, $master);
}

protected function convertRequestParameters($request, $master)
{
if (!$master) {
return;
}
echo “Ok”;
}
}
[/phpcode]

ちなみに、間違って’core.request’でreturn true;とかを返すと「’A “core.request” listener returned a non response object.’」エラーが起きるので注意しましょう。return true;が許されるのは、リスナーからいきなりResponseオブジェクトを生成できる場合(リスナー側でResponseオブジェクトを生成して$event->setReturnValue()に登録した場合)だけです。リクエストURLから判断してファイルキャッシュを取得していきなりResponseで返しちゃう的な感じですかね?

notifyUntilっていうから、絶対に1回しか実行されないのかと思ってたけど、そういう先入観は良くないですね。