それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

symfonyにはValidation機能がついている

2009-02-02追記:この記述は古いですよ。symfony1.2ではDjango流に$form.isvalid()です。

Validation機能がついていて、validat+$Action名() の関数を定義するか、module/APP/validate/$Action名.ymlに条件を書けば、isValidを調べてくれるらしい。


でもadmin-generator を使っているときのvalidationについてはわからない。マニュアルのadminには載ってなかったなぁ。DBの定義(schena.yml)から自動的にValidationしてくれるとすごく助かるのだけけれど。どうしようかな。

admin使わないとかgenerat-crudしないなら、Symfonyの魅力半減なんだよなぁ。他のフレームワークでイイじゃんってなる。

admin-generatorの場合

admin-generatorの場合、ACTIONは次の4つが定義されている。CRUD

list, edit, create, delete

ここから想像するとeditフォームにvalidationを追加したいならば、

module/APP/validate/edit.yml

を作ればO.K. だと予想してみる、。

ファイル作った

ファイル作るだけで読み込んだ成功。でも空ファイルなんで、Validation条件が無くエラー落ち。
やっぱよくわからない。

manualにあるYAMLをコピペしてみた

fields:
  name:
    required:
      msg: "nameは必ず入力してください。"

で、実行してみた。お、なんか行けそう?表示は出来る。送信してみた。やっぱダメか。。。

There are some errors that prevent the form to validate

ってエラー。form を validateするのに邪魔が入りました。エラーの所為です。と。

どうすればイイのだろう。とりあえず、手詰まり。

Manualに戻ってみる

The validation process doesn't stop when a validator fails. Symfony tests all the validators and declares the validation failed if at least one of them fails. And even if some of the rules of the validation file fail, symfony will still look for a validateXXX() method and execute it. So the two validation techniques are complementary. The advantage is that, in a form with multiple failures, all the error messages are shown.

validation processはvalidatorがfailしても止まらず、symfonyは出来るだけ多くのvalidatorと、declareの条件をテストしようとする。条件を記述したファイルでValidationが失敗だったとしても、さらにvalidateXXX()メソッドの実行を試みる。それがsymfonyのvalidation機構。なのでfileに記述する手法とメソッドを作成する手法は両立するし、競合しない。この利点は、不一致条件のエラーメッセージをまとめて一度にユーザーに伝えることが出来る点だ。

Validation files are located in the module validate/ directory, and named by the action they must validate. For example, Listing 10-19 must be stored in a file called validate/send.yml.

Validation ファイルは、modules/APPNAME/config/validate ディレクトリに、Action名を使った名前で作成する。10-19の例だと、Action名がsendだから validate/send.ymlとした

Redisplaying the Form / フォームの再描画

By default, symfony looks for a handleErrorSend() method in the action class whenever the validation process fails, or displays the sendError.php template if the method doesn't exist.
Validationが失敗したら、デフォルトでは、handleErrorXXXX() メソッドを実行する。handleErrorXXXX() メソッドはaction.class.phpに記述する。メソッドがないと、XXXError.php という名前のsymfony Templateファイルを探して表示する。

The usual way to inform the user of a failed validation is to display the form again with an error message. To that purpose, you need to override the handleErrorSend() method and end it with a redirection to the action that displays the form (in the example, module/index), as shown in Listing 10-20.
ユーザへValidationが失敗したことを通知するのに、ふつうは、フォームを再描画し、エラーメッセージを添えてやる。コレを実現するには、handleErrorXXX()メソッドを使う。メソッド中でRedirect処理を行う。どのようなRedirect処理をするかは、以下の例を参考に

Listing 10-20 - Displaying the Form Again, in modules/contact/actions/actions.class.php

class ContactActions extends sfActions
{
  public function executeIndex()
  {
    // Display the form
  }
 
  public function handleErrorSend()
  {
    $this->forward('contact', 'index');
  }
 
  public function executeSend()
  {
    // Handle the form submission
  }
}

と、書いてある。xxx/indexにリクエストを転送しても仕方がない。
でもどうすれば・・・

さらに読み進めてみる

If you choose to use the same action to display the form and handle the form submission, then the handleErrorSend() method can simply return sfView::SUCCESS to redisplay the form from sendSuccess.php, as shown in Listing 10-21.

フォームとフォームの送信に同じActionを再利用してフォームの描画を行いたいとき、handleErrorXXX()メソッドがsfView::SUCCSESS 戻り値として返せば、フォームの再描画をxxxSuccsess.phpのテンプレート内で処理が可能になる。

Listing 10-21 - A Single Action to Display and Handle the Form, in modules/contact/actions/actions.class.php

一つのACITONでフォームの作業を行う例。

class ContactActions extends sfActions
{
  public function executeSend()
  {
    if ($this->getRequest()->getMethod() != sfRequest::POST)
    {
      // Prepare data for the template
 
      // Display the form
      return sfView::SUCCESS;
    }
    else
    {
      // Handle the form submission
      ...
      $this->redirect('mymodule/anotheraction');
    }
  }
  public function handleErrorSend()
  {
    // Prepare data for the template
 
    // Display the form
    return sfView::SUCCESS;
  }
}

The logic necessary to prepare the data can be refactored into a protected method of the action class, to avoid repeating it in the executeSend() and handleErrorSend() methods.

この手法使うときは、データはメソッド中で保護され書き換わらない事が必要だ。handleErrorSend()やexecuteSend()で繰り返しを避けるためだ

With this new configuration, when the user types an invalid name, the form is displayed again, but the entered data is lost and no error message explains the reason of the failure. To address the last issue, you must modify the template that displays the form, to insert error messages close to the faulty field.

この手法をでは、ユーザーが間違った名前をタイプしたとき、フォームは再描画されるが、エラーメッセージが何も表示されないままだ。ユーザーにエラーの原因が伝わらない。この問題に対処するために、テンプレートを書き換えて、フォームがエラーメッセージを表示できるようにしてやる。