第2回関西ソーシャルゲーム勉強会に参加しました

参加してきました。
http://atnd.org/events/32096

迷子になってなかなか会場にたどり着けなくて思いっきり遅刻しました。大阪駅周辺はほんとダンジョンです。

後半の二つの発表を聴けました。

Varnish導入事例

varnishは設定を専用の言語で書いてC言語に変換してコンパイルして.soにして読ませるっていう変態的なことをするらしくて、ちょっとおもしろそうでした。設定間違いをコンパイル時に検出できるっていうのは利点だなと。

PHPerなら絶対に知っておきたい3つのソーシャルゲーム開発テクニック

APCの設定でapc_stat=0にしてメンテタイムを短縮するっていうのは目から鱗でした。
Jenkinsは、まあですよねーという感じでした。しかしやっぱり導入が難しいというか、めんどくさい…。
その点、お菓子駆動開発は導入が簡単ということで、やってみたいです、はい。

感想

ネットで見かける情報はほとんどが東京のものばかりですが、関西にもソーシャルアプリとかやってる人たちがいっぱいいるんだなーと思いました。横のつながりとか、助け合いとかして連携してみんな幸せになれたらいいなー。

Twitter見ると前半のAzure発表がおもしろかったらしくて、遅刻して聴けなくてざんねんでした。
ぶっちゃけAzureはスルーしてたんですが(すいません!)、いただいた資料を見るとすごいいい感じで、導入事例もいっぱいあるし、なんか申し訳ないくらいの手厚いサポートとUIのわかりやすさでちょっと試してみたくなりました。こんど会社で提案してみようかなー、と。

サイバーエージェントの会場はきれいで広くて、とてもよかったです。無線LANも完備だし。窓からの景色も最高でした。写真撮れば良かった。
しかし、こんどこの会場で行われる関西PHP勉強会で発表するんですが、ここで話すのかと思うと、震えますね、、。

第4回関西PHP勉強会
http://atnd.org/events/32233

Re: CakePHP 2.x系の更新時のSQL発行回数を減らしたい

http://damepg.hatenablog.com/entry/2012/09/08/134126

ちょうど最近同じことやってました。
僕の場合は、updateAll()で対応しました。

元エントリの例にならうと、こんなかんじ。

<?php

public function addPoint($user_id, $point) {
    $ret = $this->updateAll(
    	array('point' => $this->escapeField('point') . ' + ' . $this->getDatasource()->value($point)),
    	array('id' => $user_id)
    );
    if ($ret === false) {
        // エラー処理
    }
    if ($this->getAffectedRows() == 0) {
        // エラー処理
    }
}

発行されるSQLはこんなかんじ。

UPDATE `sample`.`users` AS `User`  SET `User`.`point` = `User`.`point` + 10  WHERE `id` = 1

updateAll()使う利点としては、

  • aliasなど、モデルの設定の恩恵を受けられる
  • 検索条件がfindと同じ形式で設定できる

いっぽう欠点としては、

  • setするフィールド値のエスケープがめんどくさい

というところかなぁ、と思います。

あと書いてて気付きましたが、どちらの方法もmodifiedが自動更新されないのできちんと指定してやらないといけないんですね。

参考:
"updateAll" フォーラム - CakePHP Users in Japan
Ceatant Official Blog - CakePHPでupdateAllを使うとmodifiedを自動で更新してくれない

Cookbook のコミッタになりました

昨日から、Cookbookのコミッタになりました。
もうちょっと正確に言うと、cakephp/docsリポジトリへのコミット権を与えられました。
具体的には、リポジトリに直接コミットしたり、pull requestをマージしたりできるみたいです。

Cookbookのコミッタなので、CakePHP本体にコミットしたりとかはできないです。
なので「CakePHPのコミッタ」というわけではないです。

いつものように息抜きにぼんやりGithubにアクセスしたら、「You’ve been added to the cakephp organization!」て表示があって???てなりながらリンクたどったらcakephpのページに自分の名前があってマジビビりました。
あとでメール確認したら、コミッタのMark Storyさんから「追加しといたから!」的なメールが来てました。

僕のコミットはtypoの修正がほとんどで、それに比べたら他の人たちの方がすごい量の翻訳しまくったりしてるので、なんで自分が?という気がしなくもないですが、ともあれ微力ながらも自分のやったことが認められたようでうれしいです。

今後も特にやること自体は変わらないと思うので、地道に着実に作業を進めていければいいなーと思います。

CakePHPのドキュメントにpull requestした

まだ勝手がよく分からないので、とりあえずwarningつぶすのと左のメニューの並びを直すのをやりました。

https://github.com/cakephp/docs/pull/329
https://github.com/cakephp/docs/pull/330

どちらも無事に取り込まれてまずはよかったです。

もうひとつ、トップページのダウンロードリンクの追加もpull reqしたんですが、

https://github.com/cakephp/docs/pull/332

「日本語のPDFが無いよ」てツッコミが入ってしまいました。
@cakephperさんにアドバイスいただいて、いったん英語版のPDFにリンク先を切り替えました。



