cakephpはフルスタックフレームワークで進む

将来のcakephpについてCakeMatsuri懇親会でGrahamとJoelに質問してみた。
正直に言えば、知ってる英単語とサービスを並べたらどうにかがんばって理解して答えてくれた。

質問
最近pythonでもperlでもrubyでもフルスタックなフレームワークが小さなプラガブルなフレームワークに変わっている。ruby on railsさえも!
フルスタックのフレームワークcakephpはこれからもフルスタックのフレームワークなの?それとも?

答え
Graham
cakephpはこれからもフルスタックのフレームワークだよ

Joel
cakephpはこれからもフルスタックのフレームワークだよ
全部入りを求める人たち・アプリケーションとそうでないという人たち・アプリケーションは別のターゲットにいる
一番いいと思う選択を提供したい
(ORMやテンプレートエンジン選べるようにならないかな?ってきいた)
cakephp2からmodel層がActiveRecordパターンからDataMapperパターンに変わるから、DataMapperの先が今以上にフレキシブルに書けるようにはなるよ
Merbのプラガブルなのいいよね
(Doctrineの話をしてくれてよくわからなくて聞きなおして3回ぐらいかみくだいて説明してくれたけどわからなかったのでわかったことにした)

感想と余談
懇親会の話は懇親会だけにとどめておくものだという正論は忘れた。
将来のcakephpについて講演してたgrahamに聞くのが本命だったのだけど、先にgrahamに聞いてうまくいかなかった部分をブラッシュアップしてJoelに聞けたので、結果的にJoelのほうがいっぱい話を聞けた。

そのあと自分が聞きたこと聞けて満足してたら
Joel「今日のトピックのなかで何が一番エキサイティングだった?」
て逆に質問された
ぼく「将来のcakephpの話が一番だった」
ぼく「あ、次はkey-valueの話」
とってつけたみたいに付け加えちゃったので
ぼく「クラウドやスケーラブルなプログラミングにも興味あるよ!」
って自分から話振った上にあわわになるなどどうしようもなかったりもした。
共用サーバはもうありえないよな、というところで一致した。
あんまり中身のあることしゃべれなかったけどいっぱいいっぱいだったので仕方ない。
文字に起こしてみたら質問の答えも満足に得られてないことが判明したけどいっぱいいっぱいだったので仕方ない。

一生懸命聞いてくれる相手に意図を伝えられるぐらいには英語使えるようになろうと思った。
CakeMatsuriの中でぼくにとってはこの会話が一番エキサイティングだったよ、ありがとうGraham、ありがとうJoel。
I thank Graham and Joel. Talking with you is my most exciting topic in CakeMatsuri.

フレームワークの話を聞いてきた

events.php.gr.jp – 第42回PHP勉強会@関東
http://events.php.gr.jp/events/show/75
に参加してきました。

CMSとフレームワークの話
CMSの中にかんたんなCRUDのアプリを入れたい、逆にフレームワークの中にCMSを組み込みたい、という要望はよくある。特に利用者の学習・習熟を考えるといちいちリセットしていられないというのはわかる。検討はしても最終的に組み込んだことはまだないので、実際に使っている(使おうとしている)話は参考になった。

複雑なSQL使ったときもモデルの便利機能使いたい話(propel)
レールから外れるときに「レールから外れるとフレームワーク使えねー」にいくのではなくどうにかしてレールに戻す方法考えれば楽なので、あとはその戻す方法だという話。
具体的には、DBのテーブルと1対1では紐づかないモデルの話。自分でレコードセット取ってきて、レコードセットを解釈してモデルの一般的なオブジェクトに落とし込むところに、自分で突っ込んでやればよい。そういうのはメソッド追っかけていけば直感で分かるとのこと。
参照だけなんだからもっとやりようあるんじゃね?とか同じモデルの中においた方が見通しよくね?とかはたぶん話の本質でないので措く。

じゃあどこにまとめるかって言うのは考える余地があると思う。syuukeisとかいうモデルは作りたくないもんなあ。

サービス志向の話(mobasif)
携帯向け軽量フレームワークの話。サービスをすばやくリリースして回収するところを志向してすべてが作られている。開発の機動力重視。アプリの層が薄いこと(=軽いこと)による処理速度重視。

ディスパッチャにユーザ認証が組み込み。
ユーザ認証は、端末固有番号を用いたいわゆる「かんたんログイン」がメイン?
いきなり書くときはべたっとSQLを書くときもある、再利用するときにはじめて切り出す。
フレームワークにも手を入れる。サービスごとのmobasifがあり、それは公開しているものともまた違う。スケルトンとしてのmobasif。

