Вставить одну форму сущности в другую и сохранить оба


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/…
Eyal

Спасибо, я действительно прочитал этот вопрос раньше, но, что бы я ни пытался, я не смог его найти. Я посмотрю
Neograph734

@Eyal, ты тоже знаешь метод, который не требует от меня переопределения формы? Я бы предпочел оставить пользовательскую форму такой, какая она есть.
Neograph734

Я написал собственный модуль entity_reference_form, но он недостаточно поддерживается. Возможно, вам следует использовать inline_entity_form, если вы хотите избежать пользовательского кода.
Эяль

@Eyal, я не боюсь нестандартного кода (пишу модуль: p). Но в вашем примере вы создаете мультиформную форму, которая больше не является пользовательской формой. Это означает, что всякий раз, когда кто-то другой пытается сделать такой же трюк в другом модуле, вы всегда будете видеть только 2 из 3 (или более) доступных форм. Это то, что задумывает меня. Но спасибо, что нашли время, чтобы вернуться ко мне. Через 2 дня я еще раз взгляну на встроенную форму сущности, но я буду открыт для альтернативных вариантов ее изменения.
Neograph734

Ответы:


10

Вместо того, чтобы пытаться делать что-то свое, вы должны попробовать модуль Inline Entity Form . Этот модуль сделан для этого конкретного случая (создание / редактирование сущностей в формах сущностей).

Я знаю, что для улучшения рабочего процесса в Drupal Commerce была проделана большая работа, а это значит, что это должно работать хорошо. Я не проверял это сам, но, поскольку Drupal Commerce зависит от него и в Drupal 8, он должен быть достаточно стабильным.

Модуль работает путем добавления виджета в поле ссылки на сущность, которое создает форму, поэтому он должен быть в значительной степени подключен и играть. Единственное требование - чтобы у пользователя была ссылка на ваш пользовательский объект.


Я изучил это, но форма ссылочной сущности не появилась. Хотя это могло быть ошибкой с моей стороны ...
Neograph734

Не все сущности поддерживаются в Inline Entity Form, если это настраиваемая сущность, то вам нужно будет написать плагин для сущностей вашего настраиваемого типа. Файловые сущности не поддерживаются по умолчанию и требуют этого.
Фрэнк Роберт Андерсон

7

Я считаю, что это должно быть возможно. К сожалению, сегодня у меня нет времени на написание кода, однако, я думаю, вы должны помнить следующее:

  • При добавлении подформы убедитесь, что вы удалили специальные элементы, такие как form_idи form_build_idиспользуемые Drupal, чтобы распознать, какая форма была отправлена.
  • Если вы не хотите, чтобы кнопки формы во второй форме, вам нужно удалить этот элемент формы, как unset($sub_form['actions'])прежде, чем вы добавляете вложенную форму в основную форму.
  • Убедитесь, что вы включили #treeдля формы, чтобы вы могли поймать значения подформы в отдельном кармане в переменной POST. Например, $form['#tree'] = TRUE; $form['sub-form'] = $sub_form; это сделает ваши значения формы доступными в $form_state['values']['sub-form'].
    • Если вы хотите, чтобы пользователи могли отправлять вложенную форму независимо, вам придется переименовать действия для вложенной формы, чтобы впоследствии вы могли распознать, какая кнопка была нажата. Если вы хотите, чтобы пользователь использовал только одну кнопку сохранения, чтобы сохранить обе вещи, тогда будет меньше проблем, поэтому игнорируйте этот подпункт.
  • Теперь, когда форма видима в пользовательском интерфейсе, следующим шагом будет обработка отправки. Для этого добавьте обратный вызов для отправки формы в основную форму. Возможно, вы также захотите добавить обратные вызовы проверки формы для основной формы. В пользовательском обратном вызове вам нужно будет вызвать обратный вызов отправки для формы. В Drupal 7 мы делали drupal_form_submit - я пока не знаю эквивалента для Drupal 8. В качестве альтернативы, вы можете инициировать обратные вызовы для отправки формы в худшем случае, но убедитесь, что вы передаете только sub-formзначения $form_state['values'](надеюсь, вы понимаете, что я имею в виду).
  • Как только обратный вызов формы будет работать без ошибок, вы можете предположить, что обе формы были отправлены и успешно обработаны!

Надеюсь, поможет! Звучит как адский эксперимент! Удачи.


1
Спасибо, у меня уже появился форум с моим исходным кодом. Удаление form_build_id, form_token, form_idи actionsсделал кнопку исчезают и снова сделал «внешний вид» работы. Я поиграю с этим еще немного и дам вам знать, как это получилось.
Neograph734

Я награждаю вас за вознаграждение, потому что это лучшая попытка ответить на вопрос. Я все еще борюсь с этим, потому что форма отказывается переходить в «древовидный режим». Все значения всегда хранятся на верхнем уровне, независимо от того, что я пытаюсь. И, кажется, представленные значения также не в $form_state ['values'](ключи элемента формы пусты). Вероятно, это невозможно (пока), но я надеюсь когда-нибудь выяснить это.
Neograph734

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.
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.