どうなるかなー。

CakePHPのログシステムを理解する

Cakeのログまわりはあまり使ってなかったので、調べてまとめてみました。
CakePHP 2.0のコードを元に書いていますが、1.3とか2.1とかでもだいたい同じみたいです。

ログシステムの構成

  • CakeLog
  • CakeLogInterface

の二つのクラスで構成されています。
「CakeLogInterface」は長いし意味が分かりにくいので、以降は「LogEngine」と呼ぶことにします。

基本的なログ出力方法

  1. Object::log($msg, $type)
  2. CakeLog::write($type, $message)

どちらかを使います。
Object::log()はCakeLog::write()を呼び出しているだけなので、どちらでもいいと思います。

<?php
// Object::log()
$this->log('message', 'debug');

// CakeLog::write()
CakeLog::write('debug', 'message');

ログ出力の流れ

  1. Object::log($msg, $type)
  2. CakeLog::write($type, $message)
  3. CakeLogInterface::write($type, $message)

の流れで処理が進みます。

LogEngine

CakeLogはLogEngineに処理を委譲するのみで、実際のログ出力は各LogEngineが行います。
LogEngineは、CakeLogから受け取ったログメッセージとログタイプをもとに、どこにどういうログを出力するかを判断し実行します。

デフォルトでは、ログメッセージをファイルに出力するFileLogが用意されています。

type ≠ level

CakePHPのログシステムは、ログの出力レベルについては関知しません。
ログ出力のメソッドの引数で"debug"とか"error"とかを渡せるので、デバッグレベルと連動してログ出力レベルを切り替えてくれそうな気がしますが、あくまでもただの分類(type)なのでとくになにもしてくれません。
ログを出力するかどうかの判断は基本的にはユーザーにゆだねられているみたいです。

複数のLogEngineを設定できることの意味

CakeLogにはLogEngineを複数設定できます。
しかし、CakeLogは設定されているすべてのLogEngineに対して等しくログ出力を委譲するので、特定のログタイプだけ特定のLogEngineで出力する、というような機能は、CakePHPのログシステムにはありません。
呼び出し側でも、ログ出力時にLogEngineを指定することはできません。

CakeLogとLogEngineの関係は、イベントディスパッチャーとイベントリスナーのような雰囲気になっています。

まとめ

  • CakePHPのログシステムはCakeLogとLogEngineで構成される
  • ログタイプはログレベルではない
  • LogEngineはイベントリスナーみたいな雰囲気

感想

CakePHPのログシステムはわりと簡素な作りで、デフォルトではメッセージをログファイルに書き出すだけです。
でもLogEngineでそれなりに自由に拡張できるので、もの足りないときは自分でLogEngineつくるのがいいのかなーという感じです。

なにか間違ってたり足りないことがありましたらツッコミよろしくお願いします!

気になるプロダクトなど

ChiliProject
Redmineから派生したやつ。アップデートが早そう?

CandyCane
RedminePHP移植。設置が簡単なのが魅力。REST API対応したらいろいろ夢が広がりそう。

Pivotal Tracker
タスク管理するやつ?iPhoneとかにも対応してるらしい。

Amon2
PerlのWEBアプリケーションフレームワーク。なんとなくとっつきやすそうな雰囲気。

enchant.js
JavaScriptのゲームライブラリ。ライトなゲーム作成ならネイティブアプリでやるより効率よさそう。

fluent
イベントログ収集ツール。ソーシャルゲームとかでユーザーの行動ログとるのにいいかも。

WebSocket
なにやらいろいろ夢が広がるらしいけど、あまりよくわかってない。

PhpStorm
PHPのIDE。いいらしい。

Travis CI
githubのリポジトリでCIしてくれる。

Sismo
シンプルなCIサーバ。


なんとなく「Redmineの次」というのがそろそろ来るのかなーとか思ったりしますが、どうなんでしょう。
そのへんの話を今度のRxTstudyで聴けるのかな。
個人的には手元に簡単に設置できるようなタスク管理ツールがほしくて、その点でCandyCaneには期待しています。

5.2でprivateとかprotectedなプロパティを取得する方法

5.3ならReflectionProperty::setAccessible()でいけるけど、5.2では定義されてない。

PHP Manualの下のコメントに解決方法がかいてあったので、参考にしてやってみた。
http://jp2.php.net/manual/ja/reflectionproperty.setaccessible.php#98383

対象のクラスを継承した、非公開プロパティへのアクセサを持った子クラスを生成する方法。
でもこれだと子クラスのインスタンスを毎回生成するので、対象の内部状態が変わってた場合うまく取れないと思う。

どうしようかと思ってたら、その上のコメントで「arrayにキャストしたらいいよ」みたいなこと書いてあった。
http://jp2.php.net/manual/ja/reflectionproperty.setaccessible.php#100441

こちらの記事を参考にやってみた。
http://d.hatena.ne.jp/shimooka/20090608/1244428241

いいんじゃないかと。