Incruste un formulario de entidad en otro y guarde ambos


9

Tengo una entidad personalizada, que depende de la entidad del usuario. De hecho, depende de que me parezca lógico mostrar mi formulario de entidad dentro del formulario de perfil de usuario:

ingrese la descripción de la imagen aquí

El problema que tengo ahora es el siguiente; Hay 2 botones de guardar. Y si no es lo suficientemente malo, el botón Guardar para el usuario (el inferior) ya ni siquiera funciona y el botón Guardar etiqueta blanca solo guarda la entidad de etiqueta blanca.

El formulario se modifica en el formulario de usuario de esta manera:

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

Esperaba mezclar algunos parámetros en la $whitelabel_formmatriz (que solía funcionar en Drupal 7), pero esa matriz es enorme y no pude encontrar los botones de envío y el controlador que necesitaba.

Entonces la pregunta es, ¿se puede hacer esto? ¿Y cuál sería la forma recomendada de hacerlo?



Gracias, en realidad leí esa pregunta antes, pero no importa lo que intenté, no pude encontrarla. Voy a echar un vistazo
Neograph734

@Eyal, ¿también conoces un método que no requiera que anule el formulario? Prefiero mantener el formulario de usuario como está.
Neograph734

Escribí un módulo personalizado entity_reference_form pero no se mantiene lo suficiente. Probablemente debería usar inline_entity_form si desea evitar el código personalizado.
Eyal

@Eyal, no le temo al código personalizado (estoy escribiendo un módulo: p). Pero en su ejemplo, crea un multiforme que ya no es el formulario de usuario. Esto significa que siempre que alguien más intente hacer el mismo truco en otro módulo, siempre verá solo 2 de los 3 (o más) formularios disponibles. Eso es lo que me preocupa. Pero gracias por tomarse el tiempo de responderme. Veré otra vez el formulario de entidad en línea en 2 días, pero estaría abierto a alternativas para alterarlo de alguna manera.
Neograph734

Respuestas:


10

En lugar de intentar hacer lo suyo, debería probar el módulo de formulario de entidad en línea . Este módulo está hecho para este caso específico (creación / edición de entidades dentro de formularios de entidad).

Sé que se ha trabajado mucho para mejorar el flujo de trabajo en Drupal Commerce, lo que significa que debería funcionar bien. No lo he probado yo mismo, pero dado que Drupal Commerce también depende de él en Drupal 8, ya debería ser bastante estable.

El módulo funciona agregando un widget al campo de referencia de entidad que crea el formulario, por lo que debería ser bastante plug and play. El único requisito es que el usuario tenga una referencia a su entidad personalizada.


Investigué eso, pero el formulario de entidad referenciado no apareció. Sin embargo, eso podría haber sido un error de mi parte ...
Neograph734

No todas las entidades son compatibles con el Formulario de entidad en línea, si se trata de una entidad personalizada, deberá escribir un complemento para las entidades de su tipo personalizado. Las entidades de archivo no son compatibles de manera predeterminada y lo requieren.
Frank Robert Anderson

7

Creo que esto debería ser posible. Desafortunadamente, no tengo tiempo para escribir código hoy, sin embargo, creo que debe tener en cuenta lo siguiente:

  • Si bien añadiendo el sub-formulario, asegúrese de eliminar elementos especiales como form_idy form_build_idutilizado por Drupal para reconocer qué forma se presentó.
  • Si no desea los botones del formulario en el segundo formulario, debe eliminar ese elemento del formulario como unset($sub_form['actions'])antes de agregar el subformulario al formulario principal.
  • Asegúrese de habilitar #treeel formulario para que pueda capturar los valores del subformulario en un bolsillo separado en la variable POST. Ejemplo, $form['#tree'] = TRUE; $form['sub-form'] = $sub_form; esto hará que sus valores de subformulario estén disponibles en $form_state['values']['sub-form'].
    • Si desea que los usuarios puedan enviar el subformulario de forma independiente, deberá cambiar el nombre de las acciones del subformulario para que luego pueda reconocer en qué botón se hizo clic. Si desea que el usuario use solo un botón de guardar para guardar ambas cosas, entonces habrá menos problemas, por lo tanto, ignore este subpunto.
  • Ahora que el formulario está visible en la interfaz de usuario, el siguiente paso sería manejar el envío. Para hacer esto, agregue una devolución de llamada de envío de formulario a su formulario principal. Es posible que también desee agregar las devoluciones de llamada de validación del subformulario al formulario principal. En la devolución de llamada personalizada, deberá activar la devolución de llamada de envío para el subformulario. En Drupal 7 solíamos hacer drupal_form_submit , todavía no sé el equivalente de Drupal 8. Alternativamente, puede activar las devoluciones de llamada de envío del subformulario manualmente en el peor de los casos, pero asegúrese de pasar solo los sub-formvalores $form_state['values'](espero que entienda lo que quiero decir).
  • Una vez que la devolución de llamada del subformulario funciona sin errores, puede asumir que ambos formularios se enviaron y procesaron correctamente.

¡Espero eso ayude! ¡Suena como un gran experimento! Buena suerte.


1
Gracias, ya apareció el foro con mi código inicial. Extracción form_build_id, form_token, form_idy actionsrealizado el botón desaparecerá y el trabajo realizado 'forma externa' de nuevo. Jugaré con esto un poco más y les diré cómo funcionó.
Neograph734

Te estoy otorgando la recompensa porque es el mejor intento de responder la pregunta. Todavía estoy luchando con esto porque el formulario se niega a entrar en 'modo de árbol'. Todos los valores siempre se almacenan en el nivel superior, no importa lo que intente. Y parece que los valores enviados tampoco están en $form_state ['values'](las claves del elemento de formulario están vacías). Probablemente no sea posible (todavía), pero espero resolver esto algún día.
Neograph734

1

La respuesta teórica (una que no funciona, pero esta es la más cercana que obtuve). Publicando aquí para referencia y un punto de partida para otros.

Alterar el formulario de usuario.

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

Enviar manejador:

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.
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.