AI による要約
本記事は、Drupal の
EntityFormとは何かという疑問を起点に、フォームが表示される仕組みをコアのソースコードから解説した記事です。エンティティのアノテーションによるフォームクラスの宣言、Entity Form Displayを通じたフィールドの自動挿入、そしてhook_entity_type_alter()を使った独自フォームへの差し替えまでを、実際に動作するサンプルモジュールを通じて確認しています。
EntityForm とは
エンティティ(ノード、ユーザ、タクソノミー等)の CRUD フォームを担当する基底クラスのことです。
User エンティティ等に設定されている初期フォーム
User エンティティ等には、初期フォームが設定されています。
初期フォームの表示される仕組み
この初期フォームが表示される仕組みとしては、ソースコード側のエンティティのクラスのアノテーションにおいて使用するフォームを宣言しているというものです。
ユーザクラスであれば下記のように、 @ContentEntityType アノテーションで指定しています。
// core/modules/user/src/Entity/User.php
/**
* @ContentEntityType(
* id = "user",
* ...
* handlers = {
* "form" = {
* "default" = "Drupal\user\ProfileForm",
* "register" = "Drupal\user\RegisterForm",
* "cancel" = "Drupal\user\Form\UserCancelForm",
* },
* },
* ...
* )
*/
class User extends ContentEntityBase implements UserInterface {
別のフォームを使用する方法
フォームクラスの定義
例) User エンティティに適用するエンティティを書き換える場合
ProfileForm を拡張して、別のフォームクラスを作成します。
class MyUserForm extends ProfileForm {
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
// 不要な項目を全部消す
unset($form['account']['mail']);
unset($form['account']['pass']);
// 独自フィールドを追加
$form['bio'] = [
'#type' => 'textarea',
'#title' => t('自己紹介'),
];
return $form;
}
}
適用するクラスの変更(上書き)
その後、 hook_entity_type_build(), hook_entity_type_alter() 等の hook 関数の中で setFormClass() 関数を呼び出し、アノテーションを書き換えるのと同等の処理を行います。
function my_module_entity_type_alter(array &$entity_types) {
$entity_types['user']->setFormClass('default', MyUserForm::class);
}
Tips: hook_entity_type_build と hook_entity_type_alter の違い
既存のフォームを上書きする場合は hook_entity_type_alter() 、フォームを新規に追加する場合は hook_entity_type_build() みたいです。
より正確に述べると下記のようになるとのこと by Claude
// 曖昧
「フォームを新規に追加する場合は hook_entity_type_build()」// 正確
「既存エンティティに新しい FormMode キーを追加する場合は hook_entity_type_build()」
「既存の FormMode キーに登録されたクラスを差し替える場合は hook_entity_type_alter()」
なので、今回のユースケースで使うのは、 alter() の方がメインです。
Tips: FormMode とは。 EntityForm と何が違うのか。
EntityForm は PHP クラスです。これと "FormMode" キーとの対応を定義しているのが、アノテーションやこの hook 関数です。
FormMode キーと EntityForm の新しい対応を Entity に追加する場合は hook_entity_type_build() で、上書きする場合は hook_entity_type_alter() です。
サンプルを使った動作検証
目的
hook_entity_type_alter() で default フォームを差し替えることで、 /user/{user}/edit の表示が変わることを確認することです。
検証手順
1. モジュールの雛形を用意する
drush generate module
# Module name: form_test
# Machine name: form_test
2. フォームクラスを作成する
// modules/custom/form_test/src/Form/MyUserForm.php
namespace Drupal\form_test\Form;
use Drupal\user\ProfileForm;
use Drupal\Core\Form\FormStateInterface;
class MyUserForm extends ProfileForm {
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
// 動作確認用のメッセージを追加
\Drupal::messenger()->addMessage('MyUserForm が適用されています');
// メールとパスワードを非表示
unset($form['account']['mail']);
unset($form['account']['pass']);
return $form;
}
}
3. hook を実装する
// modules/custom/form_test/form_test.module
use Drupal\form_test\Form\MyUserForm;
function form_test_entity_type_alter(array &$entity_types) {
if (isset($entity_types['user'])) {
$entity_types['user']->setFormClass('default', MyUserForm::class);
}
}
4. キャッシュをクリアして確認
drush cr
5. 確認ポイント
/user/1/edit にアクセスします。
比較すると、下記が変更されていることがわかります。
- 画面上部にメッセージが出る
- メールフィールドが消えている
- パスワードフィールドが消えている
6. 元に戻す確認(念のため)
モジュールを無効化すると標準の ProfileForm に戻ることも確認しておくと、hook が正しく機能していることの裏付けになります。
drush pmu form_test
drush cr
# /user/1/edit でメールとパスワードが復活していることを確認
あとがき
ということで、 EntityForm を拡張し、 Entity に設定することで、フォームを変更できることが確認できました。
終わり。


