Score:2

buildForm: ความแตกต่างระหว่างการโหลดหน้าซ้ำกับการโทรกลับ ajax เป็นอย่างไร

ธง br

ฉันกำลังสร้างฟอร์มที่กำหนดเองใน Drupal 9 ซึ่งมี ajax callback อยู่บ้าง

ในช่วง สร้างแบบฟอร์ม ฉันจำเป็นต้องโหลดข้อมูลเพิ่มเติมผ่านการพักสายไปยังบริการภายนอก ซึ่งจากนั้นฉันจะใส่ข้อมูลลงใน private_tempstore ตัวแปร.

ฉันต้องการหลีกเลี่ยงการเรียกจุดสิ้นสุดที่เหลือระหว่างการโทรกลับ ajax และพึ่งพาตัวแปรที่เก็บไว้

อย่างไรก็ตาม ฉันไม่สามารถหาวิธีแยกความแตกต่างระหว่างกรณี "โหลดหน้า" และ "กรณี ajax" เป็นไปได้ไหม?

ฉันพบแล้ว คำตอบนี้ ที่ดูเหมือนจะใช้งานได้โดยทั่วไป:

// ตัวอย่างสำหรับความกะทัดรัดเท่านั้น ฉีดบริการ request_stack และโทร 
// getCurrentRequest() เพื่อรับวัตถุคำขอถ้าเป็นไปได้
$request = \Drupal::request();
$is_ajax = $request->isXmlHttpRequest();

แต่ฉันต้องการทราบว่ามีตัวช่วย \ วิธีแก้ปัญหาโดยใช้ form API หรือไม่

