ECWorks Blog

ECWorks Blog

CakePHPを中心としたサイト開発情報をメインに公開。新しもの好きなので時々製品レポートなんかも。

【Ktai】「Ktai Library」バージョンアップ少し延期のお知らせとviewの話

icon_ktai何度もお騒がせしてしまい申し訳ございません。
先ほど「バージョンアップ予定」としましたが、心配していた内容は回避されていたため、少し延期します。

このままでは、やると言ったり止めると言ったり、訳が分からないでしょうから、経緯説明を兼ねて、CakePHPの仕組みについて説明をしようと思います。ちょっとCakePHPの内部の込み入った話をしますので、もしかしたら難しいと感じるかもしれませんが、まあそういうものだと思っていただいてOKです。

発端は、ヘルパーでライブラリ本体である「lib3gk」の初期化をbeforeRender()内で行っているのですが、よくよく考えてみたら、beforeRender()はView::_render()内で「何度も呼ばれてしまうのではないか」という懸念があったからです。というのは、beforeRender()とafterRender()はView::_render()でコールされるのですが、ビューファイルが展開されるたびにView::_render()が呼ばれるからです。ここで言うビューファイルというのは、一般的なビュー以外にもlayoutファイルも含まれ、最低でも2回は毎度呼ばれることになります。つまり、その都度ライブラリがクリアされ、初期化されるようであれば、非常に無駄が発生することになり、バグも生みかねません。

で、結論から言いますと、beforeRenderおよびafterRenderは、ヘルパーが初めて読み込まれた場合、つまり初めてView::_render()が呼ばれた場合だけ行われるため、実害がなかったことが分かりました。なので、現バージョンのままお使いいただいて問題なく、結果バージョンアップは不要だという判断になりました。

そしてその副産物として、今まで不可解だったhelperコールバックのことがやっと少し分かりました。
今回outputがどうしてもうまく受け取れなくて困っていたのですが、この挙動に問題があったようです。

私はCakePHP1.1後期からのCake使いなのですが、RC1が出るまでは、outputはafterRender内でob_get_clean()で受け取るのが一般的な手法で、私もそのように行っていました。ところが、RC1からこの手法が使えなくなり、変わりにView::outputプロパティが受け渡しとして使われるようになりました。そして、この頃からbeforeRender,afterRender以外に「beforeLayout()」「afterLayout()」コールバックが追加されました。

今回KtaiLibraryを実現するにあたり、outputは「afterLayout()」で受け取れば問題なく処理が出来ることが分かりました。方法は

function afterLayout(){
  $view =& ClassRegistry::getObject('view');
  $view->output = mb_convert_encoding($view->output, 'SJIS');
}

という感じです。
ところが、「afterLayoutで受け取れるんだから、初期化はbeforeLayoutだろう」という思惑でいたところ、どうも具合がおかしい。ライブラリのインスタンスが作成されていない状態で、エラーが出てしまいます。初期化はbeforeRenderでやらないとダメなのです。

私は、「beforeLayout()→ (beforeRender()→afterRender()){n} →afterLayout()」の順番で処理が行われると推測していたのですが、初期化はbeforeRenderとなると、「beforeRender()→beforeLayout()→afterLayout()→afterRender()」の順番ではないか? でも実際にはafterRender()では何も入手できない(ob_start()でバッファスタートしているにもかかわらずob_get_clean()では何も入っていない)のです。

想定とは全く違っていました。
「beforeRender()→afterRender()→beforeLayout()→afterLayout()」というのが正しい順番です。

なぜこうなるのか。
それは「View::_render()内で初めてhelperが読み込まれたときだけ」実行されるから、だったのです。
ビューの処理は、まずビューを読み込んでからレイアウト処理を行います。この「まず」の部分でbeforeRenderとafterRenderのコールバックが呼ばれます。次に、レイアウト処理に入って、まずafterLayout。そしてレイアウトファイルをView::_render()を使って読み込むのですが、この中のbeforeRenderとafterRenderは2度目となるので実行されません。そして最後にafterLayoutが呼ばれ、終了…という感じなのです。

なぜこのような仕組みが提供されているのか、その心はさっぱり分かりません。
これでは、afterRenderとbeforeLayoutはほとんど役立たずです。
また、始まりがbeforeRenderで終わりがafterLayoutというのも、なんだかスマートではない…
「beforeLayout()→ (beforeRender()→afterRender()){n} →afterLayout()」という流れが一番自然な気がします。
この流れは改善の余地があるのではないでしょうか?

