Programista na ławce

Niestandardowe formularze encji na przykładzie edycji i rejestracji użytkowników

Korzystając z CMS Drupal wiele elementów potrzebnych do realizacji projektu możemy otrzymać bez napisania choćby jednej linii kodu. Kiedy jednak chcemy wyświetlić np. formularz edycji użytkownika w niestandardowy sposób, wtedy taki komponent musi zostać poddany pewnym pracom programistycznym. W artykule tym opowiem w jaki sposób zarejestrować i wyświetlić niestandardowe tryby wyświetlania formularzy encji w Drupalu i jak może to przydać się w realizacji Twojego projektu.

Drupal od wersji 8 wprowadził jedną z ważnych funkcjonalności jaką są tryby wyświetlania formularza encji. W zasadzie dla każdej encji opartej o pola, a zatem tych które implementują interfejs Drupal\Core\Entity\FieldableEntityInterface można skonfigurować pola na domyślnym formularzu. Można również dodać nowy tryb wyświetlania formularza i aktywować go na wybranej encji bezpośrednio w panelu administracyjnym.

W prezentowanym przykładzie będę korzystał z nowej eksperymentalnej skórki administracyjnej Claro.

Konfiguracja wstępna w interfejsie użytkownika

Każda z encji (jak np. wbudowane encje - node, taxonomy, user) posiada wbudowany mechanizm zarządzania wyświetlaniem formularza. Dla encji typu user trafimy na taki formularz poprzez przejście na adres:

/admin/config/people/accounts/form-display

Poza domyślnym trybem wyświetlania możemy skorzystać z niestandardowych trybów wyświetlania poprzez aktywację wybranych trybów w dolnej sekcji:

Niestanrdowe tryby formularza

Jeżeli wasza lista jest pusta to oznacza, że nie zarejestrowaliście w CMS jeszcze żadnego niestandardowego trybu dla waszej encji. Możecie to zrobić przechodząc do formularza znajdującego się pod adresem:

/admin/structure/display-modes/form/add

Następnie klikamy w nazwę encji, która nas interesuje. W naszym przykładzie będzie to użytkownik:

Tryby formularza  

Na następnym formularzu podajemy jedynie etykietę i nazwę maszynową.

Rejestrowanie trybu formularza

Domyślnie w Drupalu nie jesteśmy w stanie w łatwy sposób wyświetlić formularz encji po jego utworzeniu i odblokowaniu w interfejsie użytkownika. Musimy jawnie "powiedzieć" naszej encji jaka klasa będzie odpowiedzialna za obsługę wyświetlania naszego formularza. Do wykorzystania mamy dwa hooki: hook_entity_type_build i hook_entity_type_alter.

Przykładowa implementacja hooku dla encji użytkownika może zatem wyglądać tak:

/**
 * Implements hook_entity_type_build().
 */
function my_module_entity_type_build(array &$entity_types) {
  $form_modes = ['custom_form_mode_1', 'custom_form_mode_2'];

  foreach ($form_modes as $mode) {
    $entity_types['user']->setFormClass($mode, 'Drupal\user\ProfileForm');
  }
}

Większość wbudowanych encji posiada już swoje klasy do obsługi formularzy i możemy z powodzeniem je wykorzystywać. Ważne jest, aby nasza klasa rozszerzała klasę:

namespace Drupal\Core\Entity\ContentEntityForm;

 

Własna strona z formularzem

W celu wyświetlenia niestandardowego formularza encji jako samodzielnej strony z formularzem, mamy możliwość stworzenia własnego routingu, który automatycznie obsłuży jego załadowanie. Kluczowe znaczenie ma ustawienie w jego konfiguracji wartości _entity_form, dzięki której odszukana zostanie właściwa klasa odpowiedzialna za wygenerowanie struktury formularza.
Przykładowa konfiguracja routingu dla strony z formularzem użytkownika mogłaby wyglądać następująco:

