Puncte:2

buildForm: cum se diferențiază între reîncărcarea paginii și apel invers Ajax?

drapel br

Construiesc un formular personalizat în Drupal 9, care are câteva apeluri Ajax.

In timpul buildForm Trebuie să încarc câteva date suplimentare printr-un apel de odihnă către un serviciu extern, pe care apoi le-am introdus în interiorul unui private_tempstore variabil.

Aș dori să evit să apelez punctul final de rest în timpul apelurilor ajax și să mă bazez pe variabila stocată.

Cu toate acestea, nu găsesc o modalitate de a face diferența între cazul „încărcare pagină” și „cazul ajax”. Este posibil?

am gasit acest raspuns care pare să funcționeze în general:

// Exemplu doar pentru concizie, injectați serviciul request_stack și apelați 
// getCurrentRequest() pentru a obține obiectul de cerere dacă este posibil.
$cerere = \Drupal::cerere();
$is_ajax = $request->isXmlHttpRequest();

Dar aș dori să știu dacă există un ajutor/soluție care folosește formularul API.

drapel ru
IMHO, nicio logică de formă nu ar trebui să se bazeze vreodată pe încărcarea paginii vs. Ajax. Având în vedere că BigPipe din core ar putea încărca orice prin Ajax (sau nu), în funcție de plasarea blocului, mediu, configurație etc..., acesta pare un drum garantat către fiasco.
Giuseppe avatar
drapel br
@Hudri asta e o considerație importantă de care nu mi-am dat seama, mulțumesc. Cu toate acestea, există o altă modalitate de a rezolva această întrebare? Adică, aș dori să evit să fac un apel de odihnă extern pentru fiecare apel invers ajax al formularului.
drapel ru
TBH Nu prea înțeleg motivul întrebării. `buildForm` are acces la `FormStateInterface $form_state`, ce este în neregulă cu `$form_state`?
Giuseppe avatar
drapel br
@Hudri Voi încerca să reformulez: în timpul primei rulări a `buildForm`, datele de care am nevoie sunt obținute de la punctul final de rest, nu se află în `$form_state`. Apoi stochez acele date în `tempstore` (dar aș putea folosi și `$form_state->setTemporaryValue()`. În timpul următoarelor apeluri ajax, datele ar putea fi astfel accesate prin `$form_state`, dar evident că trebuie să fac diferența între primul caz si urmatoarele.
drapel ru
Cred că nu vezi lemnul pentru toți copacii :-) 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
drapel br
@Hudri da, nu am putut vedea acea soluție :facepalm: Cu toate acestea, acum că o încerc, `buildForm` este apelat de două ori în timpul apelului ajax - cel puțin în timpul depanării. Prima dată când valorile stării formularului sunt goale, așa că „lucrurile externe” sunt încă încărcate de fiecare dată, așa că nu funcționează cu adevărat :-(
Puncte:5
drapel cn

Din Drupal 8, obiectul formular instanțiat cu buildForm() nu este păstrat între cererea care redă formularul și prima cerere Ajax. Așa că fiți pregătiți că buildForm() este apelat din nou și trebuie să producă exact același rezultat. Când obțineți date de la $form_state, acestea nu sunt datele pe care le așteptați de la primul buildForm() deoarece acestea nu sunt niciodată memorate în cache. Adăugând la complexitate, rezultatul redat al primei build este stocat în cache, astfel încât ceea ce stocați în prima build în altă parte, de exemplu în tempStore, ar putea fi depășit în cererea Ajax. Singurele date care funcționează conform așteptărilor sunt valorile formularului, care pot fi ascunse dacă doriți să le aveți în formularul trimis și să nu fie vizibile pentru utilizator.

TLDR: buildForm() este apelat mai des decât credeți și nu ar trebui să puneți cod în el, care este costisitor de rulat. Refactorizează apelul API extern către un serviciu, cu memorarea în cache adecvată, astfel încât să nu conteze cât de des este apelat. Invalidați memoria cache a serviciului în același mod ca și formularul randat, astfel încât niciunul dintre ele să nu aibă date învechite.

Giuseppe avatar
drapel br
1. multumesc pentru explicatie, desi nu imi este chiar clar. De exemplu. Nu înțeleg cum datele stocate în tempStore pot fi depășite, dacă $form_state nu este stocat în cache și ce relație are rezultatul redat în cache cu asta. Există o documentație mai detaliată despre cum funcționează acest lucru pentru a obține o idee mai bună?
Giuseppe avatar
drapel br
2.„Invalidați memoria cache a serviciului în același mod ca și forma redată, astfel încât niciunul dintre ele să nu aibă date învechite.” Cum se poate face asta? Care ar trebui să fie „declanșatorul” pentru a invalida cache-ul serviciului? Adică, aș dori să fac asta la reîncărcarea paginii, ar trebui să folosesc un „KernelEvents::REQUEST” în căutarea acea rută specifică? Și pentru cache-ul de formulare, înseamnă asta că ar trebui să fac pur și simplu formularul să nu fie deloc stocabil în cache?
4uk4 avatar
drapel cn
1. Principala problemă este că încercați să utilizați buildform() în afara domeniului de aplicare. Cu aceeași intrare, trebuie să producă același rezultat de câte ori Drupal numește această metodă. Numai dacă $form_state conține valori de formular trimise și procesate sau un element de declanșare, puteți reconstrui un alt $form și stocați date.
4uk4 avatar
drapel cn
2. Adăugați un cache bin la serviciu și memorați cache cu aceleași metadate cache pe care le-ați atașat la $form redat.
4uk4 avatar
drapel cn
Dacă este esențial să utilizați aceeași versiune a datelor API externe, puteți adăuga un șir de versiune ca element de formular ascuns.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.