Osadź jedną formę encji w drugą i zapisz obie

9

Mam encję niestandardową, która zależy od encji użytkownika. W rzeczywistości jest tak, że czułem, że sensowne jest wyświetlanie mojej formy podmiotu w formularzu profilu użytkownika:

wprowadź opis zdjęcia tutaj

Problem, który mam teraz, jest następujący; są 2 przyciski zapisu. A jeśli nie jest wystarczająco źle, przycisk zapisu dla użytkownika (dolny) już nie działa, a przycisk zapisu białej etykiety zapisuje tylko białą etykietę.

Formularz jest zmieniany w formularz użytkownika w następujący sposób:

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

Miałem nadzieję przetasować niektóre parametry w $whitelabel_formtablicy (która kiedyś działała w Drupal 7), ale ta tablica jest ogromna i nie mogłem znaleźć przycisków przesyłania i obsługi, których potrzebowałem.

Pytanie brzmi: czy można to zrobić? A jaki byłby to zalecany sposób?

Neograph734
źródło
Zobacz tę odpowiedź: drupal.stackexchange.com/questions/203405/…
Eyal
Dzięki, właściwie przeczytałem to pytanie wcześniej, ale bez względu na to, czego próbowałem, nie mogłem go znaleźć. Muszę spojrzeć
Neograph734
@Eyal, czy znasz również metodę, która nie wymaga ode mnie zastąpienia formularza? Wolę zachować formularz użytkownika bez zmian.
Neograph734
Napisałem niestandardowy moduł encja_referencja_forma, ale nie jest wystarczająco obsługiwany. Prawdopodobnie powinieneś użyć inline_entity_form, jeśli chcesz uniknąć niestandardowego kodu.
Eyal
@Eyal, nie boję się niestandardowego kodu (piszę moduł: p). Ale w twoim przykładzie tworzysz formularz, który nie jest już formularzem użytkownika. Oznacza to, że ilekroć ktoś spróbuje wykonać tę samą sztuczkę w innym module, zawsze zobaczysz tylko 2 z 3 (lub więcej) dostępnych formularzy. To mnie otacza. Ale dzięki za poświęcenie mi czasu, aby do mnie wrócić. Za dwa dni przyjrzę się inline formie encji, ale będę otwarty na alternatywne sposoby jej modyfikacji.
Neograph734

Odpowiedzi:

10

Zamiast próbować robić swoje, powinieneś wypróbować moduł Inline Entity Form . Ten moduł jest przeznaczony do tego konkretnego przypadku (tworzenie / edytowanie encji w formularzach encji).

Wiem, że włożono w to wiele pracy, aby poprawić przepływ pracy w Drupal Commerce, co oznacza, że ​​powinno to działać dobrze. Nie przetestowałem tego sam, ale ponieważ Drupal Commerce również od tego zależy w Drupal 8, powinien już być dość stabilny.

Moduł działa poprzez dodanie widżetu do pola referencyjnego encji, która tworzy formularz, więc powinno być w zasadzie plug and play. Jedynym wymaganiem jest, aby użytkownik miał odniesienie do Twojej jednostki niestandardowej.

googletorp
źródło
Przyglądałem się temu, ale formularz encji, do której istnieje odwołanie, nie pojawił się. To może być błąd z mojej strony ...
Neograph734
Nie wszystkie encje są obsługiwane przez formularz encji, jeśli jest to encja niestandardowa, musisz napisać wtyczkę dla encji niestandardowego typu. Jednostki plików nie są domyślnie obsługiwane i wymagają tego.
Frank Robert Anderson
7

Wierzę, że to powinno być możliwe. Niestety nie mam dzisiaj czasu na pisanie kodu, jednak myślę, że powinieneś pamiętać o następujących kwestiach:

  • Dołączając podformularz, upewnij się, że usunąłeś specjalne przedmioty, takie jak form_idi form_build_idużywane przez Drupal do rozpoznania, który formularz został przesłany.
  • Jeśli nie chcesz przycisków formularza w drugim formularzu, musisz usunąć ten element formularza, tak jak unset($sub_form['actions'])przed dołączeniem podformularza do formularza głównego.
  • Upewnij się, że włączono #treeformularz, aby można było przechwytywać wartości podformularza w osobnej kieszeni w zmiennej POST. Przykład: $form['#tree'] = TRUE; $form['sub-form'] = $sub_form; Twoje wartości podformularza będą dostępne w $form_state['values']['sub-form'].
    • Jeśli chcesz, aby użytkownicy mogli przesyłać podformularz niezależnie, będziesz musiał zmienić nazwę akcji dla podformularza, aby później móc rozpoznać, który przycisk został kliknięty. Jeśli chcesz, aby użytkownik używał tylko jednego przycisku zapisywania, aby zapisać obie rzeczy, wówczas byłoby mniej problemów, więc zignoruj ​​ten podpunkt.
  • Teraz, gdy formularz jest widoczny w interfejsie użytkownika, następnym krokiem będzie obsłużenie przesyłania. Aby to zrobić, dodaj wywołanie zwrotne przesyłania formularza do głównego formularza. Możesz także dodać wywołania zwrotne sprawdzania poprawności podformularza do formularza głównego. W niestandardowym wywołaniu zwrotnym konieczne będzie wyzwolenie wywołania zwrotnego przesyłania dla podformularza. W Drupal 7 robiliśmy drupal_form_submit - nie wiem jeszcze odpowiednika Drupala 8. W najgorszym przypadku możesz ręcznie wywoływać wywołania zwrotne w podformularzu, ale upewnij się, że przekazujesz tylko sub-formwartości do $form_state['values'](mam nadzieję, że rozumiesz, co mam na myśli).
  • Gdy wywołanie zwrotne podformularza działa bez błędów, możesz założyć, że oba formularze zostały przesłane i pomyślnie przetworzone!

Mam nadzieję, że to pomoże! Brzmi jak diabli eksperymentu! Powodzenia.

Jigarius
źródło
1
Dzięki, udało mi się wyświetlić forum z moim początkowym kodem. Usuwanie form_build_id, form_token, form_ida actionswykonane przycisk zniknie i wykonane ponownie pracę „forma zewnętrzna”. Będę się z tym jeszcze bawić i dam znać, jak się udało.
Neograph734
Przyznam ci nagrodę, ponieważ jest to najlepsza próba odpowiedzi na pytanie. Nadal mam z tym problem, ponieważ formularz odmawia przejścia w „tryb drzewa”. Wszystkie wartości są zawsze przechowywane na najwyższym poziomie, bez względu na to, co próbuję. Wygląda na to, że przesłanych wartości również nie ma $form_state ['values'](klucze elementów formularza są puste). Prawdopodobnie nie jest to możliwe (jeszcze), ale mam nadzieję, że kiedyś to rozwiążę.
Neograph734
1

Teoretyczna odpowiedź (taka, która nie działa, ale jest to najbliższa odpowiedź). Publikowanie tutaj w celach informacyjnych i punkt wyjścia dla innych.

Zmień formularz użytkownika.

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

Prześlij obsługę:

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
źródło