業務連絡 Symfony Advent Calendar JP 2011 参加者の皆さんへ
ATND のメッセージですでに送らせて頂きましたが、メールアドレスの設定をしていない方も何人かいらっしゃるので、ここでも書いておきます。
Symfony Advent Calendar JP 2011 では、Gihyo Digital Publishing さんの「技術系アドベントカレンダーを電子書籍化する企画」に乗る予定です。
2011年の技術系Advent Calendarを電子出版で提供しませんか? | Gihyo Digital Publishing
つきましては、今回のアドベントカレンダー参加者の中で自分のエントリは電子書籍化して欲しくないという方は、12/29 までに以下のいづれかの方法でその旨表明して下さい。
どうぞよろしくお願いします。
アドベントカレンダーと勉強会文化
クリスマスが過ぎ、各コミュニティで開催されていたIT系アドベントカレンダーもみな一段落したようです。自分も今年は PHP Advent Calendar jp 2011とSymfony Advent Calendar JP 2011に参加して、それぞれ記事を書かせてもらいました。
特に Symfony の方は、成り行きで取りまとめ役になってしまい、運営サイドのやきもきもちょっと経験できましたw。
昨年くらいから盛り上がりを見せてきたIT系アドベントカレンダーですが、gihyo.jp さんの記事によると、今年はものすごいことになっています。
本日12月1日より,プログラマ有志による2011年の技術系Advent Calendarが各所ではじまる:インフォメーション|gihyo.jp … 技術評論社
1ヶ月弱という短い期間に、これだけ大量の技術記事が一気に投入され、ノウハウが共有されアーカイブされていくのですから、日本は凄いところに来たなぁと割りとマジで思います。
その基板になっているのは、ここ5年くらいで徐々に広がってきていた勉強会文化(もう文化と呼んじゃっていいよね)が熟成させてきたIT系コミュニティなのでしょう。かつて勉強会ムーブメントを目の当たりにしたときに、これはひょっとして日本の社会を変えるんじゃないかと考えて「IT Community Impact!」というイベントを企画したりしました。
最近のこの手の盛り上がり方を見てると、日本人は情報発信が苦手なんて誰が言ったんだろうと思いますw。お祭り好きで自分の好きな事を話したり聞いたりするのが好きな日本人像に、割りかし明るい未来が見えたりするのは自分だけでしょうか?
Nexus SをAndroid 4.0にアップデートした
Nexus S 向けに Android 4.0.3 Ice Cream Sandwitch がリリースされたという報道がありました。1日待っても自動で OTA する様子がなかったので手動にてアップデートを行いました。
手順は以下にある通り。
[INFO] Nexus S Official ICS 4.0.3 Released D… | Samsung Nexus S | XDA Forums
定番ボタン付きの ICS は案外使い易い
友人の Galaxy Nexus をこれまでに何回か触らせてもらいましたが、いろんな人がすでに書いている通り、メニューボタンの場所がコロコロ変わるのは UI デザインの改悪としか思えませんでした。Nexus S の場合は、端末が持っているメニューボタンがそのまま使用できるので、その点は不満はありません。
設定項目の増減
設定項目に無くなったものがあります。例えば、従来は確か「ディスプレイ」カテゴリにあった「アニメーション」の設定が無くなっています。つまり ICS では画面のエフェクトアニメーションが常に有効になっています。
また「開発者向けオプション」がかなり拡張されていて、
- 厳格モードを有効にする
- ポインタの位置
- タップを表示
- 画面の更新を表示
- CPU 使用状況を表示
- ウィンドウアニメスケール
- トランジションアニメスケール
などなど、多くの項目が追加されています。
子プロセス制御ふたたび : PHP Advent Calendar jp 2011 Day 8
はい、7日目の @scriptwork さんのエントリ「DateTimeクラスの落とし穴と対策 : PHP Advent Calendar jp 2011 Day 7」から引き続いて、PHP Advent Calendar jp 2011の8日目なわけです。
今回は何を書こうかずいぶん悩んで、ちょうど昨晩開催されたPHP忘年会2011@関東でネタ募集したところ、@sizuhikoさんが口走ったphpQueryネタをパクるという案もあったのですが、やはり正攻法で手持ちのネタでいくことにしました。
子プロセスfork
このはてなダイアリーでの数少ないPHPヒットネタとして「pcntl extensionを使って一定個数の子プロセスに作業させる方法 - Blog::koyhoge」という記事がありまして、公開した2007年以来ぼちぼちとずっとアクセスを稼いでくれております。
ただこの時に書いたサンプルコードも、話を単純にするためにグローバル空間にベタ書きですし、今となってはあまり良いサンプルとは呼べません。実は今年になって、とある目的できちんとクラス化したものが作ったのでそれを紹介しようと思います。
きっかけは Amazon SQS+SDB のワーカー
その目的というのは、AMN の広告配信ログサーバを改善する際の途中成果として作成した、キューからデータを取ってきて DB に入れるワーカー処理です。11月15日に開催された「第7回 MongoDB 勉強会 in Tokyo」で発表した以下のスライドで、そこに至る背景と経緯を説明しています。
ProcessForker クラス
では早速コードを見ていきましょう。
<?php class ProcessForker { // defaults protected $_options = array( 'max_children' => 10, // max number of child processes 'process_limit' => 0, // return when this count tasks are finished 'loop_task' => false, // reuse tasks 'sleep' => 0, // microseconds 'single_execution' => null, ); protected $_idx_task = 0; public function __construct($options = null) { if (!empty($options)) { $this->_options = array_merge($this->_options, $options); } } public function fetchTask(&$tasks) { if ($this->_options['loop_task']) { $idx = $this->_idx_task; $task = $tasks[$idx]; // circulation in tasks ++$idx; if ($idx >= count($tasks)) { $idx = 0; } $this->_idx_task = $idx; } else { $task = array_shift($tasks); } return $task; } public function run($tasks) { // number of current running child processes $nchildren = 0; // number of finished task $nfinished = 0; for (;;) { if (empty($tasks)) { break; } $maxproc = $this->_options['process_limit']; if (($maxproc > 0) && ($maxproc <= $nfinished)) { break; } if ($nchildren <= $this->_options['max_children']) { $task = $this->fetchTask($tasks); $pid = pcntl_fork(); if ($pid === -1) { throw new Exception('pcntl_fork faild'); } else if ($pid) { // parent process ++$nchildren; } else { $exit_code = 0; // child process $func = $task[0]; $arg = $task[1]; if (!is_array($arg)) { $arg = array($arg); } try { call_user_func_array($func, $arg); } catch (Exception $e) { $exit_code = -1; } // care singleExecution: // child process must not unlock $se = $this->_options['single_execution']; if ($se !== null) { $se->setDoUnlock(false); } exit($exit_code); } $sleep = $this->_options['sleep']; if ($sleep > 0) { usleep($sleep); } } else { $pid = pcntl_waitpid(0, $status, 0); --$nchildren; ++$nfinished; } } } }
前回は決め打ちだった各種パラメータや実際に実行する処理を、すべて外部から渡せるようにしてあります。
使用例
この ProcessForker クラスは以下のように使用します。
<?php require_once 'ProcessForker.php'; function hoge($str) { srand(); $rand = rand(1, 5); echo "$rand: $str\n"; sleep($rand); } $opts = array( 'max_children' => 4, 'process_limit' => 50, 'loop_task' => true, ); $pf = new ProcessForker($opts); $tasks = array( array('hoge', 'a'), array('hoge', 'b'), ); $pf->run($tasks);
まずはオプションを指定してProcessForkerオブジェクトを作ります。それぞのれオプションの意味は以下になります。
max_children | 子プロセスの最大同時実行数 |
process_limit | いくつのタスクを処理したら終了するか |
loop_task | 渡されたタスクを繰り返すかどうか |
sleep | 親プロセスが処理を行うたびにスリープする時間(us) |
single_execution | singleExecutionオブジェクト(後述) |
この例では、
- 最大4つの子プロセスを起動し (max_children => 4)
- 全部で50回の処理を行い (process_limit => 50)
- タスクを繰り返しながら (loop_task => true)
実行するという意味になります。
タスク指定
子プロセスとして処理するタスクは、配列の形で渡します。
array(<callable>, <引数>)
callable はPHPの is_callable() でtrueとなるもので、以下のどれかになります。
- 関数名文字列: 'hoge'
- オブジェクトとメソッド名の配列: array($obj, 'hoge')
- クラス名とメソッド名の配列: array('Hoge', 'hoge')
- (PHP-5.3 以降は)無名関数やクロージャ
タスクへの引数は、ひとつの場合はそのままで構いませんが、複数の場合はそれも配列にして渡します。
繰り返し処理
loop_task オプションが true になっていると、渡されたタスクをすべて処理し終えてても終了せずに、またタスクリストの先頭から処理を行います。同じ処理を何度も繰り返したいときは、タスクを1つだけ用意して loop_task を true にすれば良いです。
single_execution 対応
常にプロセスが動いていて欲しい場合は cron で毎分キックするということをよくやりますが、しかし大元の親プロセスが複数立ち上がってしまうのは好ましくありません。そこで @bto さんが作られた single_execution を利用して、同時起動チェックを行いました。しかし単に ProcessForker と single_execution を組み合わせるだけではどうも上手く動いてくれません。
調べたところ ProcessForker から起動された子プロセスが、プロセス終了時に singleExecution の管理しているロックファイルを削除してしまっていることが解りました。single_execution はそこから更に子プロセスが fork されることなど想定していないので当然ですね。
ということで、single_execution.php にパッチを当ててプロセス終了時のロック解除を選択できるように変更しました。ProcessForker 作成時の single_execution オプションに singleExecution オブジェクトを渡せば、子プロセスの場合はロックを解除せずに終了するようになっています。改変した single_execution.php は以下に置いてあります。
これですでにプロセスが動作しているかどうか気にせずに、cronからスクリプトを定期的に起動するだけで、複数プロセスで動的に処理を行なってくれるようになりました。
明日の Advent Calendar は @takuya_1st さんです。
TwigからEntity::findするフィルターを書いてみた (Symfony Advent Calendar JP 2011 2日目)
初日の @brtriver さんに引き続き Symfony Advent Calendar JP 2011 の2日目です。
ここ数ヶ月 Symfony2 を触っています。実は Symfony 1.X の頃は興味ありながらもほとんど触っていなくて、2になってから触り始めたビギナー&ニューカマーなんです。諸先輩方よろしくお願いします。
Symfony Advent Calendar JP 2011ができるまで
昨年はSymfony Advent 2010をやっているのは知ってたので、今年はどうするのかなーやらないのかなー? と思って
Symfony Advent Calendar 2011 はやらないのかな?
@koyhoge 是非お願いします!
2011-11-21 18:41:04 via YoruFukurou to @koyhoge
@hidenorigoto あー ATND 立てれば良いですか?w
2011-11-21 18:45:49 via Echofon to @hidenorigoto
@koyhoge はいー!
2011-11-21 18:47:16 via YoruFukurou to @koyhoge
Twig フィルターを書いてみた
プロパティの動的参照
さて本題です。Symfony2 の標準テンプレートエンジンの位置にある Twig ですが、開発しているのが Symfony の作者である Fabien さんだけあって、View としての役割がきっちり守られていて、余計なことはできないようになっています。
例えばオブジェクトのプロパティを動的に取得するようなことも、現在 Symfony2 にバンドルされている Twig 1.1.2 ではできません。Github Issues で話題になった時も Fabien は
This feature won't be included in Twig. Twig is a template system, not a fully-features language. Dynamic properties is clearly out of Twig scope.
https://github.com/fabpot/Twig/issues/41
訳: それは Twig の機能として含まれるべきではないよ。Twig はただのテンプレートシステムでフル機能の言語じゃないんだ。動的なプロパティ参照は Twig のスコープ外だよ。
と答えています。(その後考え直したのか Twig 1.2 から attribute 関数が導入されて、オブジェクトのプロパティを動的に取得できるようになりました。)
Entityから動的に取得する Twig フィルター
さて今回作成した Twig Filter は、Entity に対して検索をして値を取得するという、上記をさらに一歩踏み越えたある種のキワモノです。ロジックは Model や Controller でという原則からは外れるので安易に使うべきではありません。とは言えそういうキワモノを作るにはそれなりの理由もあるのです。
たとえばユーザの属性情報を考えてみましょう。ユーザはたくさんの属性情報を持っている場合があります。そのたくさんの属性のうちどれをどうやって表示するかを決めるのは View ですが、それを実際に表示するには Model や Controller 側でお膳立てをしておく必要があります。あるアイテムの所有者としてユーザ情報を表示するときに、そのユーザ情報の種類がすごく多かったり、直接 JOIN できなかったりする場合、M/C 側で全てを準備することは逆に現実的ではないと思うのです。
Symfony2 で Twig Extension
ということで、こんな Twig フィルターを作りました。
<?php namespace Koyhoge\HogeBundle\Twig; class HogeExtension extends \Twig_Extension { public function getFilters() { return array( 'entity' => new \Twig_Filter_Method($this, 'entityFilter'), ); } public function entityFilter($entity, $id, $prop, $by = null) { if (empty($by)) { $obj = $entity->find($id); } else { $objs = $entity->findBy(array($by => $id)); $obj = $objs[0]; } if ($obj == null) { return ''; } $method = 'get' . ucfirst($prop); $call = array($obj, $method); if (!is_callable($call)) { throw new \Exception('Not callable:' . $method); } return call_user_func($call); } public function getName() { return 'hoge'; } }
使い方:Controller 側
Controller 側で以下のように Entity を直接 Twig に渡します。
<?php namespace Koyhoge\HogeBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class DefaultController extends Controller { public function indexAction() { $users = $this->getDoctrine()->getRepository('KoyhogeHogeBundle:User'); $items = array( array('user_id' => 1), array('user_id' => 11), ); return $this->render('KoyhogeHogeBundle:Default:index.html.twig', array('users' => $users', 'items' => $items)); } }
使い方:Twig テンプレート側
テンプレート側では以下のように呼び出せます。
{% for item in items %} {{ users|entity(item.user_id, 'name') }} {% endfor %}
{{ users|entity(item.user_id, 'name') }}
の部分で、User Entityから item.user_id で find() を行い、その結果のオブジェクトから name プロパティを取得する、という処理を行います。
他のキーで findBy()
別のユニークキーで findBy() したい場合は
{{ users|entity(item.other_id, 'name', 'other_key') }}
などのように3番目の引数に渡します。
まとめ
正直あまり実用的ではない tips ですが、View に必要なデータを Controller 側ですべてお膳立てするのはなんか違うなーと感じていたので、試しに実装して見ました。何にでも多用することは危険だと思われますが、デザインの都合によっていつ表示するか分からない基本的な情報をこのやり方で処理するのは、有効なのではないかと思っています。
明日は、今回の Advent Calendar 企画を私に振った張本人、日本の Symfony 界の重鎮 @hidenorigoto さんです。よろしくお願いします!
はてなブログはじめました
はてなブログで初エントリーを書きました。他の人が短い記事ばっかりだったので、無理矢理でもそこそこ長めのものをw
そろそろPHPMatsuriについて書いておくか
Photo CC by @suzuki
PHPMatsuri については「闇」で発表したスライドの記事を書いたのでそれでいいかとも思ってたんだけど、いやもっとちゃんとブログを書こうと思い直したばかりだったし、せっかくだからもう少し書いておきます。
大阪入りする前から今回の PHPMatsuri で何をするか考えていても何も浮かばなくて、実際にイベントが始まって一応とあるライブラリの extension を作ろうかと思いついたのだけど、さすがに準備が全然できてないので VirtualBox に CentOS 6.0 x86-64をインストールして環境をほげほげしてたら時間切れになってしまった。
まあそれでも、仕事で悩んでた Symfony2 の Bundle の設計について明確な回答をもらえたり、闇PHPMatsuri で Net_IPv6 に送ったパッチの発表をしたり、光画部活動でたくさん写真を撮ったりで、楽しかったし得るものもそれなりにありました。
TDD や CI など今日びの開発手法を多くの人達が使いこなしているのを見て、自分も負けてられないなぁと思いました。PHP は Web 開発業界では底辺に見られがちだけど、開発効率や信頼性を高めるべく新しい技術を貪欲に取り入れる人達もたくさんいます。PHP の言語仕様がダメダメな部分は分かった上で、素晴らしい設計をしたり素早く素晴らしいコードを書くことはできるし、それらを広めることで下らない苦労をする人が一人でも減れば PHP の可能性をもっと広げることにもなるのだと思います。
参加者はすでに日常に戻り日々のコードとの戦いに復帰しているのだと思われますが、年に一回くらいはああいう特別な場所で、熱い想いを持っている人達の空気にどっぷり浸かるのも、エンジニアとしてしての生き方には必要なのだろうと思います。
そう、終わってみて分かる。あれは「特別な場所」でした。来年の開催はまだ不明ですが、今年いろんな理由で参加を躊躇した人は一度は参加してみることを強くお薦めします。
2日目午前中の光画部活動
@lllnoriko4lll の「今年も撮影散歩行こうよー」という一言で、PHPMatsuri 会場の国際交流センターから、インテック大阪の横を通り、ATC まで撮影しながらぐるっと歩きました。
南港の辺りは埋立地ということもあって、どうしても風景がお台場とかぶりますね。今回の見た中にはすでに廃墟になりかけている建物もあったりして、10年後のお台場もひょっとしてこんな感じなのだろうかと感傷にふけれます。
その他の写真はこちらから。
20111016-osaka - an album on Flickr
帰京途中に寄った大阪駅ビルからの夜景がすごかった
帰りは @NEKOGET @shin_okamatsu と一緒に帰ることになったのですが、二人とも新しい大阪駅の駅ビルをまだ見てないというので、ちょっと寄り道してノースゲートビルディングを観光してきました。
自分が前回来たときには大雨で見ることができなかった屋上農園も、今回はばっちり見学できました。
前回はまだ骨組みだけだった駅北側のビル群も、今回見たらずいぶんと出来ていて、なんかもう物凄くなりそうな予感が今からプンプンします。楽しみ。
その他の写真はこちらから。
20111016-Osaka Station - an album on Flickr