互いのサービスが疎になっていて(なっているのかな?)、インターフェイスさえ変わらなければ別にいいのかな、とも思う。

全体的に思ったこと1 テスト
フレームワークは自身のプロジェクトで十分テストが行われているので、フレームワーク自体を疑うテストコードは書かない。に染まりつつある自分としては、それを書かざるをえないのは直感的にいやだ。でも、きっとそこは見通しのよさでカバーするんだろう。というか本体に直接手を入れようと、継承してきて自分で手を入れる仕組みが出来ていようと、結局把握してないとダメなのは変わらないのか。

全体的に思ったこと2 情報が来てないのかそれとも感じていないのか
自分の話。アウトプットとインプットの比率がいびつで、アウトプット不足を個人的にはどうにかしたいのだけれど、そもそもインプットも足りてないのを実感。過多なぐらい情報はあるんだから集め方と飲み込み方が悪いんだなあと思う。

全体的に思ったこと3 ライブラリ
pear, pear2, openpear, github, coderepos,
…場はいっぱいあるんだけどどうライブラリを利用したものかずっと困り中。どのライブラリがトレンドでどれがdeprecatedなのか追いつけていない。もっと低次元で言えば、検索で引っかかったブログのエントリ中のコードをコピペするのはさすがにもうやめたい。

===

Keep
会場運営ありがとうございました。
thechaw(チョー)…cakephp界のgithubを教えてもらった。

Problem
電源はあるけど自分の席まで届かなかった。次は延長コードとタップ的なものを持参する。

Try
懇親会で質問できたけど、勉強会でも質問する。
勉強会では名札してたけど、懇親会では外してしまった。つけとく。

CakePHP Users in Japanの勝手に全文配信RSSを組み立ててみた

Yahoo Pipesフォーラム – CakePHP Users in Japanの勝手に全文配信RSSを組み立ててみました。
Pipes: CakePHP Users in Japan (Show All Unofficially)
http://pipes.yahoo.com/pipes/pipe.info?_id=5ad195a09b02662e1fdb1574a35e83d4

作って一人で使っているのはもったいない、でも作ったのですが作ってないわけですから(微妙なニュアンス)、おおっぴらに広めるのは直感的にまずい気もします。CakePHP Users in Japanの中の人が明確にNOと言ったら止めます。


実は「組み立ててみました」というのはかなり語弊があって、途中まで作ったところでニッチもサッチも行かなくなって「ここまで作ったんだけどわかんないよ!助けて!」ってダメもとで公式掲示板に嘘英語で質問投げたら、charsetを巧みに操るUKの超人が現れてほぼ書き直してくれました。すげえ。あとUKの人の元ネタのヘッダ変換サービス提供してくれている中国の人にも感謝。顛末のURLも載せておきます。たどると私の書いた拙い方のPipeも見られます。

Yahoo! Message Boards – Developer Help – In foreach loop, How can I use valiables? http://discuss.pipes.yahoo.com/Message_Boards_for_Pipes/threadview?m=te&bn=pip-DeveloperHelp&tid=3699&mid=-1&tof=2&rt=2&frt=2&off=1#-1


もうちょっと抽象化すればもっと使えるのかな。私にはこれで必要十分だからまあいいや。 ただ、甘やかされすぎなのもまずいのでそのうち使い方のエントリも書く予定。

Remoraを眺めてみた2

Remoraを眺めてみた感想メモその2。

實松アウトプット: Remoraを眺めてみた1
http://sane.justblog.jp/blog/2008/02/remora1-e01b.html

Revision 10695: /addons/trunk/site
http://svn.mozilla.org/addons/trunk/site/

全部要る時だけbindFully

$hasMany_full,$hasAndBelongsToMany_full,$belongsTo_full
を書いておいてフル必要なときにbindFully()でバインドするっていうのはいいね。

bindModelかSQLか

条件つけたり取り出す順番だったりってのは前に書いたようにbindModelで出来る。
でもRemoraはモデルに直にSQLで書いちゃってる。まあわかりにくいもんなあ。SQLで書いちゃったほうがミスも少ないし速い(速い人は速いしそういう人が多いはず)。ただ私の場合SQL書くにもドキュメント見ながらだし、arrayで書くのとあんまり変わらない。bindModelならデータベースの差異を吸収できる(はず)っていうのはあるけど。ひょっとすると速度的な問題もあるのかな。remoraはどこみてもMySQL専で書かれているし。