ちなみに、Ktai Libraryはバージョンアップしたいと言えばしたいです。
うっかりミスをしてしまった箇所がありまして…
なんと、get_version()でとれるバージョン番号が「0.0.2RC4」となってしまっているのです。
バージョン番号を直すのを忘れてしまいました(大汗)。
これだけを直すバージョンアップは、さすがにアレですので(^^;;;

とうわけで、お騒がせしてしまったこと、重ねてお詫び申し上げますm(__)m。

【追記】(2009.11.18)
コールバックの順番ですが、1.2.5(それ以前も?)では修正がされていて、「beforeRender()→beforeLayout()→afterLayout()→afterRender()」の順になっていました。どうやらこの現象はバグだったようです。
icon_ktai何度もお騒がせしてしまい申し訳ございません。
先ほど「バージョンアップ予定」としましたが、心配していた内容は回避されていたため、少し延期します。

このままでは、やると言ったり止めると言ったり、訳が分からないでしょうから、経緯説明を兼ねて、CakePHPの仕組みについて説明をしようと思います。ちょっとCakePHPの内部の込み入った話をしますので、もしかしたら難しいと感じるかもしれませんが、まあそういうものだと思っていただいてOKです。

発端は、ヘルパーでライブラリ本体である「lib3gk」の初期化をbeforeRender()内で行っているのですが、よくよく考えてみたら、beforeRender()はView::_render()内で「何度も呼ばれてしまうのではないか」という懸念があったからです。というのは、beforeRender()とafterRender()はView::_render()でコールされるのですが、ビューファイルが展開されるたびにView::_render()が呼ばれるからです。ここで言うビューファイルというのは、一般的なビュー以外にもlayoutファイルも含まれ、最低でも2回は毎度呼ばれることになります。つまり、その都度ライブラリがクリアされ、初期化されるようであれば、非常に無駄が発生することになり、バグも生みかねません。

で、結論から言いますと、beforeRenderおよびafterRenderは、ヘルパーが初めて読み込まれた場合、つまり初めてView::_render()が呼ばれた場合だけ行われるため、実害がなかったことが分かりました。なので、現バージョンのままお使いいただいて問題なく、結果バージョンアップは不要だという判断になりました。

そしてその副産物として、今まで不可解だったhelperコールバックのことがやっと少し分かりました。
今回outputがどうしてもうまく受け取れなくて困っていたのですが、この挙動に問題があったようです。

私はCakePHP1.1後期からのCake使いなのですが、RC1が出るまでは、outputはafterRender内でob_get_clean()で受け取るのが一般的な手法で、私もそのように行っていました。ところが、RC1からこの手法が使えなくなり、変わりにView::outputプロパティが受け渡しとして使われるようになりました。そして、この頃からbeforeRender,afterRender以外に「beforeLayout()」「afterLayout()」コールバックが追加されました。

今回KtaiLibraryを実現するにあたり、outputは「afterLayout()」で受け取れば問題なく処理が出来ることが分かりました。方法は

function afterLayout(){
  $view =& ClassRegistry::getObject('view');
  $view->output = mb_convert_encoding($view->output, 'SJIS');
}

という感じです。
ところが、「afterLayoutで受け取れるんだから、初期化はbeforeLayoutだろう」という思惑でいたところ、どうも具合がおかしい。ライブラリのインスタンスが作成されていない状態で、エラーが出てしまいます。初期化はbeforeRenderでやらないとダメなのです。

私は、「beforeLayout()→ (beforeRender()→afterRender()){n} →afterLayout()」の順番で処理が行われると推測していたのですが、初期化はbeforeRenderとなると、「beforeRender()→beforeLayout()→afterLayout()→afterRender()」の順番ではないか? でも実際にはafterRender()では何も入手できない(ob_start()でバッファスタートしているにもかかわらずob_get_clean()では何も入っていない)のです。

想定とは全く違っていました。
「beforeRender()→afterRender()→beforeLayout()→afterLayout()」というのが正しい順番です。

なぜこうなるのか。
それは「View::_render()内で初めてhelperが読み込まれたときだけ」実行されるから、だったのです。
ビューの処理は、まずビューを読み込んでからレイアウト処理を行います。この「まず」の部分でbeforeRenderとafterRenderのコールバックが呼ばれます。次に、レイアウト処理に入って、まずafterLayout。そしてレイアウトファイルをView::_render()を使って読み込むのですが、この中のbeforeRenderとafterRenderは2度目となるので実行されません。そして最後にafterLayoutが呼ばれ、終了…という感じなのです。

なぜこのような仕組みが提供されているのか、その心はさっぱり分かりません。
これでは、afterRenderとbeforeLayoutはほとんど役立たずです。
また、始まりがbeforeRenderで終わりがafterLayoutというのも、なんだかスマートではない…
「beforeLayout()→ (beforeRender()→afterRender()){n} →afterLayout()」という流れが一番自然な気がします。
この流れは改善の余地があるのではないでしょうか?

ちなみに、Ktai Libraryはバージョンアップしたいと言えばしたいです。
うっかりミスをしてしまった箇所がありまして…
なんと、get_version()でとれるバージョン番号が「0.0.2RC4」となってしまっているのです。
バージョン番号を直すのを忘れてしまいました(大汗)。
これだけを直すバージョンアップは、さすがにアレですので(^^;;;

とうわけで、お騒がせしてしまったこと、重ねてお詫び申し上げますm(__)m。

【追記】(2009.11.18)
コールバックの順番ですが、1.2.5(それ以前も?)では修正がされていて、「beforeRender()→beforeLayout()→afterLayout()→afterRender()」の順になっていました。どうやらこの現象はバグだったようです。


Tagged as: , , , , ,

Comments are closed.