9.8.1. hook_form_alter() dodavanje submit i validate funkcija za postojeći formular.
U jednoj od prethodnih lekcija smo naučili šta su hook-ovi, a u ovoj lekciji ćemo raditi sa hook_form_alter() hook-ovima u praksi i dodati funkcionalnost postojećem formularu.
Primere koda možete pronaći na github-u:
https://github.com/levmyshkin/drupalbook8
U ovoj lekciji ćemo početi da gledamo hook-ove u praksi, kasnije ćemo se vratiti hook-ovima i pogledati još nekoliko primera. Za sada, hajde da počnemo sa hook_form_alter().
Da bismo dodali hook u modul, potrebno je da napravimo fajl nazvan MODULENAME.module, tako da ćemo napraviti fajl drupalbook.module. Ovo će biti PHP fajl u kome će se čuvati naši hook-ovi i pomoćne funkcije, za ostalo je bolje koristiti posebne fajlove i klase u src folderu. Za sada u fajl možete dodati samo početni tag
Sada dodajmo hook_form_alter(). Ako koristite PhpStorm, počnite da kucate ime hook-ova i PhpStorm će vam ponuditi da izaberete jedan od hook-ova. Kada ovako izaberete hook, PhpStorm automatski ubacuje argumente u funkciju i nije potrebno da pamtite ili gledate u pomoć koji argumenti su potrebni:
Kada želite da dodate hook, potrebno je da zamenite reč hook imenom vašeg modula, i onda Drupal automatski umeće vaš kod na mesto hook-a. Kao rezultat, trebalo bi da imate ovu funkciju:
/**
* Implements hook_form_alter().
*/
function drupalbook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
}
U prethodnoj lekciji smo već videli da će u $form i $form_state biti sačuvani podaci o formi, a u $form_id će biti ID formulara koji smo definisali u odgovarajućoj metodi:
9.8. Rad sa formularima u Drupalu. Dodavanje konfiguracionog formulara programatski.
Sada proširimo formular za dodavanje API ključeva koji smo napravili u prethodnoj lekciji. Da bismo to uradili, treba da definišemo form_id, što možete videti u ovoj metodi:
function getFormId() {
return 'drupalbook_admin_settings';
}
Ili otvorite DOM inspektor i pogledajte id atribut u HTML-u:
Ovde treba da zamenite - (crte) sa _ (donjim crticama). Ali budite pažljivi, id u form tag atributu može biti inkrementiran posle AJAX zahteva, na primer drupalbook-admin-settings-0, drupalbook-admin-settings-1, drupalbook-admin-settings-2 i slično. Nama je potrebna samo osnovna vrednost bez broja na kraju, a to je vrednost form_id koju smo definisali u metodi getFormId().
Sada treba da ograničimo izvršenje našeg koda samo na formu drupalbook_admin_settings, jer će kod koji je u hook_form_alter() biti izvršen za sve forme koje se generišu preko Drupal Form API-ja:
if ($form_id == 'drupalbook_admin_settings') {
// Dalji kod ovde.
}
Unutar if uslova možemo napisati naš kod za API ključ formular. Dodajmo placeholder-e za tekstualna polja da prazna polja pokažu šta treba uneti:
if ($form_id == 'drupalbook_admin_settings') {
$form['drupalbook_api_key']['#attributes']['placeholder'] = 'API key';
$form['drupalbook_api_client_id']['#attributes']['placeholder'] = 'API client ID';
}
Da bi se primenio hook_form_alter(), očistite keš.
Iako #attributes nisu eksplicitno navedeni u dokumentaciji kao mogući ključ za tekst polje:
https://api.drupal.org/api/drupal/core%2
Ovaj ključ se i dalje može koristiti za definisanje atributa taga: class, placeholder, različitih rel-atributa. Jasnija tabela postoji za Drupal 7 Form API:
https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7.x
Tamo možete pronaći #attributes za tekstualna polja.
Vrednosti atributa se postavljaju u Form API-ju prilikom generisanja (renderovanja) elementa forme u metodi setAttributes:
Iako ovo nije jasno navedeno u dokumentaciji Form API-ja, možete se uveriti da funkcioniše.
Takođe možete videti koje druge vrednosti možete postaviti za polja forme u osnovnoj FormElement klasi:
https://api.drupal.org/api/drupal/core%21lib%2
Drupal Form API može delovati nejasno i zbunjujuće, i jeste takav, i ja još uvek ne razumem neke stvari u njemu. Ali korišćenje ovog API-ja je prilično jednostavno i jasno, ako imate radni primer pri ruci. Zato, ako imate pitanja i ne znate kako da uradite nešto u formi, potražite na internetu i sigurno ćete pronaći 100% radni primer. Treba da znate da svi formulari prolaze kroz Drupal Cache, Render, Theming API-je, i bilo koje polje u formi možete izmeniti preko hook_form_alter(), a kako se to radi možete saznati preko Google-a. Što više radite sa Form API-jem i što više proučavate primere, to će vam ovaj API biti jednostavniji i jasniji. I ne brinite zbog njegove veličine, koristite samo deo koji vam je trenutno potreban.
Validacija
Sada ćemo pogledati kako se koriste validate funkcije preko Form API-ja. Proverićemo polje API ključa da li počinje sa rečju google, na primer google-KEY123a3sa. Kada pišemo kod za naš formular, mogli bismo odmah ubaciti metodu validateForm() i obaviti sve provere u njoj:
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
}
Ali često se dešava da su forme sa kojima radimo u dodatnim modulima, pa je bolje da kod za takve forme pišemo u prilagođenim modulima. Zato ćemo dodati novu validate funkciju formi:
['#validate'][] = 'drupalbook_settings_validate';
U nizu #validate čuvamo sve callback-ove i validacione funkcije. Callback je poziv funkcije po imenu, tj. dodajemo niz ['callback_function1', 'callback_function2'], Drupal zatim poziva te funkcije da proveri formu. Sada treba da kreiramo funkciju drupalbook_settings_validate u fajlu drupalbook.module. Ova funkcija prima parametre $form i $form_state:
/**
* Prilagođena validaciona funkcija.
*/
function drupalbook_settings_validate(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
}
Sada ćemo dodati proveru samog polja API ključa:
/**
* Prilagođena validaciona funkcija.
*/
function drupalbook_settings_validate(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
if (strpos($form_state->getValue('drupalbook_api_key'), 'google') === FALSE) {
$form_state->setErrorByName('drupalbook_api_key', t('API ključ mora početi sa "google".'));
}
}
Koristimo strogu proveru (===), zato što ako je google na početku stringa, strpos() vraća 0, a u PHP (0 == FALSE) daje TRUE, jer u PHP su '', 0, NULL, FALSE prazne vrednosti i u jednostavnoj proveri su jednake.
Sada će se svaki put kada sačuvate podešavanja izvršiti provera, i ako provera ne uspe, Drupal će prikazati grešku i podešavanja neće biti sačuvana:
Submit
Nakon što sve validacione funkcije prođu bez grešaka, Drupal poziva submit funkcije koje rade nakon slanja podataka iz forme. Već ste videli metodu submitForm() u prethodnoj lekciji gde sačuvamo podatke u konfiguraciju. Ali možemo izvršiti i druge radnje prilikom submit-a, na primer menjati podatke ili sačuvati podatke u druge entitete. Napravićemo još jednu submit funkciju koja će prikazati dodatnu poruku kako koristiti API ključ. U hook_form_alter() dodajemo ime funkcije:
['#submit'][] = 'drupalbook_settings_submit';
Sada u funkciji drupalbook_settings_submit(), koja takođe prima $form i $form_state kao parametre, prikazaćemo poruku.
/**
* Prilagođena submit funkcija.
*/
function drupalbook_settings_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
\Drupal::messenger()->addStatus(
t(htmlentities('Ubaci API ključ unutar svog <script> taga: </script>.'))
);
}
Koristimo funkciju htmlentities() da bismo bili sigurni da svi specijalni karakteri koje koristimo za prikaz "<", "/", ">" tagova neće biti obrisani od strane Drupala. Sav HTML tekst izvlačimo iz t() funkcije, jer ako bi u tekstu bio na primer JavaScript za preusmeravanje na drugi sajt, on bi se izvršio pri prikazu poruke. Zato koristimo htmlentities da bi tagovi bili prikazani kao tekst.
Poruka se neće prikazati ako validacione funkcije nisu prošle, poruku vidimo samo kada nema grešaka u formi.
Ranije se u Drupalu koristila funkcija drupal_set_message za prikaz poruka:
(t('Došlo je do greške i proces nije završen.'));
Ali sada svi teže ka jedinstvenom korišćenju OOP pristupa svuda.
Ispod je kompletan trenutni kod fajla drupalbook.module:
/**
* Implements hook_form_alter().
*/
function drupalbook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if ($form_id == 'drupalbook_admin_settings') {
$form['drupalbook_api_key']['#attributes']['placeholder'] = 'API key';
$form['drupalbook_api_client_id']['#attributes']['placeholder'] = 'API client ID';
$form['#validate'][] = 'drupalbook_settings_validate';
$form['#submit'][] = 'drupalbook_settings_submit';
}
}
/**
* Prilagođena validaciona funkcija.
*/
function drupalbook_settings_validate(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
if (strpos($form_state->getValue('drupalbook_api_key'), 'google') === FALSE) {
$form_state->setErrorByName('drupalbook_api_key', t('API ključ mora početi sa "google".'));
}
}
/**
* Prilagođena submit funkcija.
*/
function drupalbook_settings_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
// drupal_set_message je zastareo
// drupal_set_message(t('Došlo je do greške i proces nije završen.'));
\Drupal::messenger()->addStatus(
t(htmlentities('Ubaci API ključ unutar svog <script> taga: </script>.'))
);
}
Time završavamo našu lekciju o Form API-ju, ali time ne završavamo učenje o Form API-ju, još ćemo se susretati sa validate, submit funkcijama i raznim poljima. Takođe ćemo u nekoj od lekcija razumeti kako koristiti AJAX i form_state kroz Form API.
Primere koda možete pronaći na github-u:
https://github.com/levmyshkin/drupalbook8