logo

Dodatni tipovi blokova (EBT) - Novo iskustvo rada sa Layout Builder-om❗

Dodatni tipovi blokova (EBT) – stilizovani, prilagodljivi tipovi blokova: slajdšouvi, kartice sa tabovima, kartice, akordeoni i mnogi drugi. Ugrađena podešavanja za pozadinu, DOM Box, javascript dodatke. Iskusite budućnost kreiranja rasporeda već danas.

Demo EBT moduli Preuzmite EBT module

❗Dodatni tipovi pasusa (EPT) – Novo iskustvo rada sa pasusima

Dodatni tipovi pasusa (EPT) – analogni skup modula zasnovan na pasusima.

Demo EPT moduli Preuzmite EPT module

Scroll

TipoviPolja, VidžetiPolja i FormatatoriPolja

18/06/2025, by Ivan

Pregled

Drupal 8 dolazi sa velikom bibliotekom osnovnih klasa koje vam omogućavaju da radite sa sopstvenim sadržajem. Kada su u pitanju entiteti sadržaja, želite da koristite polja. Važno je razumeti polja, jer tu vaši entiteti čuvaju svoje podatke.

Tipovi polja (FieldTypes)

Osnovni tipovi polja:

 

Tipovi prilagođenih polja
Kad god želite da prikažete podatke na način koji Drupal ne pruža, možda ćete želeti da napravite novi tip polja za svoje podatke.

Recimo da imate entitet sadržaja koji sadrži poverljive podatke. Kreator tog sadržaja može dozvoliti određenim korisnicima pristup entitetu putem lozinke koja je različita za svakog korisnika. Ako govorimo u terminima tabela baze podataka, želeli bismo nešto ovako:

| entity_id | uid | password      |
-----------------------------------
| 1         | 1   | 'helloworld'  |
| 1         | 2   | 'goodbye'     |

Kao što vidite, naš entitet sa ID-jem 1 ima dve različite lozinke za dva različita korisnika. Kako to možemo realizovati u Drupalu, a da ne pravimo tabelu ručno? Napravićemo novi tip polja.

Pošto Drupal implementira logiku polja kao Plugin, uvek postoji osnovna klasa od koje možemo naslediti da bi polje radilo u Drupalu. Za novi tip polja treba da kreirate sledeću strukturu foldera u vašem modulu:
modules/custom/MODULENAME/src/Plugin/Field/FieldType
Ovaj put je prilično dug i malo zamoran, ali Drupal olakšava rad sa svim različitim funkcionalnostima koje mogu koegzistirati u vašim modulima.

Za naš primer kreiraćemo fajl EntityUserAccessField.php

namespace Drupal\MODULENAME\Plugin\Field\FieldType;
     
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
     
/**
 * @FieldType(
 *   id = "entity_user_access",
 *   label = @Translation("Entity User Access"),
 *   description = @Translation("Ovo polje čuva referencu na korisnika i lozinku za tog korisnika na entitetu."),
 * )
*/
     
class EntityUserAccessField extends FieldItemBase {
  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    //ToDo: Implementirati.
  }
     
  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    //ToDo: Implementirati.
  }
}

Kao što vidite, tip polja je vrlo sličan entitetu sadržaja. Zapravo, nema razlike između ova dva, ali to je tema za drugi čvor ;)

Pre svega, imamo anotaciju za naš tip polja:

  • @FieldType: poziva anotacionu klasu FieldType iz Drupal biblioteke
  • id: ovo je mašinsko ime našeg tipa polja, da bismo ga mogli koristiti više puta. Pazite da ne preklapate već postojeća imena iz PHP-a i slično.
  • label: ovo može biti korisnički čitljiv prevod mašinskog imena.
  • description: ako oznaka nije dovoljna, možete dodati i opis tipa polja.

 

Drugo, naša klasa nasleđuje FieldItemBase, što nas primorava da implementiramo dve metode da bismo pravilno koristili ovaj tip polja:

  • propertyDefinitions(): ova metoda je slična baseFieldDefinition entiteta sadržaja (ali nije isto!). Ovde definišemo podatke koji će se pojavljivati u formama entiteta gde se koristi ovaj tip polja.
  • schema(): kod entiteta ova metoda je zastarela, ali je još uvek prisutna kod polja. Ova metoda treba da definiše kako su podaci polja predstavljeni u bazi. Može se razlikovati od propertyDefinitions.

