Incorpore um formulário de entidade a outro e salve os dois

9

Eu tenho uma entidade personalizada, dependendo da entidade do usuário. De fato, é assim mesmo, dependendo do que achei que fazia sentido exibir meu formulário de entidade no formulário de perfil de usuário:

insira a descrição da imagem aqui

O problema que estou tendo agora é o seguinte; existem 2 botões de salvamento. E se não for ruim o suficiente, o botão Salvar do usuário (o inferior) nem funciona mais e o botão Salvar etiqueta branca salva apenas a entidade de etiqueta branca.

O formulário é alterado para o formulário do usuário assim:

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

Eu esperava embaralhar alguns parâmetros na $whitelabel_formmatriz (que funcionavam no Drupal 7), mas essa matriz é enorme e não consegui encontrar os botões de envio e o manipulador necessários.

Então a questão é: isso pode ser feito? E qual seria a maneira recomendada de fazer isso?

Neograph734
fonte
Obrigado, eu realmente li essa pergunta mais cedo, mas não importa o que eu tentei, não consegui encontrá-la. Vou dar uma olhada
Neograph734
@ Eyal, você também conhece um método que não exige que eu substitua o formulário? Eu preferiria manter o formulário do usuário como está.
precisa saber é o seguinte
Eu escrevi um módulo personalizado entity_reference_form, mas ele não é mantido o suficiente. Você provavelmente deve usar inline_entity_form se quiser evitar código personalizado.
Eyal
@ Eyal, não tenho medo de código personalizado (estou escrevendo um módulo: p). Mas, no seu exemplo, você cria uma multiforme que não é mais o formulário do usuário. Isso significa que sempre que alguém tentar fazer o mesmo truque em outro módulo, você sempre verá apenas 2 dos 3 (ou mais) formulários disponíveis. É isso que me concebe. Mas obrigado por reservar um tempo para voltar para mim. Vou dar uma outra olhada no formulário de entidade inline em 2 dias, mas eu estaria aberto a alternativas para alterá-lo de alguma forma.
precisa saber é o seguinte

Respostas:

10

Em vez de tentar fazer o que quiser, tente o módulo Inline Entity Form . Este módulo foi criado para este caso específico (criação / edição de entidades nos formulários da entidade).

Sei que muito trabalho foi feito para melhorar o fluxo de trabalho no Drupal Commerce, o que significa que isso deve estar funcionando bem. Eu mesmo não testei, mas como o Drupal Commerce depende disso no Drupal 8, ele já deve estar bem estável.

O módulo funciona adicionando um widget ao campo de referência da entidade que cria o formulário, portanto deve ser praticamente plug and play. O único requisito é que o usuário tenha uma referência à sua entidade personalizada.

googletorp
fonte
Eu examinei isso, mas o formulário da entidade referenciada não apareceu. Isso poderia ter sido um erro da minha parte embora ...
Neograph734
Nem todas as entidades são suportadas pelo formulário de entidade em linha; se essa for uma entidade personalizada, você precisará escrever um plug-in para entidades do seu tipo personalizado. As entidades de arquivo não são suportadas por padrão e exigem isso.
Frank Robert Anderson
7

Eu acredito que isso deveria ser possível. Infelizmente, não tenho tempo para escrever hoje, no entanto, acho que você deve ter em mente o seguinte:

  • Ao anexar o sub-formulário, remova itens especiais como form_ide form_build_idusados ​​pelo Drupal para reconhecer qual formulário foi enviado.
  • Se você não desejar os botões do formulário no segundo formulário, remova esse item do formulário como unset($sub_form['actions'])antes de anexar o subformulário ao formulário principal.
  • Certifique-se de habilitar #treeo formulário para poder capturar os valores do sub-formulário em um bolso separado na variável POST. Exemplo, $form['#tree'] = TRUE; $form['sub-form'] = $sub_form; Isso disponibilizará seus valores de subformulário em $form_state['values']['sub-form'].
    • Se você deseja que os usuários possam enviar o sub-formulário independentemente, precisará renomear as ações para o sub-formulário, para que você possa reconhecer posteriormente qual botão foi clicado. Se você deseja que o usuário use apenas um botão de salvar para salvar as duas coisas, haverá menos problemas; portanto, ignore esse subponto.
  • Agora, que o formulário está visível na interface do usuário, a próxima etapa seria lidar com o envio. Para fazer isso, adicione um retorno de chamada de envio de formulário ao seu formulário principal. Você também pode adicionar os retornos de chamada de validação do subformulário ao formulário principal. No retorno de chamada personalizado, você precisará acionar o retorno de chamada do envio para o sub-formulário. No Drupal 7, costumávamos fazer drupal_form_submit - ainda não sei o equivalente ao Drupal 8. Como alternativa, você pode acionar os retornos de chamada de envio do subformulário manualmente no pior cenário, mas certifique-se de passar apenas os sub-formvalores $form_state['values'](espero que você entenda o que quero dizer).
  • Depois que o retorno de chamada do subformulário funcionar sem erros, você poderá assumir que ambos os formulários foram enviados e processados ​​com sucesso!

Espero que ajude! Parece um inferno de um experimento! Boa sorte.

Jigarius
fonte
1
Obrigado, eu consegui o fórum para aparecer já com o meu código inicial. Removendo form_build_id, form_token, form_ide actionsfez o botão desaparecer e fez o trabalho 'forma exterior' novamente. Vou brincar um pouco mais e informar como tudo deu certo.
precisa saber é o seguinte
Estou lhe concedendo a recompensa porque é a melhor tentativa de responder à pergunta. Ainda estou lutando com isso porque o formulário se recusa a entrar no 'modo de árvore'. Todos os valores são sempre armazenados no nível superior, não importa o que eu tente. E parece que os valores enviados também não estão $form_state ['values'](as chaves do elemento do formulário estão vazias). Provavelmente ainda não é possível, mas espero descobrir isso algum dia.
precisa saber é o seguinte
1

A resposta teórica (que não funciona, mas essa é a mais próxima que cheguei). Postando aqui para referência e um ponto de partida para outros.

Altere o formulário do usuário.

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 manipulador:

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
fonte