1つのエンティティフォームを別のエンティティフォームに埋め込み、両方を保存する


9

ユーザーエンティティに依存するカスタムエンティティがあります。実際、エンティティフォームをユーザープロファイルフォーム内に表示するのが理にかなっていると感じたのは、非常に重要です。

ここに画像の説明を入力してください

私が今抱えている問題は次のとおりです。2つの保存ボタンがあります。そして、それが十分に悪いわけではない場合、ユーザー(下の方)の保存ボタンは機能しなくなり、ホワイトラベル保存ボタンはホワイトラベルエンティティのみを保存します。

フォームは次のようにユーザーフォームに変更されます。

function whitelabel_form_user_form_alter(&$form, FormStateInterface $form_state) {

  $whitelabel = WhiteLabel::load(1);

  $whitelabel_form = \Drupal::service('entity.manager')
    ->getFormObject('whitelabel', 'default')
    ->setEntity($whitelabel);

  $form['whitelabel'] = array(
    '#type' => 'details',
    '#title' => t('White label settings'),
    '#open' => TRUE,
    'form' => \Drupal::formBuilder()->getForm($whitelabel_form),
  );
}

$whitelabel_form(Drupal 7で使用されていた)配列内のいくつかのパラメーターをシャッフルしたいと思っていましたが、その配列は非常に大きく、必要な送信ボタンとハンドラーが見つかりませんでした。

だから問題は、これを行うことができるのですか?そして、それを行うための推奨される方法は何でしょうか?


:この回答を参照してくださいdrupal.stackexchange.com/questions/203405/...
エヤル

おかげで、私は実際にその質問を以前に読みましたが、何を試しても、見つけることができませんでした。見てみましょう
Neograph734

@Eyal、フォームをオーバーライドする必要のないメソッドも知っていますか?ユーザーフォームはそのままにしておきます。
Neograph734

カスタムモジュールentity_reference_formを作成しましたが、十分にメンテナンスされていません。カスタムコードを避けたい場合は、おそらくinline_entity_formを使用する必要があります。
Eyal 2017年

@Eyal、私はカスタムコードを恐れていません(私はモジュールを書いています:p)。ただし、この例では、ユーザーフォームではなくなったマルチフォームを作成します。つまり、他の誰かが別のモジュールで同じトリックを実行しようとすると、常に3つ(またはそれ以上)の利用可能なフォームのうち2つだけが表示されます。それが私を思い起こさせるものです。しかし、時間を割いて私に連絡してくれてありがとう。2日間でインラインエンティティフォームをもう一度見ていきますが、どうにかしてそれを変更する代替案を用意しています。
Neograph734 2017年

回答:


10

独自のことをしようとする代わりに、インラインエンティティフォームモジュールを試す必要があります。このモジュールは、この特定のケース(エンティティフォーム内のエンティティの作成/編集)のために作成されています。

Drupal Commerceのワークフローを改善するために多くの作業が行われていることを知っています。つまり、これはうまく機能しているはずです。私自身はテストしていませんが、Drupal CommerceはDrupal 8でも同様に依存しているので、すでに非常に安定しているはずです。

このモジュールは、フォームを作成するエンティティ参照フィールドにウィジェットを追加することで機能するため、ほとんどプラグアンドプレイである必要があります。唯一の要件は、ユーザーがカスタムエンティティへの参照を持っていることです。


調べましたが、参照されているエンティティフォームが表示されませんでした。それは私の側のエラーかもしれません...
Neograph734

インラインエンティティフォームですべてのエンティティがサポートされているわけではありません。これがカスタムエンティティの場合、カスタムタイプのエンティティ用のプラグインを作成する必要があります。ファイルエンティティはデフォルトではサポートされておらず、これが必要です。
フランクロバートアンダーソン

7