ru flag
IMHO ไม่ควรใช้ตรรกะของแบบฟอร์มในการโหลดหน้าเว็บเทียบกับ Ajax เนื่องจาก BigPipe ของแกนหลักอาจโหลดอะไรก็ได้โดย Ajax (หรือไม่) ขึ้นอยู่กับตำแหน่งบล็อก สภาพแวดล้อม การกำหนดค่า ฯลฯ ... ดูเหมือนว่าจะเป็นหนทางรับประกันความล้มเหลว
Giuseppe avatar
br flag
@Hudri นั่นเป็นการพิจารณาครั้งใหญ่ที่ฉันไม่รู้ ขอบคุณ อย่างไรก็ตาม มีวิธีอื่นในการแก้ปัญหานี้หรือไม่? ฉันหมายถึง ฉันต้องการหลีกเลี่ยงการเรียกส่วนที่เหลือจากภายนอกไปยังการโทรกลับ ajax ทุกครั้งของแบบฟอร์ม
ru flag
TBH ฉันไม่ค่อยเข้าใจเหตุผลของคำถาม `buildForm` มีสิทธิ์เข้าถึง `FormStateInterface $form_state` เกิดอะไรขึ้นกับ `$form_state`
Giuseppe avatar
br flag
@Hudri ฉันจะพยายามใช้ถ้อยคำใหม่: ในระหว่างการรันครั้งแรกของ `buildForm` ข้อมูลที่ฉันต้องการนั้นได้รับจากจุดสิ้นสุดที่เหลือ มันไม่ได้อยู่ใน `$form_state` จากนั้นฉันเก็บข้อมูลนั้นไว้ใน `tempstore` (แต่ฉันก็สามารถใช้ `$form_state->setTemporaryValue()` ได้เช่นกัน ในระหว่างการเรียกกลับของ ajax ต่อไปนี้ ข้อมูลสามารถเข้าถึงได้ผ่าน `$form_state` แต่ฉันต้องแยกความแตกต่างอย่างชัดเจนระหว่าง กรณีแรกและกรณีต่อไป
ru flag
ฉันเชื่อว่าคุณไม่เห็นไม้สำหรับต้นไม้ทุกต้น :-) Pseudo-Code `function buildForm() { if (!$form_state->get('some_helper_var') { $tempStore = load_external_stuff(); $form_state-> set('some_helper_var', TRUE); } $form['field_foo']['default_value'] = $form_state->get('field_foo') ?? $tempStore->get('foo')); }`
Giuseppe avatar
br flag
@Hudri ใช่ ฉันไม่เห็นวิธีแก้ปัญหานั้น :facepalm: อย่างไรก็ตาม ตอนนี้ฉันกำลังลองใช้ `buildForm` ถูกเรียกสองครั้งระหว่างการโทรกลับ ajax - อย่างน้อยก็ในขณะที่ทำการดีบัก ครั้งแรกที่ค่าสถานะของฟอร์มว่างเปล่า ดังนั้น "สิ่งภายนอก" จึงยังโหลดอยู่ทุกครั้ง ดังนั้นจึงใช้งานไม่ได้ :-(
Score:5
ธง cn

เนื่องจาก Drupal 8 วัตถุแบบฟอร์มที่สร้างอินสแตนซ์ด้วย buildForm() จะไม่ถูกรักษาไว้ระหว่างคำขอที่แสดงแบบฟอร์มและคำขอ Ajax แรก ดังนั้นโปรดเตรียมพร้อมที่จะเรียก buildForm() อีกครั้งและต้องสร้างผลลัพธ์ที่เหมือนกันทุกประการ เมื่อคุณได้รับข้อมูลจาก $form_state นี่ไม่ใช่ข้อมูลที่คุณคาดหวังจาก buildForm() แรก เนื่องจากข้อมูลนี้จะไม่ถูกแคช การเพิ่มความซับซ้อนให้ผลลัพธ์ที่เรนเดอร์ของบิลด์แรกถูกแคชไว้ ดังนั้นสิ่งที่คุณจัดเก็บไว้ในบิลด์แรกที่อื่น เช่น ใน tempStore อาจล้าสมัยในคำขอ Ajax ข้อมูลเดียวที่ทำงานตามที่คาดไว้คือค่าในฟอร์ม ซึ่งสามารถซ่อนได้หากคุณต้องการให้มีค่าในฟอร์มที่ส่งและผู้ใช้ไม่สามารถมองเห็นได้

TLDR: buildForm() ถูกเรียกใช้บ่อยกว่าที่คุณคิด และคุณไม่ควรใส่โค้ดลงไปซึ่งมีราคาแพงในการเรียกใช้ ปรับโครงสร้างการเรียก API ภายนอกไปยังบริการด้วยการแคชที่เหมาะสม เพื่อให้ไม่สำคัญว่าจะมีการเรียกบ่อยเพียงใด ทำให้แคชบริการใช้ไม่ได้ด้วยวิธีเดียวกับแบบฟอร์มที่แสดงผล เพื่อไม่ให้แคชของบริการทั้งสองไม่มีข้อมูลที่ล้าสมัย

Giuseppe avatar
br flag
1. ขอบคุณสำหรับคำอธิบาย แม้ว่าจะไม่ชัดเจนสำหรับฉันก็ตาม เช่น. ฉันไม่เข้าใจว่าข้อมูลที่จัดเก็บใน tempStore จะล้าสมัยได้อย่างไร หาก $form_state ไม่ได้แคชไว้ และผลลัพธ์ที่แสดงผลแคชมีความสัมพันธ์อย่างไรกับสิ่งนั้น มีเอกสารรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการทำงานเพื่อให้ได้แนวคิดที่ดีขึ้นหรือไม่?
Giuseppe avatar
br flag
2."ทำให้แคชของบริการใช้ไม่ได้ด้วยวิธีเดียวกับแบบฟอร์มที่แสดงผล เพื่อไม่ให้แคชของบริการทั้งสองไม่มีข้อมูลที่ล้าสมัย" ทำอย่างนั้นได้อย่างไร? สิ่งที่ควรเป็น "ทริกเกอร์" เพื่อทำให้แคชบริการใช้ไม่ได้ ฉันหมายความว่าฉันต้องการทำเช่นนั้นเมื่อโหลดหน้าใหม่ ฉันควรใช้ `KernelEvents::REQUEST` เพื่อค้นหาเส้นทางนั้นหรือไม่ และสำหรับแคชฟอร์ม หมายความว่าฉันควรทำให้ฟอร์มไม่สามารถแคชได้เลยใช่หรือไม่
4uk4 avatar
cn flag
1. ปัญหาหลักคือคุณพยายามใช้ buildform() นอกขอบเขต ด้วยอินพุตเดียวกัน จะต้องให้ผลลัพธ์เหมือนกันบ่อยครั้งที่ Drupal เรียกเมธอดนี้ เฉพาะในกรณีที่ $form_state มีค่าฟอร์มที่ส่งและประมวลผลหรือองค์ประกอบทริกเกอร์ คุณจะสามารถสร้าง $form อื่นและเก็บข้อมูลได้
4uk4 avatar
cn flag
2. เพิ่มถังแคชในบริการและแคชด้วยข้อมูลเมตาแคชเดียวกันกับที่คุณแนบกับ $form ที่แสดงผล
4uk4 avatar
cn flag
หากจำเป็นต้องใช้ข้อมูล API ภายนอกเวอร์ชันเดียวกัน คุณสามารถเพิ่มสตริงเวอร์ชันเป็นอิลิเมนต์ฟอร์มที่ซ่อนอยู่ได้

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา