Incorporez un formulaire d'entité dans un autre et enregistrez les deux

9

J'ai une entité personnalisée, qui dépend de l'entité utilisateur. En fait, c'est tout de même selon que je sentais qu'il était logique d'afficher mon formulaire d'entité dans le formulaire de profil utilisateur:

entrez la description de l'image ici

Le problème que j'ai maintenant est le suivant; il y a 2 boutons de sauvegarde. Et s'il n'est pas assez mauvais, le bouton d'enregistrement pour l'utilisateur (celui du bas) ne fonctionne même plus et le bouton d'enregistrement d'étiquette blanche enregistre uniquement l'entité d'étiquette blanche.

Le formulaire est modifié dans le formulaire utilisateur comme ceci:

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

J'espérais mélanger certains paramètres dans le $whitelabel_formtableau (qui fonctionnait dans Drupal 7), mais ce tableau est énorme et je n'ai pas pu trouver les boutons de soumission et le gestionnaire dont j'avais besoin.

La question est donc de savoir si cela peut être fait? Et quelle serait la manière recommandée de le faire?

Neograph734
la source
Merci, j'ai lu cette question plus tôt, mais peu importe ce que j'ai essayé, je ne l'ai pas trouvée. Je vais jeter un oeil
Neograph734
@Eyal, connaissez-vous également une méthode qui ne me demande pas de remplacer le formulaire? Je préfère conserver le formulaire utilisateur tel quel.
Neograph734
J'ai écrit un module personnalisé entity_reference_form mais il n'est pas suffisamment maintenu. Vous devriez probablement utiliser inline_entity_form si vous voulez éviter le code personnalisé.
Eyal
@Eyal, je n'ai pas peur du code personnalisé (j'écris un module: p). Mais dans votre exemple, vous créez un formulaire multiforme qui n'est plus le formulaire utilisateur. Cela signifie que chaque fois que quelqu'un d'autre tente de faire la même astuce dans un autre module, vous ne verrez toujours que 2 des 3 (ou plus) formulaires disponibles. Voilà ce qui me conçoit. Mais merci d'avoir pris le temps de me recontacter. J'aurai un autre regard sur le formulaire d'entité en ligne dans 2 jours, mais je serais ouvert à des alternatives pour le modifier d'une manière ou d'une autre.
Neograph734

Réponses:

10

Au lieu d'essayer de faire votre propre truc, vous devriez essayer le module Inline Entity Form . Ce module est conçu pour ce cas spécifique (création / modification d'entités dans des formulaires d'entité).

Je sais que beaucoup de travail a été fait pour améliorer le flux de travail dans Drupal Commerce, ce qui signifie que cela devrait bien fonctionner. Je ne l'ai pas testé moi-même, mais puisque Drupal Commerce en dépend également dans Drupal 8, il devrait déjà être assez stable.

Le module fonctionne en ajoutant un widget au champ de référence d'entité qui crée le formulaire, il devrait donc être à peu près plug and play. La seule exigence est que l'utilisateur ait une référence à votre entité personnalisée.

googletorp
la source
J'ai vérifié, mais le formulaire d'entité référencé ne s'est pas présenté. Cela aurait pu être une erreur de ma part cependant ...
Neograph734
Toutes les entités ne sont pas prises en charge par le formulaire d'entité en ligne, s'il s'agit d'une entité personnalisée, vous devrez écrire un plug-in pour les entités de votre type personnalisé. Les entités de fichier ne sont pas prises en charge par défaut et l'exigent.
Frank Robert Anderson
7

Je pense que cela devrait être possible. Malheureusement, je n'ai pas le temps d'écrire du code aujourd'hui, cependant, je pense que vous devez garder les choses suivantes à l'esprit:

  • Lors de l'ajout du sous-formulaire, assurez-vous de supprimer les éléments spéciaux tels que form_idet form_build_idutilisés par Drupal pour reconnaître le formulaire qui a été soumis.
  • Si vous ne souhaitez pas les boutons de formulaire dans le deuxième formulaire, vous devez supprimer cet élément de formulaire comme unset($sub_form['actions'])avant d'ajouter le sous-formulaire au formulaire principal.
  • Assurez-vous que vous activez #treepour le formulaire afin que vous puissiez intercepter les valeurs de sous-formulaire dans une poche distincte dans la variable POST. Exemple, $form['#tree'] = TRUE; $form['sub-form'] = $sub_form; cela rendra vos valeurs de sous-formulaire disponibles dans $form_state['values']['sub-form'].
    • Si vous souhaitez que les utilisateurs puissent soumettre le sous-formulaire indépendamment, vous devrez renommer les actions pour le sous-formulaire afin de pouvoir ultérieurement reconnaître le bouton sur lequel vous avez cliqué. Si vous souhaitez que l'utilisateur n'utilise qu'un seul bouton d'enregistrement pour enregistrer les deux choses, il y aura moins de problèmes, alors ignorez ce sous-point.
  • Maintenant que le formulaire est visible dans l'interface utilisateur, l'étape suivante consiste à gérer la soumission. Pour ce faire, ajoutez un rappel de soumission de formulaire à votre formulaire principal. Vous pouvez également ajouter les rappels de validation du sous-formulaire au formulaire principal. Dans le rappel personnalisé, vous devrez déclencher le rappel de soumission pour le sous-formulaire. Dans Drupal 7, nous avions l'habitude de faire drupal_form_submit - je ne sais pas encore l'équivalent pour Drupal 8. Alternativement, vous pouvez déclencher manuellement les rappels de soumission du sous-formulaire dans le pire des cas, mais assurez-vous de ne transmettre que les sub-formvaleurs dans $form_state['values'](j'espère que vous comprenez ce que je veux dire).
  • Une fois que le rappel de sous-formulaire fonctionne sans erreur, vous pouvez supposer que les deux formulaires ont été soumis et traités avec succès!

J'espère que cela aide! Cela ressemble à un enfer d'une expérience! Bonne chance.

Jigarius
la source
1
Merci, j'ai eu le forum pour apparaître déjà avec mon code initial. Retrait form_build_id, form_token, form_idet actionsfait disparaître le bouton et fait le travail « de forme extérieure » à nouveau. Je vais jouer avec cela un peu plus et vous laisser savoir comment cela a fonctionné.
Neograph734
Je vous accorde la prime parce que c'est la meilleure tentative pour répondre à la question. Je continue de me battre avec cela parce que le formulaire refuse de passer en «mode arborescence». Toutes les valeurs sont toujours stockées au niveau supérieur, peu importe ce que j'essaie. Et il semble que les valeurs soumises ne soient pas non plus $form_state ['values'](les clés des éléments de formulaire sont vides). Ce n'est probablement pas (encore) possible, mais j'espère comprendre cela un jour.
Neograph734
1

La réponse théorique (celle qui ne fonctionne pas, mais c'est la plus proche que j'ai obtenue). Poster ici pour référence et un point de départ pour les autres.

Modifiez le formulaire utilisateur.

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

Soumettre le gestionnaire:

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
la source