render()でpartialを指定したときに、"Fatal error xxxx に tpl.php, js.tpl, または委譲されたテンプレートがみつかりません。 in ... AkActionView.php"と表示された場合
先日、Helper中からさらにテンプレートを呼び出したいとき - ぐらめぬ・ぜぷつぇんのはてダで、"partial"キーを$optionに指定すれば良い、とまとめました。ところが、$optionには"controller"というキーを指定するパターンもあります。
えーっと、タイトルのエラーなんですが、コントローラを"controller"で指定しちゃうと発生してました。(Ver 0.8?)
<?php echo $controller->render(array('controller' => 'common', 'partial' => 'leftcolumn')) ?> → "Fatal error xxxx に tpl.php, js.tpl, または委譲されたテンプレートがみつかりません。 in ... AkActionView.php" <?php echo $controller->render(array('partial' => 'common/leftcolumn')) ?> → Okay.
「'controller'でコントローラ指定してるのに何で!?」という感じですよね?またそれもあって、最初、このエラーメッセージとその原因が結びつかず結構悩みました。ダメ元でやってみたら直ったのでc⌒っ*゚ー゚)っφ メモメモ...。
あるcontrollerのHelperを他のcontrollerのリクエスト処理中でも使えるよう共有したい場合
後述しますが、Controllerクラスの $helpers や $app_helpers を弄っていないデフォルトのControllerの場合、Akelos自体が提供している全ヘルパー+app/helpers/(コントローラ名)_helper.php のみそのcontrollerが処理するリクエストで使用可能です。
逆に言うと、controller-Aが処理しているリクエスト中では、controller-BのHelperを呼び出すことは(そのままでは)できません。
よくあるパターン(というか自分が嵌ったパターン)としては、共通的なpartialやHelper, デフォルトページ用のcontrollerとかを "common" コントローラとしてまとめて、そのヘルパを他のcontrollerのview中から呼ぶ・・・などがあります。
$common_helper->hogehgoe(); → Fatal error: Call to a member function on a non-object in ... app/views/other_controller/compiled/hoge.tpl.php
みたいな。
対処法としては、こうしたcommonなcontrollerのhelperを他のcontrollerで遍く使いたい場合は、ApplicationControllerで $app_helpers に共用したいcontroller名を指定します。
app/application_controller.php
<?php class ApplicationController extends AkActionController { var $app_helpers = "common"; // 面倒くさがり屋は "all" を指定。 ...
面倒くさいときは"all"を指定することで、もう全部のcontrollerのhelperを、全部のcontroller中で見境無く使えるようになります。
続きを読む処理中にエラーが発生した場合、redirectではなくて、symfonyのようにforwardしたい時
Akelosのcontrollerにはforward()相当のメソッドがありません。あえて似ているような機能を実現できるのが、
- renderAction() : 指定されたアクションを実行
- renderWithLayout() : レイアウトを指定してViewを実行
- renderWithoutLayout() : レイアウト無しでViewを実行
などになります。
AkelosではActionメソッドの戻り値は使われていない*1ので、Akelosでテンプレートを切り替えたい場合は手動でrender()シリーズのメソッドを呼ぶことになります。
で、render()シリーズのメソッドでのテンプレートやPartialの指定方法って、結構混沌としてます。AkActionController#render()メソッドを参照してみてください。ややこしいです。
ので、今回は限定的に
- renderWithLayout()で404相当エラー用のレイアウトを指定して実行
- app/views/common/error.tpl は空のダミーファイル
として話を進めます。
いきなり解答です。
適当なコントローラ中:
<?php class FooController extends ApplicationController { function bar() { // ... $this->flash_now['notice'] = "指定されたデータが見つかりません。"; $this->renderWithLayout(AK_VIEWS_DIR . '/common/error.tpl', 404, 'error'); return; }
- 第一引数:テンプレートファイルフルパス:これが一番確実です。今回はレイアウトの方でflashでメッセージを表示させていますので、テンプレートファイルの方は中身空っぽの単なるダミーファイルです。
- 第二引数:HTTPステータスコード
- 第三引数:使用するレイアウト。今回は、デフォルトのpage.tplをコピーして app/views/layouts/error.tpl としました。
また、page.tplをコピーしていますので AkActionController::$flashが使えます。ただし通常の$flashですと、次のリクエストにならないとView側で取れません。リクエストの遷移が無い今回のようなケースでは、$flash_nowの方を使います。
これで一旦、renderしてしまえばあとはそのままreturnしちゃいます。
*1:AkActionController#process(), performActionWithoutFilters(), performActionWithFilters(), performAction()のコードを参照
ADODBのコネクションを直に触りたいとき
ようやくこの話題に到達できた・・・。そもそも、ADODBのコネクションを直に触り始めたために、他のcontroller間でpartialを共有したり、エラー時にforwardじみた操作をさせたり、という感じでこれまで調査をしてきた訳です。
で、長い下準備の割には簡単です。最低一つは適当なモデルをgenerateしておきます。あとは、モデルをnewして、インスタンスのgetConnection()メソッドを呼びます。
Ak::import('Product'); $Product =& new Product(); $db =& $Product->getConnection();
これでokay。あとは、$dbを使ってADODBでプログラミングすればよい。