ぐらめぬ・ぜぷつぇんのはてダ(2007 to 2011)

2007年~2011年ごろまで はてなダイアリー に書いてた記事を引っ越してきました。

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でプログラミングすればよい。