Drupal で、フォーム関数が実行される順番 (Form API)

フォームが業務を規定すると、Dries 君は云うのだ。ウェブセントリックなウェブ 2.0 のパラダイムでは、これは正しいように思える。我々はブラウザの中でできることしか、できないのだ。値の入力はフォームが基本、ということだ。 さて、Drupal の Form API は、複雑で、理解しづらい。フォーム間の値の受け渡しに至っては未熟なところがあるようにも思える。現在のところ事実上 Drupal 唯一の参考書である Pro Drupal Development を読んでもわからないところもある。そこでサンプルフォームを作り、とりあえず Form API に関係する関数がどのような順番で実行されるのか試してみた(試したのは Drupal 5)。 仕様としては、
  1. モジュール名が hook
  2. hook_menu から hook_view が呼ばれる。
  3. hook_view から drupal_get_form 関数の引数として _hook_form_name1 が呼ばれ、このフォームが表示される。
  4. _hook_form_name1 では、#after_build プロパティ_hook_foo を指定。
  5. さらに #pre_render プロパティ_hook_bar を指定。
ポイントは、
  • アンダースコア(例:_hook_xxxxx)のついている関数は、任意に各人が用意できるものとした。
  • _hook_form_name1 という名前は、Form API のフレームワークの中では接頭語として機能する。オブジェクト指向でいうとクラス名にあたる。
  • ここでは、hook という 1つのモジュールしか試していないため、hook_form_alter は1度しか呼ばれないが、他のモジュール xxxxx で xxxxx_form_alter が実装されている場合は、モジュール xxxxx の xxxxx_form_alter も呼ばれることになる。
<?php

function hook_menu($may_cache) {
}

function
hook_view() {

 
$output = drupal_get_form('_hook_form_name1');
  return
$output;
}

function
_hook_form_name1($form_values = NULL) {

 
$form['#after_build'] = array('_hook_foo');
 
$form['#pre_render']  = array('_hook_bar');

 
$form['#redirect']  = FALSE;
 
$form['#multistep'] = TRUE// Important!
 
$form['#tree']      = TRUE// Important!

 
return $form;
}

function
_hook_foo($form, $form_values) {
}

function
_hook_bar($form, $form_values) {
}

function
_hook_form_name1_validate($form_id, $form_values, $form) {
}

function
_hook_form_name1_submit($form_id, $form_values) {
}

function
hook_form_alter($form_id, &$form) {
}

?>
ここで、boolean 型の値をとる $form['#redirect'] と $form['#multistep'] プロパティの TRUE / FALSE を変えてみる。 フォームの表示は、すべてのケースで以下の順で関数が実行される。
  1. hook_view
  2. _hook_form_name1
  3. hook_form_alter
  4. _hook_foo
  5. _hook_bar
  6. hook_form_alter
次に
$form['#redirect']  = TRUE;
$form['#multistep'] = TRUE (or FALSE);
として、submit ボタンを押した場合は、フォームはすべてトップページへと遷移する。
  1. hook_form_alter
  2. →トップページへ
次に $form['#redirect'] = FALSE; としてみる。この場合はトップページに行くのではなく、フォーム自身に戻る。しかし、$form['#multistep'] = FALSE; なため、submit で終わる。
$form['#redirect']  = FALSE;
$form['#multistep'] = FALSE;
  1. hook_view
  2. _hook_form_name1
  3. hook_form_alter
  4. _hook_foo
  5. _hook_form_name1_validate
  6. hook_form_name1_submit
  7. _hook_bar
  8. hook_form_alter
最後に $form['#redirect'] = FALSE; かつ $form['#multistep'] = TRUE; の場合も少し動きが違ってくる。$form['#multistep'] = TRUE; は、フォームでウィザードを実現する仕組みなので、今回は何も処理を施していないから、最初のフォームが表示される。
$form['#redirect']  = FALSE;
$form['#multistep'] = TRUE;
  1. hook_view
  2. _hook_form_name1
  3. hook_form_alter
  4. _hook_foo
  5. _hook_form_name1_validate
  6. hook_form_name1_submit
  7. _hook_form_name1
  8. hook_form_alter
  9. _hook_foo
  10. _hook_bar
  11. hook_form_alter
この Form API は、将来性を秘めた API だと思うが、まだまだ仕様に改善の余地がある。実際、Drupal 6 では Form API に手が加えられている。
トラックバック URL: https://perltips.twinkle.cc/trackback/226