Zend Frameworkを使って、MVCフレームワークで開発しているとき、Zend_Filter_Inputを使ってフォームで入力された値のフィルタリングを行う処理を記述した時のメモ。 以下のようなフォームで、入力された値についてチェックをかける場合。```

登録する情報を入力

ユーザー名: パスワード: パスワードの確認:

ユーザ名は半角英数字、5文字以上10文字以下
パスワードは半角英数字、5文字以上10文字以下

```普通にZend\_Filter\_Inputを使ってフィルタリング処理をアクションメソッドに書くと以下のようなになります。```
class RegisterController extends Zend\_Controller\_Action
{
    ....
    public function confirmAction() {
        $validate = array(
            'id' => array(
                'Alnum'
                array('StringLength', 5, 10),
                'presence' => 'required',
                'message' => array(
                    0 => ... // Alnumに対するエラーメッセージ
                    1 => ... // StringLengthに対するエラーメッセージ
                )
            ),
            'password1' => array(
                'Alnum'
                array('StringLength', 5, 10),
                'presence' => 'required',
                'message' => array(
                    0 => ... // Alnumに対するエラーメッセージ
                    1 => ... // StringLengthに対するエラーメッセージ
                )
            ),
            'password2' => array(
                'Alnum'
                array('StringLength', 5, 10),
                'presence' => 'required',
                'message' => array(
                    0 => ... // Alnumに対するエラーメッセージ
                    1 => ... // StringLengthに対するエラーメッセージ
                )
            ),
            'password' => array(
                'StringEquals', // 独自のバリデータ
                'fields' => array('password1', 'password2'),
                'messages' => ... // エラーメッセージ
            )
        );
        $data = $\_POST;
        $filter = new Zend\_Filter\_Input(null, $validate, $data);
        if(!$filter->isValid()) {
            // エラー処理
        }
        
        // DBなどに登録
    }
)

```このように書くとアクションメソッドが大きくなってしまってちょっといやな感じだったのでやり方を変えてみました。 以前参加した設計勉強会での[twk](http://nonn-et-twk.net/twk/node/256)さんの発表や、Ethnaのフィルター処理(もとはStruts?)を参考にしています。 まず、各コントローラーで共通の処理を基底のコントローラにまとめます。 そして各アクションメソッドはサブクラスで実装することにします。 基底のコントローラがBaseControllerで、アクションメソッドを記述するサブクラスをRegisterControllerとします。```
BaseController
RegisterController extends BaseController

```BaseControllerではフィルターの初期化と入力されたデータのセットを、それぞれinit()とpreDispatch()関数で行います。```
require\_oncd 'Zend/Controller/Action.php';

class BaseController extends Zend\_Controller\_Action
{
    ...
    
    /\*\*
     \* フォームから入力されたデータ
     \*
     \* @var array
     \*/
    protected $\_form = null;

    /\*\*
     \* フィルタークラス(Zend\_Filter\_Inputを継承したクラス)
     \* 
     \* @var Wads\_Filter\_Input
     \*/
    protected $\_input\_filter = null;

    /\*\*
     \* 適用するフィルターのルール(サブクラスで記述する)
     \* 
     \* @var array
     \*/
    protected $\_filter\_rules = array();

    /\*\*
     \* 適用するバリデータのルール(サブクラスで記述する)
     \* 
     \* @var array
     \*/
    protected $\_validator\_rules = array();
    ...
    
    public function init() {
        // コントローラの初期化処理を書く
        ...
        // フィルターの初期化
        $action = $this->getRequest()->getActionName();
        if(!empty($this->\_filter\_rules\[$action\]) || !empty($this->\_validator\_rules\[$action\])) {
            $this->\_input\_filter = new Wads\_Filter\_Input(
                                       $this->\_filter\_rules\[$action\],
                                       $this->\_validator\_rules\[$action\]
                                   );
    }
    
    public function preDispatch() {
        // アクションメソッドを実行する前の前処理を書く
        ...
        // フィルターにデータをセット
        if($this->\_input\_filter !== null) {
            $this->\_form = $\_POST;
            $this->\_input\_filter->setData($this->\_form);
        }
        ...
    }
    
}

```各サブクラスではフィルタリングするルールを、$\_filter\_rules、$\_validator\_rulesのプロパティーに記述して、各アクションでフィルタリングの処理を実行します。 もしエラーがあった場合は、エラー処理を行います。```
require\_oncd 'BaseController.php';

class RegisterController extends BaseController
{
    ...

    protected $\_validator\_rules = array(
        'confirm' => array(  // confirmActionの設定
            'id' => array(
                ... // 上の例と同じ
            ),
            'password1' => array(
                ...
            ),
            'password2' => array(
                ...
            ),
            'password' => array(
                ...
            )
        ) // confirmActionに対する設定の終わり
    );
    ...
    
    public function confirmAction() {
        ...
        
        // フィルタリングの処理
        if(!$this->\_input\_filter->isValid()) {
            // エラーがあった
            $messages = $this->\_input\_filter->getMessages();
            ...
            // エラー処理
        }
        
        // 成功したときの処理
    }
    
    ...
}

```フィルタークラスはZend\_Filter\_Inputを継承しています。 クラス内でいつも設定するオプションや、エラーメッセージ取得の簡略化など、独自の処理を記述しています。```
require\_oncd 'Zend/Filter/Input.php';

class Wads\_Filter\_Input extends Zend\_Filter\_Input
{
    private $\_options = array(
        'breakChainOnFailure' => true,
        'inputNamespace'      => 'Wads\_Validator'
    );
    
    public function \_\_construct($filterRules, $validatorRules, array $data = null, array $options = null) {
        if($options !== null) {
            $this->\_options = array\_merge($this->\_options, $options);
        }
        parent::\_\_construct($filterRules, $validatorRules, $data, $this->\_options);
    }
    
    /\*\*
     \* エラーメッセージを取得する処理
     \*/
    public function getErrorMessage($messages = null) {
        if($messages === null) {
            $messages = $this->getMessages();
        }
        
        $err\_msg = array();
        foreach($messages as $name=>$msg) {
            unset($this->\_form\[$name\]);
            $err\_msg\[\] = current($msg);
        }
        
        return $err\_msg;
    }
}

```こんな感じで作ってみましたが、ほかの人はどのようになっているのでしょうか。 **2008.12.18追記** doitさんにご指摘いただいた部分を修正しました。