Betten Sie ein Entitätsformular in ein anderes ein und speichern Sie beide

9

Ich habe eine benutzerdefinierte Entität, die von der Benutzerentität abhängt. Tatsächlich hängt es jedoch davon ab, dass ich es für sinnvoll hielt, mein Entitätsformular im Benutzerprofilformular anzuzeigen:

Geben Sie hier die Bildbeschreibung ein

Das Problem, das ich jetzt habe, ist das folgende; Es gibt 2 Speichern-Schaltflächen. Und wenn es nicht schlimm genug ist, funktioniert die Schaltfläche zum Speichern für den Benutzer (die untere) nicht mehr und die Schaltfläche zum Speichern von weißen Etiketten speichert nur die Entität für weiße Etiketten.

Das Formular wird wie folgt in das Benutzerformular geändert:

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),
  );
}

Ich hatte gehofft, einige Parameter im $whitelabel_formArray (die früher in Drupal 7 funktionierten) zu mischen , aber dieses Array ist riesig und ich konnte die Submit-Buttons und den Handler nicht finden, die ich brauchte.

Die Frage ist also, kann dies getan werden? Und was wäre die empfohlene Vorgehensweise?

Neograph734
quelle
Danke, ich habe diese Frage tatsächlich früher gelesen, aber egal was ich versucht habe, ich konnte sie nicht finden. Ich werde einen Blick darauf werfen
Neograph734
@Eyal, kennen Sie auch eine Methode, bei der ich das Formular nicht überschreiben muss? Ich würde es vorziehen, das Benutzerformular so zu belassen, wie es ist.
Neograph734
Ich habe ein benutzerdefiniertes Modul entity_reference_form geschrieben, das jedoch nicht ausreichend verwaltet wird. Sie sollten wahrscheinlich inline_entity_form verwenden, wenn Sie benutzerdefinierten Code vermeiden möchten.
Eyal
@Eyal, ich habe keine Angst vor benutzerdefiniertem Code (ich schreibe ein Modul: p). In Ihrem Beispiel erstellen Sie jedoch eine Multiform, die nicht mehr das Benutzerformular ist. Dies bedeutet, dass immer dann, wenn jemand anderes versucht, denselben Trick in einem anderen Modul auszuführen, immer nur 2 der 3 (oder mehr) verfügbaren Formulare angezeigt werden. Das ist es, was mich ausmacht. Aber danke, dass Sie sich die Zeit genommen haben, sich bei mir zu melden. Ich werde in 2 Tagen einen weiteren Blick auf das Inline-Entitätsformular werfen, aber ich wäre offen für Alternativen, um es irgendwie zu ändern.
Neograph734

Antworten:

10

Anstatt zu versuchen, Ihr eigenes Ding zu machen, sollten Sie das Inline Entity Form- Modul ausprobieren . Dieses Modul wurde für diesen speziellen Fall erstellt (Erstellen / Bearbeiten von Entitäten in Entitätsformularen).

Ich weiß, dass viel Arbeit investiert wurde, um den Workflow in Drupal Commerce zu verbessern, was bedeutet, dass dies gut funktionieren sollte. Ich habe es nicht selbst getestet, aber da Drupal Commerce auch in Drupal 8 davon abhängt, sollte es bereits ziemlich stabil sein.

Das Modul fügt dem Entitätsreferenzfeld, mit dem das Formular erstellt wird, ein Widget hinzu, sodass es praktisch Plug-and-Play-fähig sein sollte. Die einzige Voraussetzung ist, dass der Benutzer einen Verweis auf Ihre benutzerdefinierte Entität hat.

googletorp
quelle
Ich habe das untersucht, aber das Formular für die referenzierte Entität wurde nicht angezeigt. Das könnte aber ein Fehler von meiner Seite gewesen sein ...
Neograph734
Nicht alle Entitäten werden vom Inline-Entitätsformular unterstützt. Wenn es sich um eine benutzerdefinierte Entität handelt, müssen Sie ein Plugin für Entitäten Ihres benutzerdefinierten Typs schreiben. Dateientitäten werden standardmäßig nicht unterstützt und erfordern dies.
Frank Robert Anderson
7

