Вставте одну форму сутності в іншу і збережіть обидві


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

Я написав спеціальний модуль entit_reference_form, але він недостатньо підтримується. Ймовірно, ви повинні використовувати inline_entity_form, якщо хочете уникати спеціального коду.
Еял

@Eyal, я не боюся користувальницького коду (я пишу модуль: p). Але у вашому прикладі ви створюєте мультиформу, яка вже не є формою користувача. Це означає, що коли хтось інший намагається зробити той самий трюк в іншому модулі, ви завжди побачите лише 2 з 3 (або більше) доступних форм. Це те, що мене приховує. Але дякую, що знайшли час, щоб повернутися до мене. У мене буде ще один погляд на вбудовану форму сутності через 2 дні, але я буду відкритий для альтернатив, щоб якось змінити її.
Neograph734

Відповіді:


10

Замість того, щоб намагатися зробити власну справу, слід спробувати модуль Inline Entity Form . Цей модуль створений для цього конкретного випадку (створення / редагування об'єктів у формах сутності).

Я знаю, що для цього було вкладено багато роботи, щоб покращити робочий процес у Друпал-комерції, а це означає, що це має працювати добре. Я його ще не перевіряв, але оскільки 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.