はてなの「cybozu.com」記事キャンペーンに当選してレッドブルが72本送られてきた
はてなとサイボウズの共同キャンペーンで、その記事をブックマークすると抽選でプレゼントが当たるという企画がありました。
「クラウド基盤から作りました」――はてなチーフエンジニアとid:TAKESAKOが聞く「cybozu.com」 - はてなニュース
この手のプレゼント運は生まれてこの方全く恵まれたことがないので、普通に面白い記事をブックマークする体で、結果的にキャンペーンに応募したところ、なんと
- レッドブル 250ml缶 x 24 本 x 3ケース
が当たるという思わぬ結果に。
『はてなチーフエンジニアとid:TAKESAKOが聞く「cybozu.com」』記事キャンペーン当選者発表! - はてなブックマーク日記 - 機能変更、お知らせなど
これでもIT業界の端くれなので、自分の周りにはレッドブルジャンキーがごろごろいます。でも私自身に取ってはレッドブルは単に高いだけの健康ドリンクなので、普段はほとんど飲みません。コスパの良いドデカミンの方がよく飲むくらいです。そんな訳で72本とか家に送られてもとても飲みきれません。必然的にジャンキーが多数生息する勤務先、アジャイルメディア・ネットワークに送ってもらうことにしました。
送付先をはてなのWebフォームに入力して数日、無事にレッドブルがAMNに送られてきました。はてなさんありがとう。
ダンボールには中身がレッドブルであることを過不足無く主張した紙が貼られています。
この位の写真を twitter に投下して報告終了しようとしたら、傍らにいた カイさん が、
「タワー建てないとダメでしょ!」
と強烈にダメ出しして来ました。さすが身体中の血管に RSS が流れているアルファブロガーは一味違います。
しかし考えてみれば、なるほどこれをネタに遊ばないのは送ってくれたはてなさんに申し訳ないということで、空いていた会議室にレッドブルタワーを建てることにしました。
ほいほいとレッドブル缶を積んでいき、あっという間にレッドブルタワーが出来ました。
上から見ると、「ミッション:インポッシブル/ゴースト・プロトコル」にも登場して有名になった世界一高いビル「ブルジュ・ハリファ」にそこはかとなく似ている気もします。
ひとしきり撮影された後レッドブルタワーは解体されて、その一部は冷蔵庫に収まりました。すでに数本社内で消費されたようです。
なにせ大量にありますので、近々で AMN に来社する方でレッドブルを飲みたい方は遠慮無くリクエストして下さい。
ということで、このようなプレゼントを頂いたサイボウズさん、はてなさん、本当にありがとうございました。
この記事は最初ははてなブログの方に載せようと思ったのですが、はてブロはリンク記法のimage属性が使えないことに気がついて、仕方なくダイアリーとなりました。はてブロはもう少し頑張って欲しい。
業務連絡 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