これは可能だと思います。残念ながら、今日はコードを書く時間はありませんが、次の点に注意してください。

  • サブフォームを追加しますが、必ず次のような特別なアイテムを削除しますform_idと、form_build_idフォームが送信されたかを認識するためのDrupalで使用されます。
  • 2番目のフォームのフォームボタンが不要なunset($sub_form['actions'])場合は、メインフォームにサブフォームを追加する前に、フォームアイテムを削除する必要があります。
  • #treePOST変数の別のポケットでサブフォームの値をキャッチできるように、フォームを有効にしてください。例:$form['#tree'] = TRUE; $form['sub-form'] = $sub_form; これにより、サブフォームの値がで使用できるようになり$form_state['values']['sub-form']ます。
    • ユーザーがサブフォームを個別に送信できるようにする場合は、サブフォームのアクションの名前を変更して、どのボタンがクリックされたかを後で認識できるようにする必要があります。ユーザーが1つだけの保存ボタンを使用して両方のものを保存するようにしたい場合は、問題が少ないので、このサブポイントは無視してください。
  • これでフォームがUIに表示されたので、次のステップは送信を処理することです。これを行うには、フォーム送信コールバックをメインフォームに追加します。また、サブフォームの検証コールバックをメインフォームに追加することもできます。カスタムコールバックでは、サブフォームの送信コールバックをトリガーする必要があります。Drupal 7では、以前はdrupal_form_submitを実行していました -私はまだDrupal 8に相当するものを知らないのです。または、最悪の場合のシナリオでサブフォームの送信コールバックを手動でトリガーすることもできますが、sub-form値のみを渡すようにしてください$form_state['values'](つまり、私の意味を理解してください)。
  • エラーが発生せずにサブフォームのコールバックが機能すると、両方のフォームが送信されて正常に処理されたと見なすことができます。

それが役に立てば幸い!実験の地獄のように聞こえます!幸運を。


1
おかげで、最初のコードでフォーラムが表示されました。削除form_build_idform_tokenform_idおよびactionsボタンが消え作られ、再び「外形の仕事をしました。私はこれをもう少し遊んで、それがどのように機能したかをあなたに知らせます。
Neograph734 2017年

それは質問に答えるのに最善の試みなので、賞金を差し上げます。フォームが「ツリーモード」に入ることを拒否しているため、私はまだこれで苦労しています。何を試しても、すべての値は常に最上位に保存されます。送信された値も含まれていないようです$form_state ['values'](フォーム要素のキーが空です)。それはおそらく(まだ)不可能ですが、いつかこれを理解したいと思っています。
Neograph734 2017年

1

理論的な答え(うまくいかないものですが、これは私が得た最も近いものです)。参考のためにここに投稿し、他の人のための出発点。

ユーザーフォームを変更します。

function whitelabel_form_user_form_alter(&$form, FormStateInterface $form_state) {
  $whitelabel = WhiteLabel::load(1);

  $whitelabel_form = \Drupal::entityTypeManager()
    ->getFormObject('whitelabel', 'default')
    ->setEntity($whitelabel);
  $renderable_form = \Drupal::formBuilder()->getForm($whitelabel_form);

  // Remove embedded form specific data.
  unset($renderable_form['actions']);
  unset($renderable_form['form_build_id']);
  unset($renderable_form['form_token']);
  unset($renderable_form['form_id']);

  // Also remove all other properties that start with a '#'.
  foreach ($renderable_form as $key => $value) {
    if (strpos($key, '#') === 0) {
      unset ($renderable_form[$key]);
    }
  }

  // Create a container for the entity's fields.
  $form['whitelabel'] = array(
    '#type' => 'details',
    '#title' => t('White label settings'),
    '#open' => TRUE,
    '#tree' => TRUE,
  );
  $form['whitelabel'] += $renderable_form;

  $form['actions']['submit']['#submit'][] = 'whitelabel_form_user_form_submit';
}

送信ハンドラー:

function whitelabel_form_user_form_submit(&$form, FormStateInterface $form_state) {
  $values = $form_state->getValues(); 

  $form_state = new FormState();
  $form_state->setValues($values);
  // Theoretically you'd want to use $values['entity_container']
  // for the dedicated entity values.

  // Obtain or create an entity. (You want to get this from the form.)
  if (!$whitelabel = WhiteLabel::load(1)) {
    $whitelabel = WhiteLabel::create();
  }

\Drupal::entityTypeManager()
  ->getFormObject('whitelabel', 'default')
  ->setEntity($whitelabel) // Current entity.
  ->buildEntity($form, $form_state) // Update with form values.
  ->save(); // Save updated entity.
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.