ActionStackとViewRendererとZend_Layoutの連携

ActionStackとViewRendererとZend_Layoutを組み合わせると、ページ構成を決定するコントローラーから任意のコントローラー経由で収集したコンテンツをレイアウトの各セグメントで利用できるようになる。
たとえば、メニューに投入するコンテンツは$this->layout()->menuに、中心となるコンテンツその他については、$this->layout()->contentにといったことをコントローラーをパーツ化させて実装しつつ、レイアウト用に集約できるようになる。
http://d.hatena.ne.jp/noopable/20090131/1233356124
ここで参照したドキュメントの内容をもう少し実践的にした感じ。

ActionStackで出力されるコンテンツを指定のレスポンスセグメントへ

ActionStackはドキュメント通りの使い方をすると、レスポンスセグメントのdefaultに出力コンテンツがたまる。ActionStackでは投入先のレスポンスセグメントを指定する機能はない。ActionStackの仕事とは考えられていないからだろう。その辺は納得。
ActionStackにはセグメント指定できないので、別セグメントにコンテンツを投入するには若干の工夫が必要。
ViewRendererにはsetResponseSegmentという便利なメソッドがあるので、それを利用してみる。ActionStackをコールする前にViewRendererにレスポンスセグメントを指定しておくことで、ViewRendererを利用しているアクションコントローラーのコンテンツはその指定セグメントに集約できる。スタックの最後にレスポンスセグメントを元に戻すコントローラーをセットする必要はある。

ActionStackの処理系列を複数使用

ActionStackの利用が1本のラインだけで済むのなら上記で十分なわけだが、もし、メニューを集約するコントローラー、本体を集約するためのコントローラーを別に作成してある場合、それらのコントローラーを_forwardで結んで再帰的に処理させる感じになる。ここで、ActionStackに対するレスポンスセグメントの指定を解除したりといった流れを考えると、ActionStackを使いきったあとに、次のスタックを使わなければいけない。しかし、直接コールする形ではないので、スタックを使いきった後に制御を戻すのは本筋ではない。
ここを1本線で処理させるジャンクな処理ができないわけではないが、ActionStackが使っているレジストリのキーを使えばもう少しスマートに処理できそうだ。ActionStackに対してsetRegistryKeyしてあげることで、複数のスタック列を使うことができる。
レジストリキーの管理がしっかりできていれば、ActionStackを複数使いながら、それぞれを別のレスポンスセグメントに投入できるようになる。

これで、ページ構成用のゾーンから、レイアウトへの流れを自由に設定できるようになる。
http://d.hatena.ne.jp/noopable/20090212/1234388931
メッセージキューで似たようなことを出来るようにしたけど、うーん、処理が重い割にあんまりメリットなかったかな・・・と反省。

ActionStackの仕様で一つだけ

ActionStackの処理系では、あるコントローラーに与えた指示が次のコントローラーにも伝搬してしまう。ディスパッチループに入っているグローバルなリクエストオブジェクトに対して、次々にパラメータを上書きしていってしまう元からあるパラメーターは上書きできないところがちょっと。

  • パターン1
    • ctrlA → ctrlB → ctrlC
  • パターン2
    • ctrlA → ctrlC

と処理するとき、AとCへのリクエストが同一でも、Bへのリクエストのパラメータの中にCで使うものがある場合、予期せぬ動作になる。
パターン1と2でctrlCの動作が変化する可能性をスタックするときにきにしなきゃいけない。そこに微妙なカップリングがあるのは・・・