ฝังฟอร์มเอนทิตี้หนึ่งไปยังอีกฟอร์มหนึ่งและบันทึกทั้งสอง


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

ฉันเขียนโมดูลเอนทิตีที่กำหนดเอง แต่มันก็ยังคงไม่เพียงพอ คุณควรใช้ inline_entity_form หากคุณต้องการหลีกเลี่ยงรหัสที่กำหนดเอง
Eyal

@Eyal ฉันไม่กลัวรหัสที่กำหนดเอง (ฉันกำลังเขียนโมดูล: p) แต่ในตัวอย่างของคุณคุณสร้างหลายรูปแบบที่ไม่ใช่แบบฟอร์มผู้ใช้ ซึ่งหมายความว่าเมื่อใดก็ตามที่มีคนพยายามทำแบบเดียวกันในโมดูลอื่นคุณจะเห็นแบบฟอร์มที่มีเพียง 2 ใน 3 (หรือมากกว่า) เสมอ นั่นคือสิ่งที่ฉันคิด แต่ขอบคุณที่สละเวลาติดต่อฉัน ฉันจะดูแบบฟอร์มเอนทิตีแบบอินไลน์ในอีก 2 วัน แต่ฉันจะเปิดให้มีทางเลือกอื่น ๆ ในการแก้ไขได้อย่างใด
Neograph734

คำตอบ:


10

แทนที่จะพยายามทำสิ่งของคุณเองคุณควรลองโมดูลInline Entity Form โมดูลนี้ทำขึ้นสำหรับกรณีเฉพาะนี้ (การสร้าง / แก้ไขเอนทิตีภายในแบบฟอร์มเอนทิตี)

ฉันรู้ว่ามีการใช้งานจำนวนมากในเรื่องนี้เพื่อปรับปรุงขั้นตอนการทำงานใน Drupal Commerce ซึ่งหมายความว่าควรจะทำงานได้ดี ฉันไม่ได้ทำการทดสอบด้วยตัวเอง แต่เนื่องจาก Drupal Commerce ขึ้นอยู่กับมันใน Drupal 8 เช่นกันจึงน่าจะมีเสถียรภาพอยู่แล้ว

โมดูลทำงานโดยการเพิ่มวิดเจ็ตในฟิลด์การอ้างอิงเอนทิตีที่สร้างแบบฟอร์มดังนั้นจึงควรใช้งานแบบพลักแอนด์เพลย์ ข้อกำหนดเพียงอย่างเดียวคือผู้ใช้มีการอ้างอิงถึงเอนทิตีที่กำหนดเองของคุณ


ฉันได้ตรวจสอบแล้ว แต่ฟอร์มเอนทิตีที่อ้างอิงไม่ปรากฏขึ้น นั่นอาจเป็นข้อผิดพลาดในส่วนของฉันแม้ว่า ...
Neograph734

ไม่ใช่เอนทิตีทั้งหมดที่ได้รับการสนับสนุนโดย Inline Entity Form หากนี่เป็นเอนทิตีที่กำหนดเองคุณจะต้องเขียนปลั๊กอินสำหรับเอนทิตีที่กำหนดเองของคุณ เอนทิตีไฟล์ไม่ได้รับการสนับสนุนโดยค่าเริ่มต้นและจำเป็นต้องใช้สิ่งนี้
Frank Robert Anderson

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']
    • หากคุณต้องการให้ผู้ใช้สามารถส่งแบบฟอร์มย่อยได้อย่างอิสระคุณจะต้องเปลี่ยนชื่อการกระทำสำหรับแบบฟอร์มย่อยเพื่อให้คุณสามารถจำได้ว่าปุ่มใดถูกคลิกในภายหลัง หากคุณต้องการให้ผู้ใช้ใช้ปุ่มบันทึกเพียงปุ่มเดียวเพื่อบันทึกทั้งสองสิ่งนั่นจะมีปัญหาน้อยลงดังนั้นอย่าเพิกเฉยจุดย่อยนี้
  • ตอนนี้แบบฟอร์มที่ปรากฏใน UI ขั้นตอนต่อไปคือการจัดการกับการส่ง เมื่อต้องการทำสิ่งนี้ให้เพิ่มการส่งการเรียกกลับแบบฟอร์มไปยังแบบฟอร์มหลักของคุณ คุณอาจต้องการเพิ่มการเรียกกลับการตรวจสอบความถูกต้องของฟอร์มย่อยให้กับฟอร์มหลักเช่นกัน ในการโทรกลับที่กำหนดเองคุณจะต้องเรียกการส่งกลับสำหรับฟอร์มย่อย ใน 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.
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.