Railsっぽいのを実装する。
Ethnaの場合は、コントローラが1つしかないので、コントローラ単位で場面ごとにlayoutを切り替えるのが難しい。しかしフォルダ分けに対応しているので、フォルダ単位でlayoutが適用される方法を考える。
ルールとしては、template/ja/以下に、layoutというフォルダを作る。
このフォルダ以下を、以下のような規則にする。
- 拡張子は.tpl
- ViewClassに$layout変数があれば、それで指定された($layout = 'aaa/bbb.tpl';みたいに指定)templateを展開する。
- 使用するtemplateと同名同階層のファイルがあれば、それをlayoutとして適用する
- 上記のが無い場合、同階層にlayout.tplがあれば、それを適用する
- 上記のが無い場合、上の階層のlayout.tplを適用する(無い場合は更に上の階層を辿る)
- 最後まで無かった場合は何も適用しない
- layoutファイルの{$layout.body}部分に本体を展開する。
しかしこういう規則ってEthnaの設計っぽくない気が…。まあ構わず続ける。
対応部分のソースはこんな感じ?(APPID_ViewClass.php)
function forward() { $renderer =& $this->_getRenderer(); $this->_setDefault($renderer); $layout = NULL; $layout_vars = array(); if (property_exists($this, 'layout')) { $layout = $this->layout; } else { $layout_path = $this->forward_path; if ($renderer->templateExists('layout/' . $layout_path)) { $layout = $layout_path; } else { $layout_path = ereg_replace('[^/]*\.tpl$', '', $layout_path); while($layout_path != '') { if ($renderer->templateExists('layout/' . $layout_path . 'layout.tpl')) { $layout = $layout_path . 'layout.tpl'; break; } $layout_path = ereg_replace('[^/]+\/$', '', $layout_path); } if ($renderer->templateExists('layout/layout.tpl')) { $layout = 'layout.tpl'; } } } if (!is_null($layout)) { ob_start(); $renderer->perform($this->forward_path); $layout_vars['body'] = ob_get_contents(); ob_end_clean(); $renderer->setProp('layout', $layout_vars); $renderer->perform('layout/' . $layout); } else { $renderer->perform($this->forward_path); } }
※07/02/27 15:59修正
これで自動でlayoutが適用されて表示されるようにはなったものの、部分的な動的レイアウト(例えば共通メニューだけど、現在位置によってメニューの内容が変わるとか)が難しい気がする。Railsとかどうしてるんだろう。