bindModelの上手な使い方

addons_controllerのversionsメソッド一部抜粋

$bindusers = array('hasAndBelongsToMany' => array('User' => $this->Addon->hasAndBelongsToMany['User']));
$this->Addon->unbindFully();
$this->Addon->bindModel($bindusers);
$addon = $this->Addon->findById($id, null, null, null, null, 0);

なるほどなるほどー。一番勉強になったのはここ。このbindModelの書き方はかっこいい。そうかこれならすっきりだ。

なんだかんだで結構fatなコントローラ

基本的にSQLのクエリのべた書きが必要なもの以外はコントローラで済ませちゃってる。いくつかコントローラにSQLべた書きしているところもある。かなり効率的に分かりやすく書かれているけど、なんだかんだで結構fatなコントローラだ。getActiveUserByMail($mail)とか作ってちょっとずつ条件の違うメソッドでモデルが埋め尽くされるのとどっちがましなんだろう。これは一見thinに見えるけど結局いちいちモデル確認しなきゃいけないんだよね。あ、でも全部丸ごとモデルに押し込んじゃうとアソシエーションを設定するためにはあらかじめアソシエーションが無いと直には読めないのか。でもやっぱりコントローラ経由すれば読めるのか。やっぱりappimportしちゃえばいいのか。どっちがマシかはまだよくわからない。

まだ続くかも。そのうち。

訂正:scaffoldにBasic認証をかける

エントリの訂正です。

實松アウトプット: scaffoldにBasic認証をかける http://sane.justblog.jp/blog/2008/02/scaffoldbasic-d.html


var $protectedActions = array(‘index’, ‘add’, ‘edit’, ‘delete’);
+
var $protectedActions = array(‘index’, ‘add’, ‘edit’, ‘delete’, ‘view’);

に訂正します。登録データが全部見えちゃう!というか見えてた!

pmaimai Social Network Service by PHP

pmaimaiはCakePHPで作られている作りかけのSNSです。

pmaimai – Google Code
http://code.google.com/p/pmaimai/

プロフィール、日記、メッセージ、マイフレンドの機能があります。
ライセンスはMITです。
動作環境はPHP5です。
ドキュメントは0です。


形になった段階で公開する予定だったのですが、それを待っていると一生公開出来ない気がしたので出来損ないの段階で出しておきます。逆に、それっぽい形になったところでいったん終了ということにします。OpenPNEあるし。

「私はこれぐらいのことが出来るよ!」というプレゼンのつもりで基本的なものを作っていたのですが、結果的に「私にはこれぐらいしか出来ないよ!」というプレゼンになってしまっている皮肉です。

findByFooBar的なものを使っているため動作環境はPHP5です。findByFoo_bar的なものに書き換えればPHP4でも動くのかな。
管理側の機能は現状scaffoldで手動でやります。

動作サンプルを置いておきます。CakePHP1.2.x.x_24.01.2008, xrea+, PHP5, SQLiteです。
pmaimai
http://pmaimai.zapto.org/

サンプルなのでdroptableもrollbackもガシガシやっちゃうのであしからず。

続きはプロフィール・日記のアクセス権と管理側の機能実装をやる予定です。

Remoraを眺めてみた1

Remoraを「読んでみた」ではなく「眺めてみた」です。感想メモその1。
Revision 10695: /addons/trunk/site
http://svn.mozilla.org/addons/trunk/site/

MVC間のデータ移動はざっくり

コントローラではモデルから受け取ったデータをざっくりビューに押し込んでいる。
サニタイズをapp_controllerでビューにセットする直前にやってる。$this->publish()ってやつ。それはビューでやりたい気も。

ビューはやっぱりモデル名やカラム名で溢れる

ビューが一見あんまりモデル名やカラム名で溢れてないって書いたけれど、前言撤回。

たとえばapp/views/addons/display.thtmlなんかそんなのでいっぱい。foreachの中で$addon[‘Version’][0][‘File’][0][‘id’]こんなのとか。てことは渡されてるデータは$addons[0][‘Version’][0][‘File’][0][‘id’]みたいなのか。うげげ。

ビューの共通ロジックもコンポーネントに

コントローラごとに違う処理の場合コントローラが持っているけれど、コントローラまたいで共通のロジックの場合、コンポーネントにしてあってビューからロジックを呼び出している。

app/views/addons/recommended.thtmlだと

$prevPath = $this->controller->Image->urlForAddonPreview($addon[‘Addon’][‘id’], 1);