my_custom_module.user.edit_form:
 path: '/user/{user}/custom-form-mode-1'
 defaults:
   _entity_form: user.custom_form_mode_1
   _title: 'User entity custom form mode 1'
 requirements:
   _permission: 'required permission goes here' 

Nie potrzeba deklarowania żadnego dodatkowego kontrolera lub osobnego formularza.

Samodzielne ładowanie formularza

Często wyświetlenie formularza encji na osobnej stronie nie spełnia oczekiwań projektowych. Dlatego potrzebne są mechanizmy do załadowania go w innych przypadkach, np. jako treść bloku lub element jakiegoś wbudowanego, lub własnego szablonu. W przypadku encji użytkowników może być to jakiś prosty formularz edycji awatara lub danych profilowych do wyświetlenia, np. w bloku.
Aby osiągnąć założony rezultat należy wykonać kilka kroków, które w dużo większym uogólnieniu wykonają w zasadzie podobne operacje, jak te które niejawnie wykonywane są w przypadku wyświetlania własnej strony na podstawie routingu.
Na początek będziemy potrzebować jednego z najczęściej używanego serwisu do zarządzania typami encji:

$entityTypeManager = \Drupal::entityTypeManager();

Oczywiście zalecam wstrzyknięcie serwisu, jeżeli implementacja znajduje się w ciele klasy.
Manager ten jest wstanie zwrócić nam odpowiednią klasę odpowiedzialną za wyświetlania formularza implementującą \Drupal\Core\Entity\EntityFormInterface poprzez przekazanie parametru id typu encji  i trybu formularza.

$entity_type_id = 'user';
$form_mode = 'my_custom_form_mode_2';
$userForm = $entityTypeManager->getEntityForm($entity_type_id, $form_mode);

Następnie musimy poinformować nasz formularz encji nad jaką konkretną instancją tego typu encji będziemy pracować. Możemy zarówno załadować istniejącą encję, jak i utworzyć nową:

$existingUser = $entityTypeManager->getStorage('user')->load($user_id);
// or
$newUser = $entityTypeManager->getStorage('user')->create();

a następnie ustawić ją jako encję formularza:

$userForm->setEntity($existingUser);
// or
$userForm->setEntity($newUser);

Posiadając tak przygotowany obiekt formularza encji możemy nareszcie zbudować na jego podstawie strukturę finalnego formularza z wykorzystaniem serwisu \Drupal::formBuilder().

$form = \Drupal::formBuilder()->getForm($userForm);

Formularz taki jest tablicą nadającą się już do bezpośredniego wyrenderowania w dowolnym miejscu w naszym kodzie, zgodnie z dokumentacją metody getForm z interfejsu Drupal\Core\Form\FormBuilderInterface.

Przydatne moduły

W ekosystemie Drupala, nie ma zbyt wielu modułów, które ułatwiają rozwiązanie rozważanego przez nas problemu. Jednym z nich jest moduł Entityform block, który pozwala na wyświetlenie formulrza wybranej encji w bloku. Innym modułem, już tylko pośrednio rozwiązującym problem jest Inline Entity Form, który dostarcza widżet pozwalający na wyświetlenie pola z referencją do encji jako formularz encji. Warto też nadmienić moduł Paragraphs, który również dostarcza widżet do wyświetlenia formularza dla pola z referncją do encji paragraph.

Podsumowanie

Niestandardowe formularze encji to niezwykle wygodna funkcjonalność, jednakże nadal wymagająca pewnego nakładu pracy ze strony programistów Drupala. Na szczęscie okazuje się, że wiele gotowych mechanizmów pozwala osiągnać nam zamierzony efekt za pomocą krótkiej konfiguracji pliku .yml lub kilku linijek kodu. Implementacja takiego formularza na dedykowanej stronie czy w postaci własnego bloku nie powinna zatem przysparzać już żadnych większych problemów. A zatem, powodzenia!

3. Najlepsze praktyki zespołów programistycznych