$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

symfonyのフォームの登録時に値を変換したい場合

 formクラス内にprocessValues関数を記述することで、登録時に値変換を行うことができる。
 例えば、ユーザにパスワード入力させて、暗号化した後、暗号化に使ったsaltと暗号化済みパスワードをデータベーステーブルに登録したい場合を考える。


1.データベース定義
 テーブル名はuser,カラムはid, name, salt, sha1_passwordとする。schemaは以下のようになる。
database:
  user:
    id: ~
    name:
      type: varchar(80)
    salt:
      type: varchar(32)
    sha1_password:
      type: varchar(40)
 このとき、symfonyは上のカラム定義に沿ったBaseUserFormクラスを自動生成する。


2.ユーザパスワード入力用ウィジェットの作成
 sha1_passwordは暗号化した後のカラムであり、ユーザに入力した内容のバリデートをすることができない。symfonyのフォームクラスではカラムで定義している以外のものもウィジェットとして登録できるため、ユーザパスワード入力用のウィジェットを作成する。UserFormクラスのconfigureオペレーションを以下のように変更する。

<?php

class UserForm extends BaseUserForm
{
  public function configure()
  {
   
    $this->widgetSchema['password'] = new sfWidgetFormInputPassword();
    $this->validatorSchema['password'] = new sfValidatorString(
      array(
        'min_length' => 6,
        'max_length' => 15,
      ),
      array(
        'min_length' => 'パスワードは6文字以上にしてください',
        'max_length' => 'パスワードは15文字以下にしてください'
      )
    );
   
    $this->useFields(
      array('name', 'password')
    );
  }
}


 これによって入力項目はユーザ名、暗号化していないパスワードとなり、入力させたパスワードをバリデートすることができるようになった。


3.登録時の変換
 もちろん上の状態では、テーブルにないカラムがあるため、そのままではデータベースに登録することはできない。そのため、登録時に値を変換する。
 symfonyの場合、登録前に必ずprocessValuesという関数を通すため、これを利用して値を変換し、登録するときにはname, salt, sha1_passwordとして登録するようにする。UserFormクラスは最終的に以下のようになる。

<?php

class UserForm extends BaseUserForm
{
  public function configure()
  {
   
    $this->widgetSchema['password'] = new sfWidgetFormInputPassword();
    $this->validatorSchema['password'] = new sfValidatorString(
      array(
        'min_length' => 6,
        'max_length' => 15,
      ),
      array(
        'min_length' => 'パスワードは6文字以上にしてください',
        'max_length' => 'パスワードは15文字以下にしてください'
      )
    );
   
    $this->useFields(
      array('name', 'password')
    );
  }
 
  /**
   * フォーム入力値をオブジェクトに渡す前に行う処理
   *
   * @param array $values フォームフィールドに入力され、バリデーションを経た値の配列
   * @return array 処理を行った後の値の配列
   */
  public function processValues($values)
  {
    $password = $values['password'];
    unset($values['password']);
   
    $salt = md5(microtime().mt_rand());
    $sha1_password = sha1($password.$salt);
   
    $values['salt'] = $salt;
    $values['sha1_password'] = $sha1_password;
   
    return $values;
  }
}

これにより、登録時には値が変換されて、暗号化されたパスワードが登録される。