こんな感じ。
こういうのってたいていヘルパー使うと思うんだけどなんでなんだろう。
Imageコンポーネントの中身見てみるとモデルにアクセスしてるメソッドがあった。findByIdとか。ああだからこの辺の機能まとめてコンポーネント(コントローラ)なんだ。納得した。
あとコンポーネントのstartupで$this->controller =& $controller;ってしておけばコンポーネントからモデルにアクセスするのも簡単なのね。でもappimport(Model, Hoge)でモデル入れといてnew Hoge()した方が分かりやすいしアクセスしやすい気がしないでもない。このへんはあらかじめ規約で決めとくのかな。そっかこれならコンポーネントでコントローラのメソッドが使えるんだ。redirectとかflashとか。

真似してやってみたけれどviewからだと$this->controller->Componentでアクセスできない。何か設定が足りないかな。ビューがコントローラのオブジェクト持ってないからか。というわけでFAQを参考にコンポーネントのスタートアップでコンポーネント自身をビューに渡して、ビューからコンポーネントに$componentでアクセスできるやり方にしてみた。

どうでもいいけど眺めてたデータは五日前のRevision 10565なのに今はもうRevision 10695になってる。更新してみたら30個以上ログがあった。

続きはそのうち。

重複チェックのバリデート3

重複チェックのバリデートを若干使いやすくしました。条件をつけてメールアドレスの重複チェック等に使えます。CakePHP1.2.x.x_24.01.2008で確認してます。

//重複チェックのバリデート
function checkDuplicate($data, $addconds = array())
{
$cond = array(key($data) => '= '.current($data));
if(($id = $this->getID()) !== false){
$cond[$this->primaryKey] = '!= '.$id;
}
foreach($addconds as $key => $value){
$cond[$key] = $value;
}
return ($this->findCount($cond, -1) === 0);
}

使い方はバリデーションの中で
‘rule’ => array(‘checkDuplicate’, array(‘status’ => ‘= active’))
例えばこんな感じに連想配列を入れてやると、statusがactiveなメールアドレスの中で重複チェックができます。findの連想配列に渡しているので付け足せる条件は連想配列のみです。

直したところ

  • 条件を付け足せるようにしたこと
  • findCountのrecursive = -1にしたことでモデル名が要らなくなったこと
  • primaryKeyをid決め打ちじゃなくしたこと

實松アウトプット: バリデーションでメールアドレスの重複登録チェック
http://sane.justblog.jp/blog/2008/02/post-9f5d.html

實松アウトプット: バリデーションでメールアドレスの重複登録チェック2
http://sane.justblog.jp/blog/2008/02/2-810c.html

焼きたての感想

第2回CakePHP勉強会に参加してきました。とても刺激を受けました。感想、疑問、個人的な反省という三段構成で行きます。

感想

addons.mozilla.orgの事例

addons.mozilla.orgがcakephpで作られているというのは聞いたことがありましたが、オープンソースでやっているというのは知りませんでした。

Update:Remora – MozillaWiki
http://wiki.mozilla.org/Update:Remora

Revision 10566: /addons/trunk/site
http://svn.mozilla.org/addons/trunk/site/

ブラウザでも見られますし、subversionでひっぱってきてもいいです。/app以下をチェックアウトして持ってきたのでおいおい読んでみます。

見覚えのあるaddonsのサイト(Remora)がlocalhostで動いて、しかも下の方に今度はローカルで見覚えのあるSQLのデバッグログが出てきたプレゼンには感動しました。あとmemcache速えー。memcacheつえー。

トピックイットの事例

デバイスフリー志向でPC版やモバイル版だけでなくipod touch版やwii版を用意しているということ、PCと携帯のアクセスが半々ぐらいということが頭に残りました。振り分けはIPやUA等でやってるのかな。ビューだけ(もしくは文字コードだけ)分けるのか完全に分離しちゃうのかどんなファイルの置き方をしているんだろう。
あと以前、自分の作ったプログラムのDBからデータを返すRESTなAPIもどき(GETのパラメータに応じて毎回クエリを作ってXMLで返す)は作ったことがあるのですが、結局自分しか使わなくてあまり負荷がどうのという話にはなりませんでした。やっぱりAPIの定番の作り方について勉強しようっと。ここもキーポイントはキャッシュなのかな。
なんだかトピックイットともCakePHPとも関連が薄い感想ですみません。

懇親会

findで引っ張ってくるデータでunbindするのがめんどくさいって話を振りました。

