技術日記ZendFramework
Zend_Frameworkにおけるバリデーションコードの置き場所Edit

Zend_Frameworkにおけるバリデーションコードの置き場所ってどうよ? ってのをいろいろ試行錯誤した結果、今のところこうしてるよ、というのをまとめてみる。

DBアクセスレイヤーは基本的にZendDbTableを使っている。テーブルにマッピングできないものも、データ操作レイヤーに関するものはapplication/models/以下に置いて、ZendDbTableと同じようなインターフェースを持たせて使う。で、共通化できるバリデータはこのモデルクラスにまとめて持たせる。

[sourcecode language="php"]
class ModelBase extends ZendDbTable
{
  protected $validators = array();
  public function getValidators()
  {
    return $this->validators;
  }
  public function getValiator($name)
  {
    if (!isset($this->validators[$name]) {
      $this->validator[$name] = new ZendValidate();
    }
    return $this->validator[$name];
  }
}
[/sourcecode]
みたいなベースクラスを作っておいて、 各実装クラスでは、
[sourcecode language="php"]
class FooTable extends ModelBase
{
  public funciton init()
  {
    $this->getValidtor('foo')
    ->addValidtor(new ZendValidateStringLength(5, 15));
  }
}
[/sourcecode]
みたいな感じでinit()内でバリデータをセットしておく。そうすると、ZendDbTableRowとかでこのバリデータを使いたい場合は、
[sourcecode language="php"]
class FooTableRow extends ZendDbTableRow
{
  public function isValid()
  {
    $result = true;
    foreach ($this->getTable()->getValidators() as $name => $validator) {
      $result = $validator->isValid($this->$name) && $result;
    }
    return $result;
  }
}
[/sourcecode]
なんて感じでバリデーションを書ける(上の例は共通バリデータをぶん回すだけでOKな場合の話ね)。また、このFooTableに対してのCRUDを行うようなZendFormでは、
[sourcecode language="php"]
class FormFoo extends Zend_Form
{
  public function init()
  {
    $fooTable= new FooTable();
    $foo = $this->createElement('input', 'foo');
    $foo
    ->addValidator($fooTable->getValidator('foo'))
    ->addValidator(new CustomValidatorForForm());
    $this->addElement($foo);
  } 
}
[/sourcecode]
なんて感じでFooTableの該当パラメータ用のバリデータを使うことができるし、それにフォーム専用の追加パラメータを追加することもできる。

アクションコントローラのパラメータの場合は、

[sourcecode language="php"]
class FooController extends ZendControllerAction
{
  public function fooAction()
  {
    $foo = $this->_getParam('foo');
    $fooTable = new FooTable();
    $validator = $fooTable->getValidator('foo');
    if (!$validator->isValid($foo)) {
      // IIIINNNNVALIIIIIIIDDDDDDDDDDD!!!!!!!!!!!!!!!!
    }
  }
}
[/sourcecode]
なんて感じで、使いたい要素のバリデータだけ引っ張り出して使える。

ということで、バリデータはモデルクラスにパラメータ名ごとに共通(使い回せる)部分を突っ込んでおいて、シチュエーションごとにそれを取り出しつつ、シチュエーションに特化したバリデータはその場でaddValidator()して使う、いう置き方が一番きれいなんじゃないかと思うのだが、どうだろう。

フィルターに関しては、まとめて同じ処理をしたいという要求がそれほど大きくない、というか同じパラメータでも入力シチュエーションによってどういうフィルターをかけたいかが変わるんで、必要な場所(アクションメソッドとかフォーム要素とか)にそれぞれ書くのが無難な気がする。フィルタークラス自体はアプリケーションに特化したものをapplication/filters以下に用意しておいた方が楽だけど。

と、久しぶりにZendFrameworkで新しいアプリを書こうと思い、どうせならZendFrameworkのコンポーネントを使い倒した書き方にしてみるかといろいろ試行錯誤した結果、こんな感じになったという話でした。

Windows Server 2008でManaged DirectXを使ったASP.NET MVC3が動かないという、ググってもレアケース過ぎて解決策が見つからないシチュエーションからの現実逃避の一環でもある。単にDirect 3Dのベクトル演算関数をサーバーサイドでも使いたいだけなんだけどなー。なんで依存関係が解決できないんだろう。

Published At2011-12-02 20:16Updated At2019-12-30 15:06