新規ドキュメントはこちら(http://ozaki.kyoichi.jp/content/blogsection/4/26/)に掲載しております。
フォームの初期化を透過的にする
最近、mojaviがモハビと読まれることが判明しました。これは、mojaviの開発者であるsean kerrさんからの直々の言葉なので、間違いはないです。
さて、今回は今まで手動で組み込んできたHTML_QuickFormを親クラスで処理するようにして、実際にモジュールを作成するときには、ActionやViewでHTML_QuickFormオブジェクトを意識しなくていいようにしたいと思います(コード生成の自動化、実際に記述するコード量の軽減を行います)。具体的にどういった方法で行うかというと、親のActionでHTML_QuickFormを初期化して、リクエスト変数に格納します。また、親のViewでは、リクエスト変数からHTML_QuickFormオブジェクトを取り出し、Smarty変数にセットします。フォームオブジェクトは、別ファイルでクラスファイルとしてAction毎に用意することにします。これを行うためには、命名規則をきめる必要がありますが、今回は、各モジュールにおいて、モジュールディレクトリ配下に、forms というディレクトリを作成して、その下にアクション名Form.class.phpという規則にしたがって、フォームオブジェクトを作成することにします。言葉の説明では分かりづらいと思いますので、下記のサンプルコードを参考にしてみてください
フォームを使うアクションの場合用に、新たにMyFormActionを作成します。MyProject/webapp/lib/MyFormAction.class.phpというファイルで、内容は以下のようになります
<?php
ini_set("display_errors", 0);
ini_set("error_reporting", false);
require_once('/usr/local/share/pear/HTML/QuickForm.php');
ini_restore("error_reporting");
ini_restore("display_errors");
abstract Class MyFormAction extends Action
{
static
$form = null;
public function initialize ($context)
{
parent::initialize ($context);
$module =& $context->getModuleName();
$action =& $context->getActionName();
$formObjectName = $action.'Form';
$formObjectDirectory = MO_MODULE_DIR . '/' . $module . '/forms';
$formObjectFile = $formObjectDirectory. '/' . $formObjectName . '.class.php';
if (is_readable($formObjectFile)) {
include ($formObjectFile);
$form = new $formObjectName;
$this->form = $form->execute();
}
$request =& $context->getRequest();
$request->setAttribute('form', $this->form);
return true;
}
}
?>
新規に作成したMyFormActionをautoload.iniに追加します
MyFormAction = "%MO_WEBAPP_DIR%/lib/MyFormAction.class.php"
フォームを使うビューの場合用に、新たにMySmaryQuickFormViewを修正します。内容は以下のようになります
<?php
ini_set("display_errors", 0);
ini_set("error_reporting", false);
require_once('/usr/local/share/pear/HTML/QuickForm/Renderer/ArraySmarty.php');
ini_restore("error_reporting");
ini_restore("display_errors");
abstract class MySmartyQuickFormView extends MySmartyView
{
public function initialize ($context)
{
parent::initialize($context);
$request =& $context->getRequest();
if ($request->hasErrors()) {
$errors =& $request->getErrors();
$this->setAttributeByRef('errors', $errors);
}
$form =& $request->getAttribute('form');
$quickformSmarty = new HTML_QuickForm_Renderer_ArraySmarty($this->getEngine());
$form->accept($quickformSmarty);
$this->setAttribute('form', $quickformSmarty->toArray());
return true;
}
}
?>
前回修正した、LoginActionからフォームの初期化部分を抜き出し、MyFormActionで自動的に読み込まれるようにフォームオブジェクトとして作り直します。命名規則にしたがって、MyProject/webapp/module/Default/forms/LoginForm.class.phpというファイルを作成します。内容は以下のようになります
<?php
class LoginForm
{
function execute()
{
$form = new HTML_QuickForm(get_class ($this),
'POST',
'index.php',
'_self', null);
$form->addElement('hidden', 'module', 'Default');
$form->addElement('hidden', 'action', 'LoginCommit');
$form->addElement('text', 'loginName');
$form->addElement('password', 'password');
$form->addElement('submit','submit', 'ログイン');
return $form;
}
}
?>
ここで重要なのは、クラス名をアクションFormとすること。それとファイル名はアクションForm.class.phpとしてモジュールディレクトリのformsディレクトリの下に作成すること。最後に、必ずHTML_QuickFormオブジェクトを返すexecute()メソッドを実装すること。次に、LoginActionを修正します。前回 validate で実装して、_buildform() を呼び出していた部分を削除します。新しいLoginActionは以下のようになります
<?php
class LoginAction extends MyFormAction
{
public function execute ()
{
return View::INPUT;
}
public function handleError ()
{
return View::INPUT;
}
}
?>
かなりスッキリしたでしょ?注意する点は、MyActionではなく、MyFormActionを継承するように変更したところです。Viewも修正します。Viewの親クラスは新規に作成していないので、継承するクラスは変更しません。その代わり、親クラスで実装するようにしたフォームオブジェクトの取り出しや、Smartyへの変数セットなどの処理は除きます。修正後は下記のようになります(MyProject/webapp/modules/Default/views/LoginInputView.class.php)
<?php
class LoginInputView extends MySmartyQuickFormView
{
public function execute ()
{
$this->setTemplate('LoginInput.tpl');
}
}
?>
これでViewもかなりスッキリしたでしょ?ほとんど何も意識しなくてよい。冗長する処理はまとめる事ができました。最後に、ログイン処理が通ったときに表示されるHelloWorldモジュールのHelloWorldDBアクションのビューを修正します。MySmartyQuickFormViewはMyFormActionの初期化処理が必須になるので、このビューは継承できません。ここは、とりあえずMySmartyViewを継承するように修正します
class HelloWorldDBSuccessView extends MySmartyView
{
....
最後に、Loginのアクションにアクセスして確認を行います。今までと同じように表示され、動作すれば問題ありません
http://192.168.0.15/MyProject/index.php?module=Default&action=Login
まとめると、今回のポイントは:
- formの初期化はモジュールディレクトリ/forms/の中で行う(これをFormクラスと呼ぶ)
- formを使う場合はMyFormActionを継承する
- formを使う場合はMySmartyQuickFormViewを継承する
- Formクラスは必ずHTML_QuickFormオブジェクトを返すexecute()メソッドを実装する(ここは実際にプロジェクト開発ではActionFormとかいうAbstractクラスを使って強制されるべきだね)