Ich glaube, das sollte möglich sein. Leider habe ich heute keine Zeit, Code zu schreiben. Ich denke jedoch, dass Sie Folgendes beachten sollten:

  • Während die Unterform anhängen, stellen Sie sicher , entfernen Sie spezielle Elemente wie form_idund form_build_idvon Drupal verwendet , um zu erkennen , welche Form vorgelegt wurde.
  • Wenn Sie die Formularschaltflächen im zweiten Formular nicht möchten, müssen Sie dieses Formularelement wie unset($sub_form['actions'])zuvor entfernen, bevor Sie das Unterformular an das Hauptformular anhängen.
  • Stellen Sie sicher #tree, dass Sie das Formular aktivieren , damit Sie die Unterformularwerte in einer separaten Tasche in der POST-Variablen abfangen können. Beispiel: $form['#tree'] = TRUE; $form['sub-form'] = $sub_form; Dadurch werden Ihre Unterformularwerte in verfügbar $form_state['values']['sub-form'].
    • Wenn Sie möchten, dass Benutzer das Unterformular unabhängig senden können, müssen Sie die Aktionen für das Unterformular umbenennen, damit Sie später erkennen können, auf welche Schaltfläche geklickt wurde. Wenn Sie möchten, dass der Benutzer nur eine Schaltfläche zum Speichern verwendet, um beide Dinge zu speichern, gibt es weniger Probleme. Ignorieren Sie diesen Unterpunkt.
  • Nachdem das Formular in der Benutzeroberfläche angezeigt wird, besteht der nächste Schritt darin, die Übermittlung zu behandeln. Fügen Sie dazu Ihrem Hauptformular einen Rückruf zum Senden von Formularen hinzu. Möglicherweise möchten Sie auch die Validierungsrückrufe des Unterformulars zum Hauptformular hinzufügen. Im benutzerdefinierten Rückruf müssen Sie den Übermittlungsrückruf für das Unterformular auslösen. In Drupal 7 haben wir drupal_form_submit gemacht - ich weiß noch nicht, was Drupal 8 entspricht. Alternativ können Sie die Rückrufe des Unterformulars im schlimmsten Fall manuell auslösen, aber stellen Sie sicher, dass Sie nur die sub-formWerte übergeben $form_state['values'](ich hoffe, Sie verstehen, was ich meine).
  • Sobald der Rückruf des Unterformulars fehlerfrei funktioniert, können Sie davon ausgehen, dass beide Formulare erfolgreich gesendet und verarbeitet wurden!

Ich hoffe es hilft! Klingt nach einem verdammt guten Experiment! Viel Glück.

Jigarius
quelle
1
Danke, ich habe das Forum bekommen, um bereits mit meinem ursprünglichen Code zu erscheinen. Entfernen form_build_id, form_token, form_idund actionsdie Taste verschwinden lassen und machte das wieder ‚äußere Form‘ Arbeit. Ich werde noch etwas damit spielen und dich wissen lassen, wie es geklappt hat.
Neograph734
Ich vergebe Ihnen das Kopfgeld, weil es der beste Versuch ist, die Frage zu beantworten. Ich habe immer noch Probleme damit, weil das Formular sich weigert, in den "Baummodus" zu wechseln. Alle Werte werden immer auf der obersten Ebene gespeichert, egal was ich versuche. Und es scheint, dass die übermittelten Werte auch nicht in sind $form_state ['values'](die Formularelementschlüssel sind leer). Es ist wahrscheinlich (noch) nicht möglich, aber ich hoffe, dass ich das eines Tages herausfinden kann.
Neograph734
1

Die theoretische Antwort (eine, die nicht funktioniert, aber die nächste, die ich bekommen habe). Hier als Referenz und Ausgangspunkt für andere posten.

Ändern Sie das Benutzerformular.

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';
}

Handler senden:

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.
}
Neograph734
quelle