Caution: You are browsing the legacy symfony 1.x part of this website.

条件つきバリデーターを実装するには?

1.2
Language

古典的なログインフォームは2つのフィールド: ユーザー名とパスワードで構成されます。

バリデーションのルールはとても直感的です:

  • それぞれのフィールドを必須にしたい
  • パスワードの正しさをチェックしたい

ログインフォームの最初の実装です:

class loginForm extends sfForm
{
  public function configure()
  {
    $this->setWidgets(array(
      'username'  => new sfWidgetFormInput(),
      'password'  => new sfWidgetFormInputPassword(),
    ));
 
    $this->setValidators(array(
      'username' => new sfValidatorString(array('required' => true)),
      'password' => new sfValidatorString(array('required' => true)),
    ));
 
    $this->widgetSchema->setNameFormat('login[%s]');
  }
}

このフォームによってユーザー名とパスワードフィールドの要件が強制されますがパスワードの正しさはチェックされません。

ログインフォームの最初の実装

ユーザー名の値へのアクセス権限もある場合のみパスワードはバリデート可能です。 しかしおわかりの通り、フィールドに添付されたバリデーターはフォームの他の値にアクセスする権限がありません。

バリデーターが別の投稿された値に依存するとき、ポストバリデーターを作ることが必要です. ポストバリデーターは他のすべてのバリデーターの後で実行されクリーンナップされた値の全体の配列が渡されます。

パスワードをチェックするために、投稿されたパスワードがユーザーと等しいことを確認するために シンプルなコールバックバリデーターを実装します。 もちろん、彼の実際のプロジェクトに関して、実際の作業を行うためにモデルレイヤーを呼び出さなければなりません。

追加されたpostバリデーターつきの修正されたログインフォームは次の通りです:

class loginForm extends sfForm
{
  public function configure()
  {
    $this->setWidgets(array(
      'username'  => new sfWidgetFormInput(),
      'password'  => new sfWidgetFormInputPassword(),
    ));
 
    $this->setValidators(array(
      'username' => new sfValidatorString(array('required' => true)),
      'password' => new sfValidatorString(array('required' => true)),
    ));
 
    $this->widgetSchema->setNameFormat('login[%s]');
 
    // postバリデーターを追加する
    $this->validatorSchema->setPostValidator(
      new sfValidatorCallback(array('callback' => array($this, 'checkPassword')))
    );
  }
 
  public function checkPassword($validator, $values)
  {
    if ($values['password'] != $values['username'])
    {
      // パスワードが正しくなければ、エラーを投げる
      throw new sfValidatorError($validator, 'Invalid password');
    }
 
    // パスワードが正しければ、クリーンな値を返す
    return $values;
  }
}

これで、フォームは期待通りに動作しますが、小さな問題が1つあります: ユーザー名を入力せずにランダムなパスワードを投稿すると、 2つのエラーメッセージ: 必須項目のユーザー名に対するエラーと間違ったパスワードに対するグローバルエラーが表示されます。

2つのエラーメッセージ

しかし、少しお待ちください。ユーザー名が空の場合、パスワードをバリデートする必要はありません。 ユーザー名が投稿される場合のみパスワードをバリデートするようにフォームを変更してみましょう。 $values['username']`が空ではないことを確認することだけなので、これはとても簡単です:

public function checkPassword($validator, $values)
{
  // パスワードをバリデートする前に、ユーザー名が空ではないことをチェックする
  if (!empty($values['username']) && $values['password'] != $values['username'])
  {
    throw new sfValidatorError($validator, 'Invalid password');
  }
 
  return $values;
}

グローバルエラーを用意する代わりに、上記のパスワードフィールドで'Invalid password'エラーメッセージを表示したいとします。

グローバルエラーを投げる代わりに、passwordフィールドにバインドされたエラーを投げることで実現するのはとても簡単です:

public function checkPassword($validator, $values)
{
  if (!empty($values['username']) && $values['password'] != $values['username'])
  {
    $error = new sfValidatorError($validator, 'Invalid password');
 
    // パスワードフィールドにバインドされたエラーを投げる
    throw new sfValidatorErrorSchema($validator, array('password' => $error));
  }
 
  return $values;
}

フィールドにバインドされたエラーメッセージ