新規ドキュメントはこちら(http://ozaki.kyoichi.jp/content/blogsection/4/26/)に掲載しております。

バリデーション機能(Validator)

mojavi 3には入力値を検証するための機能が用意されています。これで毎回同じような処理を書く手間から逃れられます。また、mojavi 3では、mojavi 2のときより、検証の設定がかなり楽になり、設定ファイルを用意するだけで入力値の検証が可能になっています。今回は、認証機構で説明したログインアクションに、実際にユーザIDとパスワードの入力フォームを取り付け、バリデーション(Validation)の実装を行ってみたいと思います。

フォームの作成には、HTML_QuickFormを利用します。LoginActionでは、入力フォームの画面を表示する処理として、ユーザIDの入力欄、パスワードの入力欄、サブミット(Submit)ボタン、モジュール名のhiddenフィールド、アクション名のhiddenフィールドを作成します。MyProject/webapp/modules/Default/actions/LoginAction.class.phpの中に、以下のようなメソッドを追加します

...

     /*
     * HTML_QuickForm によるフォームの生成
     * @access private
     */
    private function _buildForm() {

      $context    =& $this->getContext();

      $moduleName = $context->getModuleName();
      $actionName = 'LoginCommit';
    
       // フォームの初期化
      if (!isset($this->form)) {
      		$this->form = new HTML_QuickForm($actionName,
			       						'POST',
			       						'index.php',
			       						'_self', null);
      }

     	$this->form->addElement('hidden', 'module', $moduleName);
   		$this->form->addElement('hidden', 'action', $actionName);
     	$this->form->addElement('text', 'loginName');
   		$this->form->addElement('password', 'password');
		$this->form->addElement('submit','submit','ログイン');
		
       return TRUE;
		
    }
... 

フォームを作成する際に、actionをLoginCommitに指定します。これが、実際にPOSTされたデータを検証するアクションクラスになります。また、ここでは$formというクラス変数を使っていますので、LoginAction.class.php内で、クラス変数を定義しておいてください。方法は以下のようになります

...
class LoginAction extends MyAction
{

	static $form;
...

アクションが呼び出されたときに、_buildForm()メソッドが呼び出されるようにします。アクションが呼び出されたときは、excute()が実行される前に、validate()がまずよびだされるので、validate()メソッドをオーバーライドします。

...
     public function validate()
    {

    	return $this->_buildForm();
    }
...

validate()がTRUEを返す場合には、excute()が実行されます。この場合、_buildForm()は必ずTRUEを返すので、execute()はかならず実行されます。本来、エラーが起きた場合はhandleError()メソッドが呼び出されます。このメソッドは、View::ERRORを返すので、万が一エラーが発生した場合のときを考え、このメソッドもオーバーライドして、View::INPUT (入力フォーム)を返すようにします。LoginAction.class.phpの中に、次のようにメソッドをオーバーライドします

...  
  public function handleError ()
    {

        return View::INPUT;

    }
	...

認証機構の説明の章でexecute()の中で無条件に認証を付与してフォワードする設定を行ったので、そこも入力画面へ遷移するように修正します

...  
  public function execute ()
    {

        $context    =& $this->getContext();
        $request    =& $context->getRequest();
        $request->setAttribute('form', $this->form);

        return View::INPUT;
    }
...

Viewクラスを修正して、Smarty用にフォームを設定します。この辺りは、QuickFormとSmartyの章で説明した内容の通りですね。また、バリデーションによるエラーが発生した場合に、Smarty用にエラーにアクセスできるオブジェクトを作成します。MyProject/webapp/modules/Default/views/LoginInputView.class.phpは以下のようになります

class LoginInputView extends MySmartyQuickFormView
{

    public function execute ()
    {
    	$context =& $this->getContext();
    	$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());
    	$this->setTemplate('LoginInput.tpl');

    }

}

テンプレートにフォームが表示されるように修正します。MyProject/webapp/modules/Default/templates/LoginInput.tplを以下のように編集します

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Login画面</title>
<link href="mystyle.css" rel="stylesheet" type="text/css" />
</head>
<body>
{foreach from=$errors item=error}
{$error}<br />
{/foreach}
<form {$form.attributes}>
{$form.hidden}
ユーザID:{$form.loginName.html}<br />
パスワード:{$form.password.html}<br />
{$form.submit.html}<br />
</form>
</body>
</html>

ここまでが、入力フォーム側です。先にでたように、これをPOSTするアクションはLoginCommitです。従って、LoginCommitActionも用意します。このアクションは、入力値の検証が問題なければ呼び出され、ログイン処理を行うアクションになります。ただし、今回はバリデーション(Validation)のHOWTOなので、その処理は除きます。バリデーション(Validation)の説明を簡潔にするため、今回LoginCommitアクションでは、単に認証状態を変更して、HelloWorldモジュールのHelloWorldDBアクションにフォワードするようにします。また、エラーが起きた場合は、入力画面に戻るように設定します。handleErrorをオーバーライドします。内容は以下のようになります

<?php
class LoginCommitAction extends MyAction
{
    public function execute ()
    {

        $context    =& $this->getContext();
        $controller =& $context->getController();
        $user       =& $context->getUser();
        
        $user->setAuthenticated(TRUE);

        $controller->forward('HelloWorld', 'HelloWorldDB');

    }

    public function handleError ()
    {
        $context    =& $this->getContext();
        $controller =& $context->getController();
        $controller->forward(MO_LOGIN_MODULE, MO_LOGIN_ACTION);
    }
    
}
?>

次に、肝となるバリデーション(Validation)用の設定ファイルを用意します。バリデーション(Validation)は、バリデートしたいアクションの名前で、モジュールディレクトリ/validate/アクション名.iniで作成します。ここでは、LoginCommitActionに、送られてくるデータを検証したいので設定ファイルは、MyProject/webapp/modules/Default/validate/LoginCommit.iniになります。内容は以下のようになります

[methods]

    get  = "loginName, password"
    post = "loginName, password"

[names]

    loginName.required     = "Yes"
    loginName.required_msg = "ユーザIDを入力してください"
    loginName.validators   = "UsernameValidator1, UsernameValidator2"

    password.required     = "Yes"
    password.required_msg = "パスワードを入力してください"
    password.validators   = "PasswordValidator"

[UsernameValidator1]

    class = "StringValidator"

    param.min       = "3"
    param.min_error = "ユーザIDは3文字以上です"
    param.max       = "25"
    param.max_error = "ユーザIDは25文字以内です"

[UsernameValidator2]

    class = "RegexValidator"

    param.match       = "Yes"
    param.match_error = "ユーザIDを半角英数字で入力してください"
    param.pattern     = "/^[a-z][a-z0-9\-\._]+[a-z0-9]$/i"

[PasswordValidator]

    class = "StringValidator"

    param.min       = "8"
    param.min_error = "パスワードは8文字以上です"
    param.max       = "50"
    param.max_error = "パスワードは50文字以内です"

ファイルの説明をしますと、まず先頭に[methods]があります。[methods]では、どのFORMメソッドの場合(GETかPOST)、どのフォームエレメントを検証するのか定義します。フォームのinputタグのname属性を指定します。LoginCommitActionはPOSTされる前提ですが、GETによりリクエストされる可能性もあるので、ここは万全を期して、両メソッドにおいてもバリデーション(Validation)を行うようにします。[names]では、[methods]で定義したフォームエレメントに対して、どのような検証が必要なのか定義します。利用できるバリデーター(Validator)はMyProject/mojavi/validatorの中にあります。現在(2005/02/04)のmojavi 3パッケージに含まれるバリデーター(Validator)はDate、Email、Number、Regex、Stringです。まず、loginNameとpasswordともに、必須項目なので、required = "Yes" を設定します。また、required_msgは、検証が失敗した場合にセットされるエラー文言です。validatorsには、それ以外に、検証が必要なルールを追記できます。ここでは自由に検証ルールの名前をつけることができますが、それに対する設定を明記する必要があります。たとえばログインIDについては、UsernameValidator1とUsernameValidator2が指定されています。ここで、用意されているValidatorクラスを使うことができるのです。StringValidatorでは文字の最小、最長文字数の確認。RegexValidatorでは、正規表現による文字列の検証がおこなえます。

このファイルを設置すれば、検証の設定は完了です。ログインURLにアクセスしてみましょう。

http://localhost/MyProject/index.php?module=Default&action=Login

入力画面が表示されます。ここで何も入力せずにサブミットボタンを押してみてください。設定ファイルで設定したエラーメッセージが表示されると思います。いろいろ、条件が不一致するような入力を行ってサブミットを行ってみてください。同様に検証に失敗した場合のエラー文言が表示されます。最後に、全ての条件にあるような入力を行ってサブミットを行ってください。HelloWorldモジュールのHelloWorldDBアクションが表示されます。

Validatorの簡単な使い方は以上です。自分でValidatorを作って適用する場合などは後ほど説明します