nazolabo

フリーランスのWebエンジニアが近況や思ったことを発信しています。

Ethnaの複合ビュー化を考える(2)

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とかどうしてるんだろう。