Pošto nije baš jasno šta se piše u ove metode, dodaćemo malo koda za primer.

public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
  $properties['uid'] = DataDefinition::create('integer')
      ->setLabel(t('Referenca na korisnički ID'))
      ->setDescription(t('ID referenciranog korisnika.'))
      ->setSetting('unsigned', TRUE);

  $properties['password'] = DataDefinition::create('string')
      ->setLabel(t('Lozinka'))
      ->setDescription(t('Lozinka sačuvana u čistom tekstu. To nije bezbedno, druže!'));

  $properties['created'] = DataDefinition::create('timestamp')
    ->setLabel(t('Vreme kreiranja'))
    ->setDescription(t('Vreme kada je unos kreiran'));

    // ToDo: Dodati još svojstava.
 
    return $properties;
}

Moguće je i sačuvati ID korisnika preko DataReferenceDefinition, što se može razmotriti u budućnosti.

public static function schema(FieldStorageDefinitionInterface $field_definition) {
  $columns = array(
    'uid' => array(
      'description' => 'ID referenciranog korisnika.',
      'type' => 'int',
      'unsigned' => TRUE,
    ),
    'password' => array(
      'description' => 'Lozinka u čistom tekstu.',
      'type' => 'varchar',
      'length' => 255,
    ),
    'created' => array(
      'description' => 'Timestamp kada je ovaj unos kreiran.',
      'type' => 'int',
    ),

    // ToDo: Dodati još kolona.
  );
 
  $schema = array(
    'columns' => $columns,
    'indexes' => array(),
    'foreign keys' => array(),
  );

  return $schema;
}

Schema() je potrebna da bi Drupal znao kako da sačuva naše podatke. Kolone u schemi treba da budu podskup svojstava definisanih u propertyDefinitions().

Sada imamo potpuno novi tip polja. On nema nikakvu logiku za obradu unosa podataka, ali se može koristiti u bilo kom entitetu sadržaja kao polje. Ako želite, možete ga koristiti kao baseField za entitet:

public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
  // Neki drugi fieldovi gore.
 
  $fields['entity_user_access'] = BaseFieldDefinition::create('entity_user_access')
    ->setLabel(t('Entity User Access'))
    ->setDescription(t('Odredite lozinke za bilo kog korisnika koji želi da vidi ovaj entitet.'))
    ->setCardinality(-1); // Omogućava da imate više od jednog člana
 
  // Još polja ispod.
 
  return $fields;
}
  • BaseFieldDefinition::create(): treba da koristite mašinsko ime tipa polja u create()
  • setCardinality(-1): broj elemenata predstavlja koliko vrednosti polja može imati jedan entitet. Na primer, ako postavite 2, samo dva korisnika mogu imati pristup entitetu, 3 znači tri korisnika itd. -1 znači neograničen broj korisnika.

 

Vidžet polja (FieldWidget)

Ako imate prilagođene podatke, možda će vam trebati prilagođeni prikaz tih podataka. Vidžeti se koriste za predstavljanje načina na koji korisnik može uneti te prilagođene podatke u forme. Na primer:

  • ako u formi treba da unesete ceo broj, ali korisnik može da označi samo checkbox
  • ako želite automatsko popunjavanje za vaše podatke
  • ako se unos lozinke vrši kroz specijalni grafički interfejs

i slično.

Vidžet polja u Drupalu možete pronaći pod
modules/custom/MODULENAME/src/Plugin/Field/FieldWidget
ovo je takođe veoma dug put. Do sada bi trebalo da vam bude jasno zašto Drupal koristi ovaj stil za organizaciju .php fajlova. Lako je znati koji fajl gde pripada.

Kreiraćemo vidžet polja u EntityUserAccessWidget.php

namespace Drupal\MODULENAME\Plugin\Field\FieldWidget;
 
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
 
/**
 * Implementacija plugina za vidžet 'entity_user_access_w'.
 *
 * @FieldWidget(
 *   id = "entity_user_access_w",
 *   label = @Translation("Entity User Access - Widget"),
 *   description = @Translation("Entity User Access - Widget"),
 *   field_types = {
 *     "entity_user_access",
 *   },
 *   multiple_values = TRUE,
 * )
 */
 
