読者です 読者をやめる 読者になる 読者になる

Crowi

最近Crowiを触っている。
CrowiはUIがjQueryで組み立てられてて、新しい機能はReactで実装されている。
Reactの範囲がまだ狭いので、全体の動作が把握しやすくReactの勉強にちょうどいい。
既存処理のReact化をちょっとずつやっていこうと思う。

browserifyを試す

とある案件でJavaScriptでブラウザ判別をする必要があり、それではとwoothee-jsを使った。1ファイルにまとまってるファイルがあったので今回はそれを使ったけど、npmのパッケージが用意されてるのでbrowserify使ったらどうなんだろうと思って試してみた。

まずは公式サイトを参考に進めてみる。

http://browserify.org/

作業

インストール。

$ npm install -g browserify

browserify コマンドが使えるようになった。

$ browserify
Usage: browserify [entry files] {OPTIONS}

〜略〜

とりあえず作業ディレクトリを作って

$ mkdir -p ~/dev/labo/browserify/hello-browserify
$ cd $_

npmパッケージをインストール。

$ npm install woothee

main.js を記述。

var woothee = require('woothee');

woothee.parse('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)');

ビルド。

$ browserify main.js -o bundle.js

コードがライブラリと実装コード含めて bundle.js にまとまった。 これを <script src="bundle.js"></script> のように読み込めばブラウザで動くはず。

まとめ

  • 分かったこと
  • 分からないこと
    • require という関数は何なのか
    • require 関数がnpmパッケージを検索する手順

感想

node.jsとかnpmとかの理解が全然足りてないが、JSのパッケージ管理についてとっかかりがつかめた気がする。 次はrequrejsについて調べてみたい。

第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つくるのがいいのかなーという感じです。

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