例えばuserモデルがmailaddressモデルとnicknameモデルとpostモデルとcommentモデル持っているときに、プロフィールを編集したいときにはuserとmailaddressとnicknameだけあればよくてpostやcommentは要りません。で、まずはrecursive、次にunbindModelで取り外すわけですが、関連がある状態で不要なものをunbindModelするという形だと、テーブルが増えたときや構成変えたときに変更漏れが出てしまいます。さらに、使い始めのときはbakeが勝手にアソシエーション書き出してくれるからいいですが、テーブル増やしたり、カラム名変えたりのときは倍倍でめんどくさいです。かといって、関連まっさらにしてから必要なものを組み立てる、というのはarray()が多すぎてこれもまためんどくさいです。というような話です。

これについてアドバイスをもらいました。
Modelのアソシエーションはあらかじめ全部書いておく。それでModelは全部基本的にrecursive = -1にしておいて、必要なときにrecursiveの数字上げたりbindModelしたりすればいい、条件はあらかじめメンバ変数にでもいれておけばいいとのことです。

これでもarray()地獄なのに変わりはありませんが、一度決めておけば変更漏れも少なくなるのでこれで行こうと思います。

基本のアソシエーションだったり、必要なアソシエーションだったりは将来的にはYAML等で外に出したいところだなあ。validationをYAMLにしてたのどこかで読んだ覚えがあるので、それを参考にしてのちのち要検討。

疑問

Remoraのプレゼンの資料では、ModelからfindやfindAllで返って来たデータを、かなりあっさりコントローラーからビューにsetしてるように見えました。そうするとビューではモデル名とDBのカラム名であふれかえるような気がします。でも今ぱらぱらとRemoraのコードを眺めていますが、それほど溢れかえってる感じは無いです。かといってヘルパーに丸投げしている感じもしないですし。ここはもうちょっと読んでみます。

今自分が書いてるコードだと、モデル名やカラム名をそれぞれで隠蔽しようとしてモデルやコントローラーでいじくり回した結果、よくわからないデータをビューに渡すことになってしまっています。結局二度手間三度手間になっているのでビューでいじる方がわかりやすいのかも。

反省

懇親会で積極的にいけなかった。次はもっと話しかけよう。話した方の数が少ないのはまあいいとしても、情報提供的なことが出来なかったのがすごく失敗。情報をもらってばかりで提供することが出来なかった。つくりかけのあれかつくりかけのこれのどっちか完成させておけば一ネタになったはず。もったいないことした。

せめてフィードバックだけでもということで感想等をきちんと書いてみました。そして、貴重な勉強会ありがとうございました。

scaffoldにBasic認証をかける

scaffoldにBasic認証をかけるやり方です。scaffoldを表に出すなよっていう是非論は横におきます。あと、アクションにベーシック認証をかけているだけなのでscaffoldに限らず使えます。CakePHP1.2.x.x_24.01.2008で確認してます。

CakePHP 管理者サイトでBasic認証を簡単に行うコンポーネント | Shin x blog
http://www.1×1.jp/blog/2008/01/cakephp_adminauthcomponent.html

best practices for admin part of website? – Cake PHP | Google グループ
http://groups.google.co.jp/group/cake-php/msg/4d1200e920b9fe0e

上のコンポーネントに下の投稿の発想を組み合わせて使います。

具体的には、認証コンポーネントのfunction startupの中を書き換えます。
before:

if (!preg_match("/^" . Configure::read('Routing.admin')  . "_/i", $controller->action)) {
return;
}

after:

if (!in_array($controller->action, $controller->protectedActions)){
return;
}

次に、認証を掛けたいコントローラ側に
var $components = array(‘ScaffoldAuth’);
var $protectedActions = array(‘index’, ‘add’, ‘edit’, ‘delete’);
という感じに認証コンポーネントと認証を掛けたいアクションを記述します。今回の場合scaffoldなのでindex,add,edit,deleteを書きます。

これでvar $protectedActionsに書いたアクションにはbasic認証がかかります。

今まで私はbakeでadmin_hogeを作ってそこに認証をかけていたのですが、構成を変えるときにMVC全部手動で書き換える必要がありました。これがめんどくさかったのでadmin用にscaffold使えないかな、という所からの発想です。私の場合、key-valueで設定組み合わせが書いてあるconfigsテーブルの編集に使ってます。

もちろん管理画面を作るに越したことはありません。が、俺俺サービスをユーザー側だけ出来た段階で早く公開したいとき等には使えそうです。ただし、パスワードがかかってるとはいえ、簡単に類推できる場所なので脆弱です。必要最小限に。