Python4PHPer 第7回講習会
mon_satです。
PHP使いの人に向けたPython勉強会に参加してきました。
この勉強会は定期的に開催されているようですので、興味がある方はATND内に記載のGoogleグループを登録しておくと良いですよ。
わたしも前回満員で今回参加できました。
Google App Engine for Python
以前、Amazon EC2 の勉強会に参加しましたが、同じクラウドであるGoogle App Engine (以下GAE)にも大変興味があります。
GAEは、JAVAもしくはPythonの使用に限定されているため、PHPだけでやってきたわたしとしては少々難易度が高いです。
ですが。
調べてみると、Pythonは、JavaScript に似たところも多く、非常に扱いやすい言語であることが分かりました。
実際、習作で、Tweepy というモジュールを利用しTwitterアプリを作ってみたところ、結構簡単に作れました。
しかしながらPHPであればつまずかないところでも、Pythonへの理解が甘いためにつまずくこともあり、もっと言語仕様に近い理解が必要であることを痛感し、今回の勉強会参加となりました。
勉強会への準備
結局キャンセル待ちが届かなかった以前の勉強会の前に、GAEのSDKのインストールおよび、Hello World 程度のチュートリアルは終わらせておきました。
SDKのインストールで詰まってしまって勉強会で学べることが限られてしまうのはもったいないので、よっぽどの事情がない限りはインストールしておくことをお勧めします。
いざ、勉強会へ
この勉強会は、10時〜22時という長丁場です。
いつも以上に朝食をがっつりとり、準備万端で臨みました。
PHPとの文法の違いを説明しつつ、章の合間に、各自手を動かして理解を深める。というのを各章ごとにやっていくかたちで勉強会は進んできます。
途中お昼休憩と自己紹介タイム、夕食タイム、GAE実践タイム、がありますが、基本的には、講師の@makotokuwataさんが作成した資料をもとにした、上記の流れで進むスタイルでした。
Python の特徴を知る
この資料が非常にためになりました。
というのも、PHPでは○○と書くところを、Pythonでは××と書く。というように書いてあるため、非常に頭に入りやすいです。
各サイトで事前に基礎的な文法が分かっていたようでも、勉強会を通じて、Python ならではの文法をいくつも知ることができました。
個人的に、とくに知りたかったのはモジュールの使い方のところです。
Python は、JavaScript が分かれば、非常に扱いやすい言語だと思います。PHPと比べても学習コストは同等程度に低いでしょう。しかし、もっとも大きな違いが、この、モジュールによる拡張ではないかと思いました。
何かを作る上で、再利用性を考えれば、いきおい自分でもモジュールを作っていくことになります。
実際、Tweepyを利用して簡単なWebアプリを作ったときもモジュール化を試しました。
しかし、モジュールがどのように扱われているかを分からないため、何度も試行錯誤を繰り返し、結局「よく分からないけど動いたからいいや」で終わらせたのでした。
この勉強会ではさらっと流れましたが、Python では必須のモジュール周りの理解は、GAEでアプリを作るにあたって大きな意味がありそうです。
この点が理解できただけでも、参加して良かったと思います。ホント。
交流しよう
勉強会は知識を習得する場ではありますが、もうひとつの側面として、参加者同士が交流をする場でもあります。
なるべく、知識習得に終わらず、交流もして帰ろうと思っているのですが、この勉強会でも、素晴らしい出会いがありました。
上述の通り、途中、夕食タイムに先立ち、自己紹介タイムがありました。
これは、講師の方が、夕食時に交流しやすいようにと設けているものです。
簡単な自己PRをすることで、その後の食堂での夕食時に、各参加者がいろいろ話しやすくなります。
驚いたことがふたつ。
ひとつは、以前つとめていた会社で同じ部署だった方(@uniom)が参加していたこと。
かぶった期間が短すぎて、お互い、よく覚えていなかったんですけどね(笑)
でも、再会できて嬉しいです。
もうひとつは、もっとびっくり。
席がとなりになった彼(@shinout)。bioを見て分かるようにすごいキャリアで「いやあ負けられないなあ」なんて呑気に思っていたんだけど。
GAE実践タイムのとき、以前NerineというHTML5+CSS3を使ったプレゼンツールを使って作った、某勉強会用のプレゼン資料をGAEであげておいたんです。
で、「GAEで静的サイト動きますよ。ほら、このプレゼンツールがそう。かっこいいよね」とぱらぱらとスライドをめくっていたら、、、自己紹介ページのブログの名前のところで「あれ?このブログ、、、最近見ましたよ」と。
え?またまたあ。ほとんどCakePHPのことしか書いてないし、(彼はSymponyユーザー)誰も見てないことには定評あるんだから、他人の空似ならぬ、他人の空サイトでしょ?と、思った訳です。
NerineはスライドをHTMLで作りますので、当然ブログにはリンクが張ってあります。
で、飛ぶ訳です。そしたら
「やっぱり見ました」って。
どうやら、gitではまってインターネッツを彷徨い、この記事を見つけて、そして『まったく同じ解決手法で解決した』んだって。びっくりですよね、奥さん!
彼の場合、さくらではなく、コアサーバーでつまずき、(例として提示した) spush ではなくご丁寧に cpush というエイリアスにしたって(コアサーバー用だから)
ちなみに続きの記事がないのは、いまだ根本的解決してないからなんですけどね(笑)
ひとりの前途多望な若者を救ってしまいました。こんな場末のブログが。
一方、見せてもらった、彼の開発ブログ。
CSS3使って、右カラムがすごいことになってます(笑)
内容もためになります。たとえばこれ。 MacOSXのコマンドからGoogleトランジット
$ open -a "/Applications/Google Chrome.app" http://www.yahoo.co.jp/
Macでこんなことできるなんて思いませんでした。
たしかにこれを使っていろいろやると便利なこと多そうです。
せっかく仲良くなれたので、起業のときとかで、何か困ったことがあったら遠慮なく言ってくださいね。
まとめてきな何か
他にもTwitterでフォローしたりと、何人かと交流できました。
こうやって輪が広がっていくのは嬉しいことです。
そしてなによりPythonの知識が深まりました。
クロージャとかデコレータとか、解説が丁寧だったので分かりやすかったです。
(途中Googleグループからファイルがダウンロードできないという予期せぬトラブルあり、最後駆け足になってしまいましたが)
こんなためになる勉強会を、激安で開催されている@makotokuwataさんには、感謝してもしきれません。
GAEを生かしたウェブアプリつくることが恩返しだと思って頑張りたいと思います。
Python がもっと普及するように祈りつつ。
というわけで、同じ時間を共有できたみなさん、どうもありがとうございましたー。
View Cache のキャッシュファイル名を変更する
久しぶりにCakePHPネタを。
ひとつのAPPで複数のサイトを運営しているAPPがあります。
bootstrap.php内でURL等を見てどのサイトかを判断しているのですが、キャッシュを設定して困りました。
aaa.example.com/index と bbb.example.com/index で生成されるキャッシュファイルが同じになってしまいます。
どちらへアクセスしても先にキャッシュされたファイルを表示してしまうのです。
しかたがないので、以下のようにキャッシュを生成することを試みました。
aaa_index.php
bbb_index.php
キャッシュヘルパーを上書きする
コアのキャッシュヘルパーをコピーする
コアのキャッシュヘルパーを、APP内にコピーします。
cp cake/libs/view/helpers/cache.php app/views/helpers
キャッシュヘルパーを書き換える
キャッシュヘルパーで書き換える箇所は1箇所です。
キャッシュを書き出している __writeFile() の↓に1行追加します。
# app/views/helpers/cache.php
# __writeFile()
$path = $this->here;
if ($this->here == '/') {
$path = 'home';
}
$path = Configure::read("subdomain") . "/" . $path; // この行を追加
$cache = strtolower(Inflector::slug($path));
subdomain はbootstrap.php にて設定してください。
この状態でURLにアクセスすると、aaa_index.phpのように、サブドメインが付加されてキャッシュファイルが作られます。
しかし、このままではdispatcherがキャッシュファイルを認識してくれません。
Dispatcher等を修正する
dispatcherの該当箇所を書き換える前に、dispatcherをコピーし、そのファイルを読むように変更しなくてはなりません。
CakePHP1.2であれば、この記事内のスライドが参考になります。
しかし、CakePHP1.3 (1.3.0)の場合、dispathcerはキャッシュしてくれないようです。
以下のように対処します。
DispatcherとBootstrapをコピーする
CakePHP1.3から登場のAPP/libsディレクトリに、コアのdispatcher.php とbootstrap.php をコピーします。
cp cake/libs/dispatcher.php app/libs cp cake/libs/bootstrap.php app/libs
Dispatcherを書き換える
cached() 内に、1行追加します。
# app/libs/dispatcher.php
# cached()
$path = $this->here;
if ($this->here == '/') {
$path = 'home';
}
$path = Configure::read("subdomain") . "/" . $path; // この行を追加
$path = strtolower(Inflector::slug($path));
次に、当Dispatcherを読み込むように修正します。
app/config/bootstrap.php にて、dispatcherの読み込み先を変更する
bootstrap.phpの最後の方に、下記を加えます。
# app/config/bootstrap.php
App::import('Lib', 'Dispatcher');
このままでは、コアのDispatcherも読みにいってしまうようですので、それを止めます。↓
Bootstrapを書き換える
コアからコピーしたapp/libs/bootstrap.phpを書き換えます。
(app/config内のbootstrap.phpではありません)
# app/libs/bootstrap.php # 最後の行をコメントアウト // require CAKE . 'dispatcher.php';
最後に、webroot/index.phpのbootstrap.phpの読み込みを変更します。
webroot/index.phpを書き換える
# app/webroot/index.php
# 次のように変更します
//if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) {
if (!include(APP_PATH . 'libs' . DS . 'bootstrap.php')) {
以上です。
もっとエレガントなやり方がありそうだけど、とりあえず。
Amazon EC2 ハンズオン・セミナー(2010年06月13日)
「勉強会はブログに書くまでが勉強会」と以前学んだため、早速ブログ書く。
Twitterで Amazon EC2 ハンズオン・セミナー の存在を知ったので、勢いで申し込みました。
ちょうど『よくわかるAmazonEC2/S3入門 ―AmazonWebServicesクラウド活用と実践』の購入を考えていたところで、 自力で手に入る情報はたくさんありますが、それでも限界があるかもと思っていたときです。
タイミングよく入手した情報には、なにかしらの縁があるはず。
実際、大変有意義なセミナーとなりました。
事前のアカウント取得が超重要!
事前にAmazon Web Services のアカウントの取得が推奨されていましたので、申し込みのあとに取得を試みました。
結果的に、これは大正解でした。
というのも、アカウントの取得後、Amazon EC2 のインスタンスを起動するためには、クレジットカード情報の入力と、それに付随するAmazonからの電話に対する応答が必要です。
電話はオペレーターがいてかかってくるのではなく、コンピューターによって自動的にかけてきて、ウェブ画面上の認証コードをプッシュホンで入力するだけなのですが、さすがにセミナー中にそれをする訳にはいかないため、手順の説明のみ。
実際にインスタンスを立ち上げてこそのハンズオンセミナーなので、参加される方は、事前にアカウントを取得し、海外からかかってくる電話にどぎまぎしながら待ってみるといいよ!
そして会場へ!
当日。会場の法政大学の外濠校舎へ。できてそれほど経ってないのでしょう、設備の整ったきれいな校舎です。
比較的小さめの教室でしたが、勉強会の会場としてはベストな大きさ。
さらに、主催者の方に電源タップも用意していただき、無線LANも完備されています。
始まってみると、講師の方の他、サポートをしていただける方もスタンバってます。
なんか至れり尽くせりな感じでした。
Amazon EC2 の概要を学ぶ
まずは、クラウドコンピューティング自体の定義や特徴を学び、つづいて、Amazon Web Services (AWS) の特徴や機能の詳細を学びます。
AWSの各サービスについてと、EC2 Compute Unitsなどの用語については、今後自分で知識を深めていくにあたって非常に重要な予備知識です。
こういう話はサイトや本で知るよりも、話を聞いた方が手っ取り早いですね。今までよくわかってなかったところが一発で理解できました。
ああ、今考えれば、課金体系のところは、質問しておけば良かったかも。
完全に、忘れてました。
が、料金シミュレーションや料金早見表が載っているページを教えてもらったので、あとで調べてみよう。
実際に Amazon EC2 のインスタンスを立ち上げる
その後、AWSのアカウントの取得の流れを一通り説明し、その後いよいよ、実際にインスタンスを立ち上げるところまでやりました。
インスタンスの種類やサーバーが設置された場所を選択したあと、起動するOSを選びます。
ここではAmazonが用意しているFedora Core + LAMPセットを選択。
マクドナルドのバリューセットのようですね(笑)
驚いたことに、数分もまたずにステータスが「準備完了だから使えるよ!」に変わりました。
これだけで、ウェブルートにアクセスすると、phpinfo()が表示されます。
え?こんなに簡単なの?
ちょっとびっくりです。多分自力でやってたら、ここまでくるのに数時間を要したことでしょう。。。
そして、インスタンス起動時に作成した秘密鍵で、SSHログインを試みます。
# 鍵を指定してSSHで接続 $ ssh -i ~/Downloads/us-east.pem root@ec2-174-129-xxx-xx.compute-1.amazonaws.com
rootであっさり接続できました。(指定し忘れて permission denied になったことは内緒)
このあたりでセミナーの終了時間が迫ってきていたため、概ねfinish。
まああとは、普通のサーバー設定ということですね。
最後に管理画面からステータスを右クリックしてでてくる Teminate で、インスタンスを落として終了。
これをしないと課金され続けてしまいますので、忘れずに!
ただし、インスタンスを落とすと、(EBSに保存するなどして永続化しないと)データはすべて消え去るそう。
この辺は自分で勉強せねば。
所感とか。あと所感とか
今回主催していただいたのは、AWS User Group -Japanで活躍されている方々。
実践形式のセミナーであったにもかかわらず、大きなトラブルなく終了。目標のインスタンス起動のみならず、SSHによるログインまでいくことができました。
もちろん今回の内容だけでは、今すぐ「EC2使ってがんがんいこうぜ」とまではいけませんが、今後知識を深めるための基礎固めには、十分すぎるほどとなりました。
EBSやS3といったところを知らないと、実際に運用することができませんので、まずはそこからはじめていき、他サーバーで稼働している何らかのサイトを動かしてみるところまではやってみたいと思います。
(もし続きのセミナーがあるならぜひとも参加したい!)
今後、日本にもAmazon EC2のサーバーが置かれる日も来るかもしれません。
そうなる前に今から準備しておきたいと思います。
これを書いたのは勉強会当日だったのですが、翌日の日経新聞の朝刊一面にAmazonが年内をめどに日本で事業開始との記事が出ました。
講師の方々、有意義なセミナー(しかも無料!)を開催していただき、ありがとうございましたー!
あと、終了後に新しい友達もできた。機会があれば、また情報交換しましょうね。
CakePHP勉強会@東京(2010年5月)
CakePHP勉強会に行ってきました。
昨年10月末に行われたCakePHP Matsuri以来のイベント参加。
今回は、札幌・名古屋・福岡でサテライト会場ができ、どこも盛況だったもよう。
勉強会の申し込みもすぐにいっぱいとなり、今回の勉強会もひとつの祭りだったのではないでしょうか。
全体的な所感としては、@cakephperさんのテンポの良い司会と各発表者の発表の上手さがあって、あっという間の4時間でした。
テーマがCakePHP1.3ということで、非常に実践的な内容も盛りだくさんで、「勉強になった」という感じです。
CakePHP以外にも、Rackspaceというクラウドサーバーや、WAFというセキュリティソリューションの存在を知ったりと、CakePHPに関わっている人たちのCakePHPに限らないお話があって良かった。
次の日早速調べてみて、使いたくなったし。
PHP Matsuri by @yandoさん
資料
トップバッターはニューヨークから。
サテライト会場が全国規模で展開され、発表者は世界規模という、まさにグローバル。
(ちなみにNYは深夜1時すぎだそう)
発表された内容も、いきなりのビッグニュース。
なんと、前回のお祭りをスケールアップして、今年も行うらしい!
その名もPHP Matsuri
PHP5.3向けのLithiumがstable間近ということもあってか、冠から"Cake"がとれました。(symfonyとかも含まれていますよ)
前回同様CakePHPのコアデベロッパーに加え、今回はLithiumのコアデベロッパーの講演も開かれる予定とのこと。
これは胸が熱くなりますね!
開催概要をまとめると(現時点で予定していること)
-
名称
- PHP Matsuri
-
テーマ
- もっと交流、もっと刺激的に
-
開催期間
- 2010-10-02(Sat) - 2010-10-03(Sun) ※オールナイト!
-
場所
- 晴海グランドホテル(予定)
-
人数
- 100名程度
-
参加費用
- 2万円前後(食事・軽食・懇親会費用込み) ※早期購入は割引
-
内容
- コアデベロッパーによる講演
- ワークショップ(入門者向け・中級者向け・Lithium入門者向け)
- コンテスト(プラグイン・ライブラリ、ハッカソン、ドキュメント、パフォーマンス、etc)
-
主催者からのお願い
- 協賛企業・団体参加企業募集
- 参加チケットの早期購入
- コンテストへの参加
- 運営スタッフ募集
- Twitter ID
まず何といっても今回は土日を通してのイベントであるということに驚きました。
プログラムは夜遅くまで組まれていて、夜通し開発(まさにハッカソン!)できる環境とのことです。
興味のある講演を聴きつつ、他の時間で隣のエリアで実践する。
素敵ですね!
しかも場所は晴海。
自宅から至近です。徒歩圏内とまではいかずとも自転車で楽々行けます。車なら数分。
近隣の地理にも明るいので、何かお手伝いできることがあれば是非協力したいな。
と思っていたら運営スタッフ(お祭りなので「青年団」)募集とのこと。
協賛企業にはなれなそうだが、他の3つは協力できますので、よろしくお願いしますー。
ともかく楽しみなイベントの告知から始まった勉強会なのでした。
CakePHP1.3の概要 by @cakephperさん
資料
さて本題のCakePHP1.3のお話。
会場アンケートではまだまだ1.3の開発経験がない方も多く、「何が変わった?」というところに興味が集中しているようです。
変更点がまとまっていて、すぐにでも導入できるということが分かったのではないでしょうか?
私としては、一番はRoutingだと思っていて、Routingの改善が、その他に良い影響を及ぼしている箇所が随所に見られます。
CakePHP1.2ではどうしても力技で解決しなくては行けなかったことも、普通に使えるようになっていることが多いのです。
あとは、plugin周りも整備されている印象です。
1.3からplugins/xxx/webroot以下にcssや画像を置けるようになり、配布・利用がより簡単になっています。
さすがCakePHP1.x系の最終バージョンといえると思います。
CakePHPでの開発経験があり、1.3を使ったことがない方は、次の案件からは1.3をお勧めします。
Ktai Library on CakePHP1.3 by @ecworks_masapさん
資料(PDF on ecworks.jp)
Ktai Library 勉強会でもお世話になってる、作者さんです。
Ktai Library は、現在は、CakePHP1.3上で開発されているため、もし1.2のアプリケーションを1.3に移行するという場合であっても、Ktai Library周辺は変更点はありません。
この辺は実際に双方で開発してみて経験済み。
安心して使えます。
根幹部分はライブラリ化する前から使っているものとのことで、十分に安定していますし。
今回は今後のバージョンアップ予定の機能を、多数、発表していました。
個人的には、早期にplugin化が希望です。
(branchがあれば、協力できることは協力します!)
コアライブラリのエレガントなハック by @hiromi2424さん
資料
今回一番男前な発表をしたのは、CakePHP界での多大な貢献者の@hiromi2424さん。
twitterでの発言や今回の発表を聞いていて感じるのは、CakePHPの中身についての調査をとことんやっているということ。
何事も仕様を理解するというのは重要ですが、表面的なところだけさらって終了することが私は往々にしてあります。コアのコードもちょっと読んで終了とか。
ですが、このかたは、深いところまで理解している。
だからこそ、どうしても必要なこと(ハック)にあたったときに、どのようにやるかということを、「分かりやすく」説明できるのでしょう。
CakePHP触って間もない人は多少振り切られた方もいるかもしれませんが、間違いなく、今回の発表資料は保存版といえます。
今すぐブックマークを!
twitterとcloud serverとcakeで新規サービス by @takamunetaniiさん
資料
つづいて、Ktai Library 勉強会でもご一緒している@takamunetaniiさんの発表。
こんなにためになる事例紹介が過去あったか?というくらい今の私にはためになりました。
タイムリーだったのは、Twitter API / Cloud Server あたり。
ちょうど勉強し始めたところだったので。
あと発表が面白い。惹き付けるなあ。
Rackspace は、Lithium実行環境として最適かも。
最安$10ちょいですって、奥さん。
インスタンスをオフれたり、保存したイメージをコピーできたら最強だなあ。
Twitter API は、GAEで実行しても面白いと思う。
ということでPython勉強中。
(CakePHPユーザーにこそお勧めできる>python)
起業するとのことです。
ぜひ今後もよろしくお願いしますー。
ライトニングトークス
そしてLTの時間。
もう盛りだくさんの内容。LTじゃなくて通常の発表枠でいける内容ばっかり!
最後に@cakephperさんから恒例のIRC集会の案内があって終了。
ちなみに次回は2010年6月11日(金) 15:00-19:00と後日発表されました。
IRCサーバーが変更になっているので注意が必要です。
初めての方もぜひ。気軽に参加できる素敵な会です。(業務中に参加できる方限定ですがw)
懇親会
私の場合、勉強は2の次で、飲むために行っているようなものです。
#cake_beer というタグもあります。
今回は会場の机といすを片付けて、その場で懇親会開始。
ほとんどの人が参加したのではないでしょうか?
ついにはビールが底をつきました(笑)
懇親会中に@sizuhikoさんのテストについての発表あり。
テスト書いておくことで1.2 -> 1.3 への移行も楽ということが分かった。
横着せずにヘルパーとかもテスト書かねば。カバレッジ低いからなあ。。。
毎度思うのが、CakePHPな人たちと飲むのは楽しい。
CakePHPに限らずいろんな話題が出てきてためにもなる。
徐々にCakePHP飲み会や勉強会後の懇親会でご一緒した人が増えてきて、それもまた嬉しい。
サテライトの人たちとも交流できたらいいなあ。
チャンスは他地域勉強会とPHP MatsuriかCakeFest2010か。
その後、懇親会は終了。(会場を貸していただいたトライコーンさんに感謝!主催者の方々、とくに@kaz_29さんおつかれさまでした!)
ぞろぞろと2次会へ。
2次会ではテーブルごとに分かれて交流。
飲み会や勉強会でお世話になってる@cakephperさんや@yashioさんらと飲む。
(もうひとりのかた、忘れてしまった。ごめんなさいい<twitterやってたら連絡ください)
他テーブル含めて雰囲気(うまく変換できた)が良い。
今年はいろんな勉強会に行ってみよう。
興味の幅を広げねば。
そこで仕入れた話をすれば、みんなハッピーになれるかもだし、いつまでも話を聞いてばかりじゃ申し訳ないし。
まとめ
最近いろいろあって疲れる日々もあったが元気出てきた。
今回交流できた方々、次回お会いしましょう。
交流できなかった方々、次回こそ是非!
Ktai Library 勉強会 #1-2
Ktai Library 勉強会に行ってきました。
といっても、第1回が3月8日(月)で第2回が4月16日(金)でしたので、もうかれこれ1ヶ月近く経とうとしていますが。。。
でも、ちっちゃいことは気にしないで、両日を通して学んだことをまとめつつ、感想などを。(遅ればせながら)
準備編
せっかく作者の@ecworks_masapさんが来るわけですから、できるだけ準備をしておこうというわけで、とりいそぎセットアップを。
CakePHPは1.2を使用しました。
(当日聞いたら1.3でも普通に使えるということで、第2回からは1.3を使用)
Ktai Library は、今後のバージョンアップに備えて、gitで持ってくる。
$ git clone http://github.com/MASA-P/KtaiLibrary.git
(app/vendors/ecw となるように、KtaiLibrary/vendors/ecwをコピーする)
絵文字アイコンが必要なので、それもダウンロード
$ cd app/webroot/img $ wget http://start.typepad.jp/typecast/download/emoticons.zip $ tar xfvz emoticons.zip
Ktai Library で必要なファイルを、app内にコピーします。
以下は、シンボリックリンクで代替。
$ cd app/config $ ln -s /path/to/KtaiLibrary/app/config/ktai_session.php . $ cd ../../app/controllers/components $ ln -s /path/to/KtaiLibrary/app/controllers/components/ktai.php . $ cd ../../../app/views/helpers $ ln -s /path/to/KtaiLibrary/app/views/helpers/ktai.php .
app_controller.php内で、redirect()を上書きするため、KtaiLibrary/app/controllers/ktai_app_controller.phpの内容を、写す。
(ver0.2.2以前の場合で、リバースルーティングに配列を渡している場合は、コレを追加)
すべてのcontroller,viewでktaiコンポーネントとktaiヘルパーを使用する場合はapp_controller内の var $componentsとvar $helpersにKtaiを追加する。
また、以下を環境に合わせて追加
# app/app_controller.php
var $ktai = array(
'use_img_emoji' => true,
'input_encoding' => "UTF-8",
'output_encoding' => "UTF-8",
);
NamedParamsのセパレータを変更
# app/config/routes.php
Router::connectNamed(array(), array('argSeparator' => '~'));
FireMobileSimulator
すでにメインブラウザをGoogle Chromeに完全移行したのですが、いかんせんChromeの拡張機能では、現状ではFireMobileSimulatorのようなものを作れません。
というわけで、ケータイからのアクセスをシミュレートするFireMobileSimulatorをFirefoxにアドオンします。
初めて使ったのですが、超絶便利でした。しかもbetaながら、タブごとに別々のuser_agentに切り替えるバージョンまであり、開発スピードが段違い。素晴らしい!
Hello Ktai Library !
ここまでできたら、Ktai Library の教科書Chapter4のリスト04-04、04-05および04-06を参考に、サンプルページを表示します。
以下、Ktai Library 開発用デモサイトソースより一部改訂して引用
# app/controllers/mypages_controller.php
function index() {}
# app/views/layouts/default.ctp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<?php if($ktai->is_iphone()){ ?><meta name="viewport" content="width=260"><?php } ?>
<title><?php echo $title_for_layout; ?></title>
</head>
<body>
<?php if(!$ktai->is_ktai()){ ?><div style="width: 240px;"><?php } ?>
<?php echo $content_for_layout; ?>
<div align="center">
<hr width="90%" size="1" color="#333333" noshade>
(C)2009 <a href="http://shop.example.com/">MyShop</a>
</div>
<?php if(!$ktai->is_ktai()){ ?></div><?php } ?>
</body>
</html>
# app/views/mypages/index.ctp
<center><?php $ktai->emoji(0xe753); ?>Hello, ktai Library!<?php $ktai->emoji(0xe753); ?></center>
絵文字付きでHello, Ktai Library!と表示されたら準備完了です。
このブログは記憶を頼りにまとめているので、記述をそのままやっても動かない場合もあると思います。
動かない場合はtwitterでお知らせください。
勉強会 #1
じつは、勉強会の1回目は、第4章を実践することがテーマだったので、準備万端で臨むと、もう終わってたりします(笑)
というわけで私は、今後の開発がしやすいように、いろいろとカスタマイズしていくことにしました。
Themeを使って、KtaiからのアクセスとPCからのアクセスで、表示を分ける
CakePHPのTheme機能を使って、Ktaiからのアクセスの場合は、themed/ktai を使用し、PCからのアクセスの場合は、通常のviewを使用するケースです。
まず、Ktaiからのアクセスかどうかを判別して、必要に応じてテーマを使用するようにします。
Ktaiからのアクセスかどうかは、 Ktaiコンポーネント(かKtaiヘルパー)のis_ktai()を使用します。
# 使用例
if ($this->Ktai->is_ktai()) {
debug("Ktaiからのアクセスです");
}
Themeを分ける場合は、beforeRender()あたりがよさそうですので、app_controller.php内のbeforeRender()を変更します。
# app/app_controller.php
function beforeRender() {
if ($this->Ktai->is_ktai()) {
$this->view = "Theme";
$this->theme = "ktai";
}
}
これでThemeの使用ができますので、必要なファイルを作成します。
まずは、必要なディレクトリを作成しましょう。
app/views内に、themed/ktaiディレクトリを作成し、その中に、layoutsやelements、今回の場合はmypagesを作成します。
$ cd app/views $ mkdir -p themed/ktai/layouts $ mkdir -p themed/ktai/elements $ mkdir -p themed/ktai/mypages
そして、レイアウトファイルを移動します。
$ cd app/views $ mv layouts/default.ctp themed/ktai/layouts
ここで、いったん動作確認。
ケータイによるアクセスとPCからのアクセスで、別々のレイアウトファイルが使われていれば成功です。
mypages/index.ctpも忘れずに移動します。
$ cd app/views $ mv mypages/index.ctp themed/ktai/mypages
その他
elementsでヘッダーやフッターを作ったりして、初日終了。
感想など
@yashioさんの呼びかけで始まったKtai Library 勉強会@関東ですが、非常に素敵な会でした。
まず何といっても雰囲気がよい。少人数故なのかどうかは分かりませんが、堅苦しくなくて良かったです。
また、講義を聞くスタイルではなくて、実践形式で進めるというのが、振り返ってみて良かったなと。講義を聞いて、その場で分かったつもりになって、実践しないでほったらかす人種のわたしとしては、手を動かす絶好の機会となりました。
なかにはセットアップに苦労していた方もいましたが、そういったことも含めて、実際にやってみることの大事さを再確認することができました。
最後は、みんなで歓談し、CakePHPやそれ以外のことについて情報交換。
『ゼッタイに第2回も参加しよう』と心に誓った第1回でした。
勉強会 #2
そして、第2回。今回は第5章ということで、非常にボリュームがあります。
しかし、その多くはPCによる管理画面の作成ですので、ケータイで作る部分はさほど多くない。
ひととおり読み込んで準備して、、、と思ったが、タイミング良く入っているケータイサイトのお仕事を進めないと進捗が遅れていることに気づく。
内容的にはフォームの作成で、サンプルと一緒の画面遷移なので、第5章を参考にしつつ作成しました。
teltoリンク
Ktai Library には、便利なmailto()というメソッドがある。これはいわゆるmailtoリンクを、キャリアに合わせて作成してくれるもの。
# 使用例 (for CakePHP 1.3)
// Site.mail はメールアドレスが入っています
// 第3引数で件名を第4引数で本文を指定可能です
$this->Ktai->mailto("メール",Configure::read('Site.mail'),"携帯サイト問合せ");
telto()もあるかなとリファレンスを見たが、なさそうなので急ごしらえした。
function telto($telno = "") {
if (empty($telno)) {
$telno = Configure::read('Site.tel');
}
$telnoWithoutHyphen = str_replace("-","",$telno);
return "<a href=\"tel:{$telnoWithoutHyphen}\">{$telno}</a>";
}
なんでHtmlヘルパー使ってないんだっけか?相対URLになっちゃうんだっけかな?
おかげで$optionsも指定できないからあんまり意味ないかも。
ハイフンを消す必要があるかどうかも不明だけど、確認するの面倒だからまあ良し。
あと対応できない端末があるかもなあ。
その他
主に見栄えのところを調整した。
Ktai Library には、スタイル調整用の機能があります。
# app/app_controller.php
var $ktai = array(
'style' => array(
'h2' => "color:#ffffff;background-color:#0000ff;",
),
);
としておき、viewで
# view on CakePHP1.3
<div style="<?php $this->Ktai->style("h2"); ?>">見出し文字列</div>
のように使います。便利ですね。
自ヘルパー内で拡張して、divでラップしても面白いかもしれませんね。
感想など
外は雨模様。帰りにはみぞれになっていた。4月なのに。
そんな悪天候の中、参加者は全員出席だったそう。それだけ注目のKtai Libraryであり、Ktai Library 勉強会ということでしょう。
帰ってから実機で確認してみると、キャリアによって細かい動作が違ってくるものがあるということも分かった。
携帯サイトはノウハウの集積が不可欠だと思っていたが、それでもその大部分を担ってくれるKtai Libraryを使うかどうかで、開発効率は大きく違ってくるでしょう。
そして。
Ktai Library を使っても、なお、知っておかなくてはならないことが多いのが、携帯サイトの開発だと気づく。
だからこそ、Ktai Library の教科書では、題材に『ショッピングサイト』を選んだのではないだろうか。
幅広い機能が必要となるため、それを実践することで、必要なノウハウも(多数)身についていくのですから。
続きは次回。
では。
さくらインターネットでbakeする前に
自分用にメモです。
さくらインターネットでCakePHPのbake等を利用する前に、bashへのパスを変更する必要があります。
CakePHPのバージョンアップの時に注意が必要です。
#!/usr/local/bin/bash
以上です。
CakePHPのdatetime validation
かゆいところに手が届くCakePHPですが、バリデーションルールにdatetimeがありません。
(私が知らないだけ?)
ということで、オリジナルメソッドとして、作成しました。
現在テスト中なので、完全ではありません。
# model
var $validate = array(
'any_field_name' => array(
'datetime' => array(
'rule' => array('datetime' ,'ymd'),
'message' => '日付の形式が間違っています',
'allowEmpty' => true,
),
),
function datetime($data ,$format) {
$datetime = current($data);
$s = strrpos($datetime ," ");
$date = substr($datetime ,0 ,$s);
$time = substr($datetime ,$s + 1);
$Validation =& Validation::getInstance();
$result = $Validation->date($date ,$format) && $Validation->time($time);
return $result;
}
(ひとりごと1)突っ込み歓迎(twitterで)
(ひとりごと2)app_model.phpにおくと動かないな。。。
CakePHPのアソシエーション
CakePHPには、非常に強力なアソシエーションという機能があります。
これは相互に関連する複数のModel(テーブル)を一括して扱うための優れた仕組みです。
便利なアソシエーションですが、マニュアルを読んで理解したつもりでも、実際に活用する段になって、どのように設定すればよいのか迷うことがあります。
CakePHPに不慣れな方がアソシエーションで迷っていたときに、どのように教えてあげると分かりやすいのかという視点で、アソシエーションについてまとめてみました。
ここではHABTM(Has And BelongsTo Many)については触れません。それはまた別の機会で。
よくある勘違い
一般にAとBというふたつのモデルがあったとき、AモデルがBモデルを『ひとつ持っているときはhasOne』で『複数持っているときはhasMany』と認識している場合がありますが、その理解のままだと、ときに混乱してしまいます。
よくあるのが、以下のようなケースです。
- ブログの記事を扱ったArticleモデルと、その記事の『編集中・投稿済・削除』等のステータスを扱うStatusモデルがあり
- ArticleモデルとStatusモデルのアソシエーションを検討したとき
- Article hasOne Status と間違ってしまう
ということがあります。
記事が、ひとつのステータスを保持するわけですから、hasOneだろうと考えると、『あれ?どうやってこれ設定するんだ???』となってしまいがちです。
つまり、上記の『ひとつ持っている』『複数持っている』という考え方は、忘れたほうが良いのです。
アソシエーションの基本
それでは、まず、基本的なところからおさらいしつつ、なぜ上述のような混乱に陥るのかを説明していきたいと思います。
アソシエーションの基本原則其の一:外部キーを持っているときはbelongsTo
まず、belongsToからおさらいしましょう。
belongsToは、あるモデル(B)があるモデル(A)に属している時に、B belongsTo A とアソシエーションを設定します。
『属してるってなんぞや?』というと、簡単に言えば、『hasOneもしくはhasManyされている』ということです。
A hasOne B もしくは、A hasMany Bという関係が成り立っている場合、B belongsTo Aというアソシエーションとなります。
hasOne や hasMany が存在せず、belongsTo だけ設定した場合でも、アプリによっては何の支障もなく動作します。
しかし、ここでは基礎を学ぶという意味で、逆方向のアソシエーションの存在と『対』で理解してもらうことから始めます。
外部キー
相手方のモデルの主キー(id)を『外部キー』といい、belongsToが設定されたモデルには、必ずこのフィールドが存在します。
たとえば、上述のArticleモデルが複数のコメントを扱うCommentモデルとhasManyの関係にある場合、
- Article hasMany Comment
- Comment belongsTo Article
ですから、Commentモデルには、article_idというフィールドが必要になります。
逆に言えば、以下の原則が成り立つということです。
アソシエーションの基本原則其の二:hasOneおよびhasManyの相手方のモデルには外部キーが存在する
A hasOne B もしくは A hasMany B というアソシエーションの場合、AモデルにはBモデルの外部キーはありません。
分かりやすいhasManyの例で説明すると、上述の例で、Articleモデルにcomment_idというフィールドを設定することは不可能です。
だってコメントは複数存在できるので、フィールドがひとつでは足りませんから(笑)
hasOne も hasMany と同類
『じゃあ、hasOneならあり得る?』かというと、そういうものではありません。
hasOneの場合、どっちに外部キーを置けばよいか分かりづらいため、外部キーを頼りに考えていくと、より混乱をきたしやすいようです。
そういう場合は、心の中で『hasOne は、hasMany の特殊な一形態』と唱えるようにしましょう。
だって、相手方(関連モデル)が『複数くっついているか、ひとつしかくっつかないか』の差でしか無いわけですから、hasOneなら自モデルに外部キーとなるはずはありません。
もちろんhasOneとhasManyはもっと本質的に違いますが、ここではどのようにアソシエーションすればよいかを考えるために単純化しています
外部キーの位置関係のまとめ
外部キーは、hasOneおよびhasManyのときには『相手方のモデルに存在』し、belongsToしているときは『自モデルに存在』するのです。
この原則を守れば、先頭で提示したマスタテーブルの問題も簡単に答えを導けます。
なお、なぜ上記の原則が正しいのかは、ここでは深く追求しませんのであしからず
マスタテーブルはhasOneではなくhasMany
答えを先に言ってしまいました。
それでは順を追って、なぜそうなるのかを説明していきたいと思います。
例の確認
- ブログの記事を扱ったArticleモデルと、その記事のステータスを扱うStatusモデルがある
- ArticleモデルとStatusモデルのアソシエーションを検討する
- Statusモデルは、editing , published , deleted の3レコードのみからなるマスタテーブル
選択肢はみっつ
hasOneと仮定した場合
- Article hasOne Status
- Status belongsTo Article
hasManyと仮定した場合
- Article hasMany Status
- Status belongsTo Article
belongsToと仮定した場合
- Article belongsTo Status
- Status has??? Article
1: 上記の原則を当てはめて考える
まず、外部キーをどちらに設定するかを考えます。
ArticleかStatusか、どちらになるのかは、あまり考える必要が無いでしょう。
マスタテーブルに外部キーを設定する可能性はありませんから。
つまりStatusには外部キーが存在しないと言うことになります。
ということは。
Article belongsTo Status が確定します。
2: Status has??? Article は、hasOne ? hasMany ?
逆に言えば、Status has??? Article ということになります。
では、hasOneなのかhasManyなのかが問題となりますが、この答えも自明でしょう。
記事は無限に増え続けるわけですから、hasManyでないと、statusが足りません(笑)
Status hasMany Article が確定します。
3: ふたたび上記の原則を当てはめて検証する
結果的にhasManyを用いて、以下のようになることが分かりました。
- Article belongsTo Status
- Status hasMany Article
当初イメージした『ArticleがStatusを持っている』という、やってしまいがちな解釈からいくと、逆になりましたね。
では、外部キーがどうなっているかを考えましょう
-
Article
- id
- status_id
- title タイトル
- body 本文
- Other その他
-
Status
- id
- name
はい。間違いなく、上記の原則に沿っています。
それでも新人くんが迷っていたら
1: hasOneは関係を逆にしてもhasOne
hasOneかhasManyかですが、次のような考え方も成り立ちます。
CakePHPのアソシエーションには『1対多』は存在しても『多対1』はありませんよね。
一方でhasOneは『1対1』ですから、User hasOne Profile が存在する場合。それは、Profile hasOne User でもあるわけです。
つまり『関係性をひっくり返してみて成り立つかどうか』で、A hasOne B か A belongsTo B にするべきかを判断することが可能といえます。
上述のArticleとStatusの例で、Article hasOne Status と(間違って)考えたとしても、逆の関係性=『Status hasOne Article が成り立たないから間違っている』と判断することが可能です。
そんなときはArticle hasMany Status なんて突拍子もないことを考えることなく、Article belongsTo Status ( = Status has??? Article)と考えることができますね。
2: hasMany の場合は、Counter Cache を考える
Article hasMany Comment というアソシエーションがあるとき、Article モデルに comment_count というフィールドを設置し、Commentモデルの(belongsTo)アソシエーション時にcounterCache => trueとすると、commentsテーブルにコメントが追加されたり削除されたりするたびに、自動的にArticle.comment_count にコメント数が入ります。
Articleモデル単体を呼び出すだけで、コメント数が分かるようになり、非常に便利です。
Commentモデルを一緒に引っ張ってきた場合でも、すべてのコメントを取得することなくコメント数が分かります
上述の例に戻ると、たとえば『各ステータス別の記事数が知りたい』という場合、以下のようにするでしょう。
# Status Model
# * id
# * name
# * article_count
$statuses = $this->Status->find('list', array('fields' => array('Status.name', 'Status.article_count'));
debug( $statuses );
// example
// editing => 3
// published => 35
// deleted => 7
Status hasMany Article が正解ということは、Counter Cacheが可能であることからも分かりますね。
まとめ
アソシエーションの基本原則
- 外部キーを持っているときはbelongsTo
- hasOneおよびhasManyの相手方のモデルには外部キーが存在する
迷ったら
- マスタテーブルはhasMany
- 外部キーから考える
- hasOneで良いのか迷ったら、関係性を逆にしてhasOneが成り立たなかったら、belongsTo
- hasManyに違和感があったら、Counter Cache が設定できないかを考え、設定できればhasManyで問題ない
以上です。
アソシエーションは油断すると中級者でも混乱します。
CakePHPに不慣れな新人さんが、アソシエーションで迷っていたときの参考に是非。
参考
関連: モデルを結びつける :: モデル :: CakePHPによる開発 :: マニュアル :: 1.2 Collection :: The Cookbook
【CakePHP】アソシエーションで迷ったらこう考えよう | ECWorks Blog
CakePHPでRSS2.0 feed
CakePHPでRSSフィードをはくのは、ものすごくカンタンです。
今回、当ブログで身をもって体験しましたので、ぜひ。
とはいえ、すでに他のサイトでRSSについては、記事になっています。
(わたしも今回参照しながら対応させていただきました。m(_ _)m)
ぜひ、以下のサイトを参考に設定してみてください。
- RssHelper で RSS フィードを生成する :: RSS :: 主要なヘルパー :: マニュアル :: 1.2 Collection :: The Cookbook
- CakePHP1.2でRSS2.0を出力する[RSS][CakePHP] | Web&MUSICブログ QUALL
- CakePHPのRSSヘルパーの使い方まとめ - 頭ん中
基本的な流れは、上記のサイトの方が詳しいので、そちらを見ていただくとしまして、今回は、Web&MUSICブログ QUALLさんのところで対応していたCDATAについての別解です。
まずは、RSS配信の流れから
ほぼ、上述のサイトそのままですが。
config/routes.phpを編集する
# config/routes.php // 追記 Router::parseExtensions();
controllerでRequestHandlerコンポーネントを読み込む
articles_controller に記事があるとします。
# controllers/articles_controller.php or app_controller.php
// 例
var $components = array('RequestHandler',);
viewにRSS用のviewを作成
レイアウトファイルに標準のものを使用する場合は、viewファイルだけを作ります。
ここで、view内にfunctionを書くのに違和感ある場合は、helperに記入すると良いでしょう。
以下は、そんなケースの例です。
ここではMyHelper (my.php) というのがあるとします。
# views/articles/rss/index.ctp
// 記事一覧が $this->data に入っている場合
echo $rss->items($this->data, array($my, 'rss_transform'));
# views/helpers/my.php
<?php
class MyHelper extends AppHelper {
function rss_transform($item)
{
return array(
'title' => $item['articles']['title'],
'link' => array('action' => 'view', $item['articles']['id']),
'description' => array(
'value' => $item['articles']['body'],
'cdata' => true,
'convertEntities' => false,
),
'pubDate' => ['articles']['posted_date'],
);
}
以上でフィードがはかれます。
デフォルトURLは、 上記の例なら、 /articles/index.rss です。
CDATA対応
上記の description のように配列で記述すると、HTMLタグがそのまま入ります。
HTMLタグをエスケープしたくない場合は、convertEntities を false に、中身をCDATAで囲う場合はcdata を true に、それぞれ設定してください。
というわけで、以上です。
このブログもRSS配信をするために、数時間で対応できました。(現在フィードのテスト中)
上述したブログのおかけで、実際の配信部分は30分程度で完了し、残りはRoutingに苦労したのと、CDATAに対応するために試行錯誤しただけ。
CakePHPさまさまです。
CakePHPのバージョンを取得する方法
CakePHPでプラグインを作っていると、現在稼働中のCakePHPのバージョンが1.2なのか1.3なのか知る必要がでてくるかもしれません。
そんなとき、どうやってCakePHPのバージョンを取得するのだろうと思って、IRCで聞いたら、教えてもらいました。
CakePHPのバージョン取得
debug( Configure::version() ); # ex : 1.2.3.8166
Configureクラスを見てみると、どうやら、coreのconfig/config.phpに値がある様子。
で、ソースを見てみると、、、
<?php return $config['Cake.version'] = '1.2.3.8166'; ?>
コメント除くとこれだけでした。
CakeMatsuriは有意義で楽しかった
ブログを書くまでが勉強会であり、ブログを書くまでがCakeMatsuri(祭り)です。
ようやくブログを書き上げた。いまだ、祭り気分が抜けていなかったから、というわけではありませんが。
お祭りもようやく終了です。
私が参加したのは2日目のカンファレンス。
事例紹介等の通常のセッションの他にも、CakePHPのコアデベロッパーの話を直接聞けるということもあり、盛りだくさんの内容。
セッションの様子は、他の方のブログに任せまして、CakeMatsuriで一番得られたものについて書きたいと思います。
私が参加した理由のひとつは、CakePHPの勉強以上に、CakePHPを使っている方々との交流にありました。
せっかくユーザー数が増えているCakePHPです。使っている方とひとりでも多くお話しするに越したことはありません。さらに、コアデベロッパーともお話しできるチャンス。これを逃す手はありません。(まあ英語できないんですけどね。そこは気持ちで押し切ろうと)
さて、カンファレンス当日。
早めに家を出たつもりも、着いてみたら開始5分前。席はまばらでしたが、ちょうど良い時間でした。
cakephperさんに受付してもらい、CakeMatsuri特製手ぬぐいをもらいます。
2種類あって悩みましたが、より祭りっぽい方をチョイス。これはうちに帰って家族にプレゼント。(デザインが素敵だと喜ばれた)
席に着くとほどなくして、隣に外国の方が!日本の人と話ながら座りました。
さすがCakeMatsuriです。インターナショナルですな。
でも、ばりばり日本語が堪能でした。
昼食時に3人で乾杯しお弁当をいただきながらいろいろお話しできました。日本語で。
聞くと、イギリス生まれで7~8年前から日本で働いているとのこと。
着くなりMacBookを開け、おもむろにWindowsを立ち上げました(笑)
何と、USBに開発ツールを始めとしたアプリをすべて詰め込み、家(win)でも会社(Mac)でも同じ環境で作業できるんだそうです。ソノハッソウハナカッタワ。
わたしも今ではその人に教わったportableappsで、USB開発環境を作ってしまいました。Macは持ってないけど取引先のPCでもネットカフェでも開発ができるっていうのは、便利すなあ。
何せUSBさえ持っていけばgitも使えるんですから、ポータブル環境最高です。
さらに、会社でもMacBookにキーボードとディスプレイを外付けしてUSBに入れたアプリで作業していると、笑いながら話してくれました。うん、Macの意味ないですね(笑)
でも見ててMac欲しくなった。
ちなみに会場に来ている方のノートPCはほとんどMacBook。私は今のところノートPCを持たないでやっていけてるのですが、必要になったらこりゃ初Macですね。開発しやすそうだし。
ちなみにちなみに私が持って行ったのはPomera。テキストエディタだけです(恥)
もちろんひとりぼっち。
この陽気なイギリスの方とは、この日いちにち最後まで一緒でした。
そしてこの方と談笑しながら席に着いたのが、帰ってきてからこれ書いた人だと分かって大層びっくりしたヨシダスタジオの中の人。
大体同じくらいのCakePHP歴で、しかも、Croogoの話を聞いた後は、CakePHP製のCMSというお互いの興味がかぶっていることも判明。
職場も私の出身高校の近くということで何かと縁のある方。
さっきサイト見たらTwitter始めたらしいからさっそくフォローした。
カンファレンスの最後のプログラムは懇親会。
ここで、他にも多数の方とお話しできた。
なかには私と同姓同名(漢字一字違い)という方も。よくある名字とよくある名前の組み合わせでも、なかなか同姓同名には当たらないものです。
もしかしたら人生で初かも。
懇親会ではおもに、コアデベロッパーにアタック。
ここで、最近英語に触れてなかったことに激しく後悔。
簡単な表現すらでてこない。orz
気持ちでは押し切れないということが分かりました。
で、何とか話をしたのは。
まず、Grahamさん(@Predominant)とは。
CakePHP1.3やCakePHP2.0ではNameSpaceがサポートされるのかという質問をしたところ、両方ともPHP5.2をサポートするから使わないというお返事。
そうだよね。そうすると結局名付け問題には当分気を遣うことになりそうです。
あとは逆にCakePHPについての不満は?と聞かれてしまう。
実は、正直言って、今のところ不満はないんです。
で、「ない」と応えると、「It's Perfect???(さすがに完璧ってことはないよね?)」と言われてしまった。
「いやあ、パフォーマンスもキャッシュ使ったりで何とかやっているので問題ないんだ、今のところは」って言おうとして、3歳児レベルの片言の英語で必死に伝えようとするものの、伝わるわけはありませんので、最終的には「Yes. Perfect!」といって笑ってごまかした。
でも、Grahamさんは、そんな私のつたない英語を必死に聞いてくれて、ああ、心底良い人だと思いましたよ。わたしは。
イケメンJoelさん(@jperras)とは。
「今までKey Valueストアを避けてきたけど、これからは使います」と、言いたくて、後半だけ伝えた。
「ぜひ使ってみてよ」と笑顔で言われた。
Joelさんは話をするとき、まっすぐ目を見て話す。真剣さが伝わってくる。見習いたい。
他にもいっぱいしゃべったが覚えていないのは、昼からビールを飲み続けたからかも知れない。
そして、2次会にもお邪魔した。
ここでは日本の食事や食材の話が多かった。
いわし明太子やらゴーヤチャンプルやら烏賊の一夜干しやら、続々と「食べたこと無いよね」という料理が注文される中、Grahamさんのベストは「たこわさ」だった。
日本食には全般的に満足してくれたみたいだ。しかもヘルシーすぎて日本から帰ったら7kgもやせていたらしい。
なんで日本人(とくに私)は、日本食で太れるのか。
振り返ってみると、2次会で見たコアデベロッパーの素の姿がとても印象的。
いたって普通だ。いや普通じゃない。いたって良い人たちだ。
デベロッパーが、人間的にも素晴らしいから、CakePHPのプロジェクトは成功しているんだと、改めて思った。
いつか海外のお祭りにも参加してみたい。
この日の解散は深夜0時に近かった。
2週間以上経っても、一瞬たりとも色あせない。とても有意義な一日だった。
運営に携わったすべての方々へ
本当に楽しめたお祭りでした。直接御礼の言葉を言えませんでしたが、どうもありがとうございました。
gitでhookを使ってWebサイトの自動更新
以前のエントリでは、最終的に、テスト環境および本番環境で git pull することによって、それぞれを更新しています。
しかし、git には、push等が実行されると、その後に自動実行してくれるフックメカニズムが用意されています。
これを利用すれば、いちいちbareリポジトリにpush後、手動でgit pullすることなく、自動的に行なわせることができます。
下準備(テスト用と本番用でbranchを分ける)
これは必ずしも同じようにやる必要はありませんが、私の場合は、テスト環境用と本番環境用で、それぞれbranchを分けることにしています。
本番環境用を masterブランチ、テスト環境用を developブランチとします。
まずは、ブランチを作りましょう。
#localhost # 現在のブランチを確認する $ git branch -l * master $ git checkout -b develop $ git branch -l master * develop $ git push origin develop #server $ cd /var/dev ;#テスト環境 $ git checkout -b develop origin/develop
開発はdevelopブランチもしくは、developブランチから分岐したブランチで行ない、テスト環境でのチェック後、developブランチをmasterブランチへmergeします。
#localhost $ git branch -l master * develop $ edit;edit;edit; $ git commit -a; $ git push origin develop #server $ cd /var/dev ;#テスト環境 $ git pull origin develop ;#後述のフックを使用し不要になる操作 #本番サーバーでのテストが完了したら #localhost $ git cehckout master $ git merge develop $ git push origin master #server $ cd /var/www ;#本番環境 $ git pull origin master ;#後述のフックを使用し不要になる操作
これでふたつのブランチで運用することができました。
hookを使用する
hookは、bareリポジトリに設定します。
#server $ cd /repos/bs.git ;#bareリポジトリ $ cp -p hooks/post-update.sample post-update $ vi hooks/post-update # 追記 (cd /var/dev && git --git-dir=.git pull origin develop) (cd /var/www && git --git-dir=.git pull origin master)
これで終了です。
実際にpullされるかを試してみましょう。
#localhost $ git checkout develop $ edit;edit;edit; $ git commit -a $ git push origin develop # このときにテスト環境がdevelopブランチをpullしていることが確認できます。 $ git checkout master $ git merge develop $ git push origin master # このときに本番環境がmasterブランチをpullしていることが確認できます。 $ git checkout develop ;#開発は常にmaster以外のブランチで行なう
めでたく自動化できました。
一度設定すると、本番サーバーでの作業が激減しますね。
さくらインターネットで git push するとgit-receive-pack: Command not found. と言われる問題の応急処置
さくらインターネット(Sakura Internet)で、git push すると、git-receive-pack: Command not found.と表示されてうまくいかないという問題があります。
問題の原因としては、gitコマンドへのパスが通っていないためなのですが、その解決方法が分からずじまい。
この問題については、以下のようなサイトが参考になります。
git [てきとうにめも]
問題の原因が分かっても、どうにも対処できなかったので、pushする側で対処しました。
#localhost
$ cd
$ vi .gitconfig
# 以下を追加
[alias]
spush = push --receive-pack=/home/username/local/git/bin/git-receive-pack
sclone = clone --upload-pack=/home/username/local/git/bin/git-upload-pack
これで git spush origin master とすればreceive-packを指定したことになります。
#localhost $ git commit;git commit;git commit $ git spush origin master $ git spush --all $ git spush --tags
根本的解決が分かったらまたブログ書く。
CakePHPのCache(Viewキャッシュ)について考える
今までさほどシビアにキャッシュについて考えてこなかったのですが、ここらでキャッシュについてまとめてみます。
まずView系のキャッシュのうち代表的なものを。
- element ( & requestAction ) キャッシュ
-
Viewキャッシュ
-
Html Cache Helper
3は、Bakeryに掲載されているMatt氏作成のヘルパーです。初回アクセス時にHTMLファイルを生成するため、以後PHPすら使われません。
多少の制限事項がありますので、それについては、後述。
下に行くほど(1→2→3)キャッシュの威力が大きくなります。
以下順番に見ていきましょう。
1.element ( & requestAction ) キャッシュ
Viewをelement単位でキャッシュしていく方法です。
ヘッダーやフッター、メニューバーやHTMLのheadなど、使い勝手は良いでしょう。
記述の方法は次の通り。
# view
$this->element('element_name' ,array('cache'=>array('time'=>"+2 hours"));
$this->element('element_name' ,array('cache'=>array('time'=>"+2 hours" ,'key'=>$id));
通常は前者で良いのですが、同じelementを別々にキャッシュしたいというときは、後者のようにkeyを渡します。
データが大きいときは'key'=>$id.'_'.md5($data)とでもすれば良いでしょう。
$idは無くてもかまいません。特定のキャッシュファイルを削除するときに分かりやすくしているだけです。
そして、そのelementファイルの中では、requestActionを使用して、データを取得すると良いでしょう。
requestActionは、任意のControllerの任意のactionを個別に呼びだす仕組みです。
右側のカラムにある「○○リスト」等を作成するために重宝します。
# view(element)
echo $this->requestAction('/controller_name/action_name/params' ,array('return'));
第二引数にreturnという値を含めるとレンダリングしたViewを(ただしlayoutは使用せず)返してくれます。
もしデータだけがほしい場合は、actionの最後に return $this->data; のようにしておいて、element側で取得したデータを整形して表示させましょう。
requestActionのパフォーマンスはあまり良くないようですので、elementのキャッシュを使用して効率化してください。
elementのキャッシュファイルを削除する
最後に、requestActionで取得しているデータが更新された場合に、elementのキャッシュファイルを削除する方法です。
ModelのafterSave()とafterDelete()を使用して削除するのが良いようです。
# Model
function afterSave() {
@unlink(CACHE.'views'.DS.'element__action_name');
}
function afterDelete() {
@unlink(CACHE.'views'.DS.'element__action_name');
}
この場合は、当該Modelの全elementのキャッシュが削除されます。
2.Viewキャッシュ
CakePHPのキャッシュは主にこのViewキャッシュで実現します。
このViewキャッシュの最大の特徴は、キャッシュファイルが存在する場合は、Controllerを通らずに、キャッシュされたページを表示する点にあります。
Controller , Component , Model , Behavior , View , Helper 等々のファイルを一切読み込みませんので、非常に高速にページが表示されます。
使用方法は、以下のようにします。
- core.php や bootstrap.php 等で Configure::Cache.check を true にする // Configure::write('Cache.check ', true);
- Controller で CacheHelper を読み込む // var $helpers = array('Cache');
- Controller で cacheAction でキャッシュする時間を指定する // var $cacheAction = 3600; // 秒
$cacheAction には配列を渡して、細かく制御することが可能です。
通常はアクション名(と$id等)を使用します※。詳しくはマニュアルをご参照のこと。
URLルーティングを行なっているときはURLになります。
次のいずれかの設定をした場合にはViewキャッシュは働きません。
キャッシュを(一時的に)使用しない場合には、ここを変更すると一発です。
- Configure::Cache.disable を true にする // Configure::write('Cache.disable', true);
- Configure::debug を 1 以上にする // Configure::write('debug', 2);
3.Html Cache Helper
これはViewをレンダリングした後にHTMLファイルを生成しておき、次回のアクセスからはそのHTMLファイルが直接読みだされるという仕組みのキャッシュです。
生成されるファイルがHTML(正確には非PHP)なので、動的に変化する要素の記述はできませんが、静的ページやRSSなどの書き出しには非常に優れています。
ヘルパーのコードは、HTML Cache - GitHub より取得し、APP/plugins/html_cache に配置してください。(downloadリンクよりzip形式でダウンロードすることも可能)
# directories
plugins/
html_cache/
views/helpers/html_cache.php
使い方は簡単です。Controllerで$helperの最後にヘルパーを記述し、 webroot/.htaccess を編集するだけ。具体的には。
# Controller (他のHelperよりも後に記述)
var $helper = array('XXX','YYY','ZZZ','HtmlCache.HtmlCache');
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^GET$
RewriteCond %{DOCUMENT_ROOT}/cache/$1/index.html -f
RewriteRule ^(.*)$ /cache/$1/index.html [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
すると webroot/cache以下にURLをもとにファイルが生成されます。(cacheディレクトリはパーミッション707等で作成)
CakePHPは標準の設定で、CSS等ファイルが実在する場合は、ルーティングを行いません。そのため生成されたHTMLファイルが直接WEBサーバーより読み込まれます。
注意事項としては、
・/controller_name 等のURL(action名のないURL)やルートに対してはキャッシュが働かない(仕様変更により可能になりました)
→/controller_name/indexのようなURLにはキャッシュが働きます
・キャッシュファイルの生存期間(expires)は設定できない
→bakeryの記述を参考にcron等で一定期間ごとに自動的に削除するようにします
・パーミッションを適切に設定する
→ファイルの書き出しはwebサーバー等の権限で行われます。webroot/cache以下に書き込み権限がないといけません。また、webroot/cacheはあらかじめディレクトリを作成しておく等の必要があります。
用途と環境に応じて選択しましょう
以上です。
利用する状況に応じてキャッシュの種類を使い分け、快適なサービスを提供していきましょう。
第1回CakePHPオフ会@関東
昨日(2009/08/05)、前回のIRC集会終了後に話題が上がった「勉強会ではなく懇親会」(つまりいわゆるオフ会)が開催されました。
過去勉強会とは縁がなかったわたしも、今回は参加申込みをし、いそいそと曙橋の会場へ。
10数人という非常に適切な規模による、素敵なオフ会がスタートしました。
こういった場所に初参加のわたしは、もちろんみな初対面。CakePHP界では名の知れた方々もちらほら。
でも、IRC等ではちょっとだけ繋がりがあったりするので、遠慮することを遠慮させてもらいました。勝手に(笑)
プレミアムビールで乾杯し、ピザや差し入れのお菓子をつまみつつ、LTを聞いてあれやこれやとCakePHPについての話題を語る。
非常に幸せな空間がそこにありました。
会場はビルの屋上のテラスのようなところ。屋根を解放すると、心地よい風が吹き抜ける。
ビールが進むこと、進むこと。ぐいっぐいっ
ドイツで行なわれたCakePHPフェスタの貴重な話も聞けて、大満足な一夜でした。
gitでpushしたりpullしたり
なんかおかしいと思いつつも、決定的な情報がなかったために間違ったやり方をしていたのですが、ひょんなことから正しい情報をゲットしたので、私はこうやって使っていますという話を。
(もしかしたらまだまだ非効率なやりかたをしていると思うので是非ご指摘ください)
バージョン管理システム自体を知らなかった自分にも理解できるよう、かみ砕いた説明をしたいと思います。
基本的にgitは、sshが使えれば、導入をためらうことはありません。
サーバー間のやりとりはsshを使って行えますので、gitを導入するにあたって余計なポートをあけたりする必要はないです。
gitでは、今いるレポジトリ(ソースを入れてるディレクトリ)を特に「ローカルレポジトリ」と呼び、やりとりする相手方を「リモートレポジトリ」と呼びます。
普段開発している社内のPCを開発サーバー(開発環境)と呼び、Webサイトを公開しているサーバーにはテスト環境と本番環境が入っているとします。
それぞれ○○環境ごとに、CakePHPのappディレクトリがあると考えると良いですね。
ここで、開発サーバーも公開サーバーもコマンドラインによる操作ができ、公開サーバーは外部からSSHが利用できるものとします。(開発サーバーは外からsshでつながらなくて良いです)
開発サーバーをlocalhostと呼び、公開サーバーをexample.comと呼びます。
www.example.comで本番環境のサイトが表示され、dev.example.comにはアクセス制限をかけてテスト環境を表示していることにします。
appファイルはそれぞれ、/var/appと、/var/www/および/var/devにあることとします。
gitを利用する場合は、このほかに、もうひとつ、bareレポジトリという、共用のレポジトリを用意するのがコツです。
このレポジトリはどこからでもアクセスでき、ローカルで行った変更を、手軽に反映させることができるのです。
svnを利用している人には、逆に少し分かりづらいかもしれません。
svnにおいては、この共用レポジトリこそが唯一のレポジトリということになります。その他はチェックアウトしているだけで、それ自体はレポジトリとは呼びません。
しかし分散型のバージョン管理システムであるgitは、レポジトリから「clone」したその場所もまた、レポジトリなのです。
このことは、ローカルレポジトリの中だけで、バージョン管理ができるということを意味します。
そして必要に応じてのみ、共用レポジトリにその更新を伝えれば足り、すべてのバージョンをその都度(毎回)共用レポジトリに伝える必要がないため、ローカルレポジトリで作業する間は、極端な話インターネットにアクセスできなくても開発は可能です。(もちろんバージョン管理を行いながらです)
具体的な手順はより詳しい方の説明の方が良いと思いますのでそちらを参照してもらうとして、ここではCakePHPで実際どのような流れで開発がされるのかを説明していきます。
まず、共用レポジトリと、www.example.comとdev.example.comのふたつのレポジトリを作成しましょう。
(アプリケーションをbsとします)
# 準備として共用レポジトリ用のディレクトリを作成します $ mkdir /repos # 共用レポジトリ用のディレクトリを作成(共用の場合は.gitをつけるのが慣例です) $ mkdir /repos/bs.git $ cd /repos/bs.git # gitレポジトリ(共用 --bare)を作成 $ git clone --bare git://github.com/monsat/cakephp-plain-app.git #でCakePHP用の初期ファイルのセットが手に入ります。 # git init --bare # 空で作成する場合はcloneの代わりにこれ # テスト・本番用ディレクトリを作成 $ cd /var # 分かりやすく短いパスで説明しています $ git clone /repos/bs.git dev $ git clone /repos/bs.git www
次に開発環境のPCに、開発用のレポジトリを作成しましょう。
# localhost $ cd /var $ git clone ssh://example.com/repos/bs.git app
これで準備は整いました。
コマンドについては詳しく説明しませんが、cloneはレポジトリを複製するコマンドです。
いちからレポジトリを作成する場合は、ディレクトリの中で git init とすると、そのなかに .git という隠しディレクトリが作成されます。
(いつでもそれを削除することで通常のディレクトリになります。逆に言えば、この特別なディレクトリを誤って削除しないようにしましょう。変更履歴をすべて失いかねません)
それではアプリを開発してもらいますが、CakePHP特有の設定を。
gitでは、バージョン管理したくないファイルを .gitignore というファイルに記述することで設定することができます。
CakePHPの場合はtmpディレクトリ以下がそれにあたり、その場合には
tmp/**/*
と記述すると、tmp以下すべてとなります。
tmp以下には、ファイルのパスの情報も入っていますので、これらのファイルがテスト環境や本番環境にコピーされてしまうと、CakePHPは正しく動作しません。場合によってはただ真っ白なページが表示されるということがあります。
それでは開発をすすめていったとします。
(本当はbranchという考え方を理解する必要がありますがそれは省略)
開発の小さな区切りごとに commit という作業を行います。
このcommitがいわばマイルストーンとなり、commitした時点のレポジトリ内の状態に、いつでも戻せます。ファイルが更新される前とか、ディレクトリを作成する前、といった状態にです。
これがバージョン管理システムの肝でして、元に戻す命令を出すと、レポジトリ(ディレクトリ)の中は、あら不思議、一変するのです。元に戻した後に、最新の状態に復帰するのもコマンド一発ですので、またさらに元に戻すことができます。
しかしそれはあくまでcommitを単位として記録されていきますので、「ひとつの機能ごとに」こまめにコミットしていきましょう。
svnと違ってgitの良いところは、このコミットをするのはあくまでローカルレポジトリに閉じた話だということです。svnの場合はコミットごとに中央の(唯一の)レポジトリにアクセスすることになるため、今回の例でいえば、都度SSHによるアクセスが入ります。(公開サーバーへのアクセスはSSH経由です)
gitの場合はコミットはローカルレポジトリで行い、テスト環境や本番環境を変更するときだけ、共用レポジトリを利用する(=共用レポジトリにコミットの履歴を伝える)ことも可能です。
前述したインターネットにつながってなくても開発ができるという状態のことです。
コミットは以下のように行いますが、詳しくは例によって省略。
$ cd /var/app $ git add file_name # 新規作成したファイルがあれば実行。複数あれば git add . ですべて $ git commit -a
コミットの都度shaによる40桁のIDが生成されます。このIDは、元に戻ったりするときに使用されますが、一意に特定できれば先頭の数文字の指定で間に合います。(当初は一桁でもいけるはずです)
そして、公開サーバーにある共用レポジトリへコミットの履歴を反映させる手順です。
# localhost $ cd /var/app $ git push
cloneしてきたリモートレポジトリに反映をさせるのは、git push と引数を省略することができるのでらくちんです。
もし複数人の開発等で共用レポジトリが更新されている「可能性がある」のであれば、push の前に git pull を行います。賢いgitが、あなたと他人の更新がごっちゃにならないように、うまく融合(merge)してくれるでしょう。
あとは、テスト環境本番環境とも、それぞれ git pull するだけで、開発した内容をそれぞれに反映させることができます。
テスト環境を反映させ、公開サーバー上でもアプリに不具合がないことを充分にテストしてから、本番環境を更新しましょう。
# example.com # dev $ cd /var/dev $ git pull # テスト実行。問題なければ本番環境へ # www $ cd /var/www $ git pull
駆け足でしたが、以上です。
CakePHPにおける開発環境について
前回のIRC集会で話題になった開発環境について、記録としてポストしておきたいと思います。
以前は「FTPもしくはSCPでファイルをアップし動作確認」という面倒なことをやっていました。
しかし、仮想化ソフトを利用してマシン内にLinuxを入れてしまえばわざわざFTPすること無いよねと、至極当たり前のことに気づいたのです。
(もちろん物理的に開発用のLinuxがあれば仮想化も必要ありませんが)
基本的にウィンドウズ(XAMPP)で開発環境を構築したくはないという好き嫌いの話があって、Linuxは前提で。
さて、仮想化ソフトは何にしようかといろいろ調べ、どうやらVMwarePlayerというのが、使っているPCのスペックでも何とかなりそうだという結論に。
しかし「OSを何にするか」ではたと悩むことに。
というのも最近はあまりOSのインストールをしていなかったのと、そもそもVineLinuxくらいしかまともに触ったことがなかったので、安定しているという噂のCentOSでいけそうなのかどうかを、これまた半日がかりで調べました。
で、どうやらいけそうだと。
利用者も多そうで(ここ大事)ネットの情報が溢れてる。
というわけで、各所を見ながら、エイヤとインストール。
(この辺も後々のためにまとめておかなきゃ。後日)
当初はどうやってファイルを共有しようかともやもやしてましたが、何のことはないsambaで共有すれば良いのでした。vmwareの共有機能を使おうとしたのは何だったのか。。。
で、めでたくファイルの共有ができたので、普段使いのEclipseで新しくプロジェクトを作成します。
あとは、CentOSにgitをインストールし、gitでサーバーにアップできるようにして完了。
とにかくこのgitが超絶便利。
gitを使いたいというモチベーションがなかったら、VMwareでLinuxという環境はできていなかったほど、今の私には重要なソフトです。
環境構築後にTortoiseGitのバージョンがあがり使い勝手が良くなっていますが、そのときは使いづらかったのです。
svnには挫折した私も、この便利さ・快適さには勝てません。
CakePHPと一緒で、慣れるまでは覚えることが多くて苦労をしても、使い始めるともはや手放すことができません。
CakePHPも1.3はgitによって管理されています。
thechawというgitレポジトリもでき、各種Plugin等が公開されています。
zipでダウンロードして解凍して、、、なんて手間はなくなるし、バージョンアップしたらコマンド一発です。
でも、もっともっと便利な環境が、世の中にはあるのだろうなあ。それは多分半年後の話。
counterCache (HABTMでも)
カウンターキャッシュとは、hasManyしている関連Modelがあるとき、そのModelの件数を元Modelに保持しておく機能です。
http://book.cakephp.org/ja/view/81/belongsTo
たとえばArticle hasMany Comment というコメントを複数ぶらさげている記事があったとき、コメントの件数をArticle Modelに持たせることができます。
これによりわざわざコメントModelを取得することなく、コメントの件数を(記事一覧ページに)表示させるといったことが可能です。
データベースの構造からすると冗長なデータの持ち方ともいえますが、フィールドをひとつ増やすことでDBへのアクセスを減らすことが見込めますので、ぜひ積極的に活用したい機能です。
使い方は簡単です。
HABTMのcounterCacheは後述します。
まず、上記の例でArticleにあたるModelにフィールドを追加します。
- model_name_count integer
上記の例では comment_count です。
つぎに、関連先のModelのアソシエーションを以下のように変更します。
# models/comment.php var $belongsTo = array( 'Article' => array( 'counterCache' => true, 'counterScope' => '', ), );
これだけです。
これだけで、コメントがadd , edit ,delete されるたびに、紐付いたコメントの件数がArticleに書き込まれます。
実際にデバッグモードで発行されるSQL文を確認すると、insert等のあとにselect count(*) して、Articleをupdateしているのがわかります。
HABTMでcounterCacheを使う
さて、非常に簡単なcounterCacheですが、残念ながらHABTMでは使えません。
Article hasAndBelongsToMany Tag ※となっているとき、ArticleにはTagの件数を、TagにはArticleの件数を持っておきたいというのが人情です。
タグ(tag)付けされた、複数の記事(article)がある状況
そこで登場するのが、bakeryに投稿されたこのビヘイビア(CounterCacheHabtmBehavior)です。
このビヘイビアのすばらしいところは、それぞれのModelに xxx_count というフィールドを用意し、$actsAsで指定すれば、それだけで良いということです。
# model
// 両方のモデルに記述します
// カウントはxxx_countというフィールドが存在しているときのみ実行されます
var $actsAs = array('CounterCacheHabtm');
なお、片方のModelのみに xxx_count を用意した場合も、何の設定も必要なく、動作いたします。
(xxx_countが存在しない場合はカウントされません)
CakePHP IRC集会 (2009年07月)
昨日(2009/07/01)は、第3回CakePHP IRC集会が開催された。
今回は「平日の昼間開催」というおもしろい試みでした。
参加人数は約40人。みんな仕事中なのに何やってんだか(笑)
いつもどおりのゆるめの雰囲気で終始し、途中わたしの空気を読めない質問でCakePHP界の大御所たちの貴重な時間を使いつつ、閉会。
閉会後も残ったメンバーの一部が盛り上がり、次回の開催やオフ会の話題で夜まで話は尽きませんでした。
※オフ会は8月上旬に東京で開催予定だそうです。
今回もMASA-Pさんより話がありましたが、返す返すも「CakePHP界隈の雰囲気は良い」のです。
これは貴重なことですね。
さて、最後になりますが、ちょうど開催がCakePHP1.2ガイドブックの発売直後だったということもあり、著者を前にして「買った」「買います」の嵐。
なかには「会社の上司を説得するための必殺トーク教えて」というオーダーも。(しかもそれを著者自ら答えるというサービスぶり)
実際CakePHPガイドブックがなければCakePHPはここまで盛り上がったとは思えません。それくらい1.1版の前著はよくできていました。
その前著を50ページも増ページした今回も間違いなく「買い」です。
CakePHPはRapid Developmentに最適なツールではありますが、慣れるまで(いや慣れてからもしばしば)開発中にはまってしまうことがあります。
生産性が非常に高まるはずのCakePHPも、使用初期はその思想等に慣れるまでどうしても遠回りしてしまうことがあるのです。
そんなとき、マニュアルだけでなく、このような良書を手元に置いておくということは開発初期の生産性を保つための最善の手段です。
「多大の時間の損失を防ぐことができるでしょう」
また、前著をすでに持っている人や、すでに中級者レベルに達している人も、この本を持っておいたほうが良いと思います。
というのは、この本は、CakePHP1.0という初期からCakePHPに関わっているこの世界の重鎮による著作だからです。
ここにはCakePHPを利用するうえで非常に有効な「優れたコード」が満載です。
自分のCakePHPの使い方に「もっと良い方法がないか」と上を目指すためのヒントが見つかることでしょう。
そう考えると、この3,360円という価格は投資額として安価です。
なぜなら必ずやその何倍ものベネフィットをもたらすわけですから。
それではIRC集会に参加したみなさん。また次回。
cakephperさん、どうもお疲れさまでした。
Tree Behavior & Tree Helper
CakePHPのCore BehaviorであるTree Behavior は、簡単にツリー構造のデータを扱うことができる便利なビヘイビアです。
http://book.cakephp.org/ja/complete/91/Tree
さらに、bakeryで公開されている準公式HelperであるTree Helperと併せて利用すると、その簡単さに誰もが驚くことでしょう。
得意なデータはたとえば次のようなものがあります。
- ディレクトリ
- カテゴリ(親子形式のあるもの)
- ユーザーグループ
- その他
基本的に何らかのデータをhasManyするModelが適していると思われます。
例として、複数のArticleを持つCategory Model のテーブルをみてみましょう。
- id integer
- name string
- article_count integer # counterCache用 ※任意
- parent_id integer # Tree Behavior用
- lft integer # Tree Behavior用
- rght integer # Tree Behavior用
- その他必要なフィールド
関連付けは以下の通りです。
# Category Model
var $hasMany = array('Article');
var $actsAs = array('Tree');
# Article Model
var $belongsTo = array('Category' => array(
'counterCache' => true, # counterCache用 ※任意
));
# Categories Controller
var $helpers = array('Tree');
これだけで準備はできました。
なお、Tree Helper は、Bakeryよりコピーしてきてください。
他のappと共用しているpluginsディレクトリがあれば、そこに入れておくとよいでしょう。
基本的な使い方
その1:ArticlesControllerで、addやeditをするときのセレクトボックス用のデータを作成する
# ArticlesController
$categories = $this->Article->Category->generatetreelist(null ,null ,null ,' ');
# views/articles/edit.ctp
echo $form->input('category_id' ,aa('label',"カテゴリ"));
参照:http://book.cakephp.org/ja/view/517/generatetreelist
その2:カテゴリの一覧を取得する
# ArticlesController
$conditions = array(
'Category.article_count >' => 0,
); // Articleが一件以上登録されているもののみ取得する場合
$this->data = $this->Category->find('all' ,compact('conditions') );
これは通常通りに取得可能です。
その3:カテゴリパス用のデータを取得する
# CategoriesController
$parents = $this->Category->getpath( $category_id );
$this->set('parents' ,$parents);
# view
foreach ($parents as $parent) {
$html->addCrumbs(
$parent['Category']['name'] ,
'/categories/index/' . $parent['Category']['id']
);
}
$html->getCrumbs('>' ,'TOP');
viewのコードはHelperにおいておき、layoutファイルから読みだすとスマートです。
参照:http://book.cakephp.org/ja/view/235/getpath
その4:カテゴリの順序を変える
カテゴリの並びを変更するにはふたつのやり方があります。
ひとつは、親カテゴリをつけかえることです。
たとえば以下のようなツリーを想定します。
-
CakePHP
-
View
- element
- ヘルパー
-
Controller
- コンポーネント
- Model
-
View
- レイアウト
- CSS
- HTML
「レイアウト」のparent_idに「View」のidを指定すれば、レイアウトがViewの子供(のカテゴリ)になるので、ヘルパーの次に表示されるようになるでしょう。
# controller
$this->Category->id = 8; // 「レイアウト」の ID
$newParentId = $this->Category->field('id', array('name' => 'View'));
$this->Category->save(array('parent_id' => $newParentId));
では、ヘルパーをelementより先に表示したい場合はどうするのかというのが二つ目の方法です。
「同じ階層の中で順序を変更するとき」はmoveUpおよびmoveDownメソッドを使用します。
マニュアルでは階層を上下させることができるような記述がありますが、あくまで同じ階層のなかで順位を変更するメソッドです。
上記の例でelementをmoveUpしてもすでに同階層の先頭に位置しているため、moveUpは失敗します。
# controller // ひとつ下に順位を下げる $this->Category->moveDown($this->Category->id, 1); # controller // ひとつ上に順位を上げる $this->Category->moveUp($this->Category->id, 1);
参照:http://book.cakephp.org/ja/view/229/Advanced-Usage
マニュアルに詳しい使用例が載っているので参考にしてください。
その5:初期データを設定する
Tree Behaviorを使うときに真っ先に苦労するのが、初期データの登録です。
もともと何らかのデータがある場合、それをインポートするために、単純にphpMyAdminなどでinsertしようとしても、lftやrghtの値を自分でつけるわけにはいかずに右往左往してしまいます。
で、そんなときは、lft・rhtをnullのままにしておき、id,name,parent_idのみを(何らかの方法で)インポートしてください。
あとは、以下のメソッドを実行するだけで、すべてのlft,rghtが割り振られます。
# controller $this->Category->reorder();
admin_reorderというactionにしておくとよいかもしれません。
また、recoverというメソッドもあり、何らかの不用意な操作でTree構造が壊れたときは、これで修復が試みられるそうです。
私は、まだ実際に使ったことはありません。
その6:データの削除
addやeditは通常通りsave()で行いますが、delete()してしまうと、Tree構造が壊れてしまいます。
delete()の代わりにremoveFromTree()が用意されていますので、そちらを利用しましょう。
Tips
Modelであらかじめ $order = array('lft ASC'); としておくと、常に順序よくデータを取得できます。