class EntityUserAccessWidget extends WidgetBase {
  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    // ToDo: Implementirati.
  }
}

Već ste primetili? Drupal 8 koristi ovaj stil koda iznova i iznova ako želite da implementirate funkcionalnost. Postoji anotacija i osnovna klasa koju treba naslediti. Da, Drupal može da koristi ovo!

  • @FieldWidget: definiše anotacionu klasu
  • id: mašinsko ime vidžeta
  • field_types: niz mašinskih imena tipova polja koje ovaj vidžet može koristiti
  • multiple_values: podrazumevano FALSE. Ako je TRUE, omogućava vam unos više vrednosti u formi entiteta

Ako sada želite da koristite ovaj vidžet sa svojim tipom polja, potrebno je da izmenite anotaciju tipa polja na sledeći način:

// ...

/**
 * @FieldType(
 *   id = "entity_user_access",
 *   label = @Translation("Entity User Access"),
 *   description = @Translation("Ovo polje čuva referencu na korisnika i lozinku za tog korisnika na entitetu."),
 *   default_widget = "entity_user_access_w",
 * )
 */
 
// ...

Gotovo! Ne, sačekajte, još se ništa ne dešava jer treba da implementiramo formElement() u našem vidžetu.

public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element['userlist'] = array(
      '#type' => 'select',
      '#title' => t('Korisnik'),
      '#description' => t('Izaberite članove grupe sa liste.'),
      '#options' => array(
         0 => t('Anoniman'),
         1 => t('Administrator'),
         2 => t('foobar'),
         // Ovo treba implementirati na bolji način!
       ),
  
    );
  
    $element['passwordlist'] = array(
      '#type' => 'password',
      '#title' => t('Lozinka'),
      '#description' => t('Izaberite lozinku za korisnika'),
    );

    // Podesite podrazumevane vrednosti za sva polja iznad
    $childs = Element::children($element);
    foreach ($childs as $child) {
        $element[$child]['#default_value'] = isset($items[$delta]->{$child}) ? $items[$delta]->{$child} : NULL;
    }
   
    return $element;
}

Ako sada otvorite formu sa ovim vidžetom, videćete najmanje dva polja za unos. Jedno je izbor korisnika, drugo je polje za lozinku. Ako želite da implementirate način čuvanja podataka, potrebno je da implementirate validaciju u ovom vidžetu ili u formi entiteta. Pogledajte Drupal 8 Form API za više informacija.

Do sada ste odradili većinu posla sa prilagođenim poljem. Ako ne razumete šta se dešava, jednostavno probate kod ili pogledajte osnovne module za dublje razumevanje teme.

Formatatori polja (FieldFormatters)

Poslednji deo slagalice je prikaz podataka u tzv. režimu pregleda entiteta – vidžet je u stvari režim forme. Ovo se najčešće dešava kada pristupite entitetu preko yourdrupalpage.com/myentity/1/view

Pošto ovde nema mnogo priče, preći ćemo direktno na kod. U folderu modules/custom/MODULENAME/src/Plugin/Field/FieldFormatter kreirajte fajl EntityUserAccessFormatter.php

namespace Drupal\MODULENAME\Plugin\Field\FieldFormatter;
     
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
     
/**
 * Implementacija plugina za formatter 'entity_user_access_f'.
 *
 * @FieldFormatter(
 *   id = "entity_user_access_f",
 *   label = @Translation("Entity User Access - Formatter"),
 *   description = @Translation("Entity User Access - Formatter"),
 *   field_types = {
 *     "entity_user_access",
 *   }
 * )
 */
     
class EntityUserAccessFormatter extends FormatterBase {
  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = array();
     
    foreach ($items as $delta => $item) {
      $elements[$delta] = array(
        'uid' => array(
          '#markup' => \Drupal\user\Entity\User::load($item->uid)->getUsername(),
          ),
        // Dodajte još sadržaja
      );
    }
     
    return $elements;
  }
}

Ovaj primer ima vrlo sličnu anotaciju kao vidžet, pa nema mnogo šta da se kaže. viewElements() samo prikazuje korisničko ime za sačuvani ID korisnika iz našeg tipa polja. Implementacija pristupa treba da se izvrši na nivou entiteta. Ova implementacija će prikazati sva korisnička imena korisnika koji imaju lozinku za entitet.

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.