Pregled: kreiranje prilagođenog tipa polja
Ovaj tutorijal je prvobitno objavljen na Web Wash. Međutim, Berdir je pitao mogu li da postavim tutorijal ovde, pa je sada ovde.
Modul za Drupal 7 omogućava skladištenje primera koda/fragmenata u polju. Dolazi sa prilagođenim poljem pod nazivom „Field Snippets“ koje prikazuje tri elementa forme: opis, izvorni kod i režim isticanja sintakse (koji programski jezik).
Ali sada je vreme da se modul ažurira za Drupal 8.
U ovom tutorijalu pokazaću vam kako sam napravio „osnovno“ prilagođeno polje u Drupalu 8. Neću ulaziti u detalje o PSR-4, anotacijama ili plugin API-ju, jer bi tada tutorijal bio preopsežan.
Umesto toga, dodaću linkove ka drugim sajtovima koji detaljnije objašnjavaju ove koncepte.
Ako tražite detaljnu dokumentaciju o Field API-ju u Drupalu 8, pogledajte sledeće serije:
U Drupalu 8 polja se ne implementiraju korišćenjem hook funkcija kao u Drupalu 7. Umesto toga, kreiraju se preko novog Drupal 8 plugin API-ja. To znači da umesto hook-ova definišemo klase za vidžet, formatere i tipove polja. Većina hook-ova iz Drupala 7, kao što su hook_field_schema, hook_field_is_empty i drugi, sada su metode u klasama.
Korak 1: Implementacija elementa polja
Prvi korak je definisati klasu elementa polja pod imenom SnippetsItem koja nasleđuje klasu FieldItemBase.
1. U Drupalu 8 klase se automatski učitavaju preko PSR-4 standarda.
Zato, da definišemo klasu SnippetsItem, potrebno je kreirati fajl SnippetsItem.php u „modulu“ na putanji /src/Plugin/Field/FieldType/SnippetsItem.php
/** * @file * Contains \Drupal\snippets\Plugin\Field\FieldType\SnippetsItem. */ namespace Drupal\snippets\Plugin\Field\FieldType; use Drupal\Core\Field\FieldItemBase; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\TypedData\DataDefinition;
Zatim u fajl dodajemo namespace Drupal\snippets\Plugin\Field\FieldType i tri use naredbe:
- Drupal\Core\Field\FieldItemBase,
- Drupal\Core\Field\FieldStorageDefinitionInterface,
- Drupal\Core\TypedData\DataDefinition.
2. Sada treba definisati detalje polja, kao što su ID polja, labela, podrazumevani vidžet, formaterski plugin itd. Ovo je ekvivalent hook_field_info u Drupalu 7.
U Drupalu 8 mnogi, ako ne i svi, info hook-ovi su zamenjeni anotacijama.
/**
* Plugin implementacija tipa polja 'snippets'.
*
* @FieldType(
* id = "snippets_code",
* label = @Translation("Snippets field"),
* description = @Translation("Ovo polje čuva fragmente koda u bazi."),
* default_widget = "snippets_default",
* default_formatter = "snippets_default"
* )
*/
class SnippetsItem extends FieldItemBase { }
Dakle, umesto implementacije hook_field_info, definišemo polje kao anotaciju u PHP komentaru iznad klase.
Atributi anotacije su jasni, samo pazite da default_widget i default_formatter koriste ID-jeve vidžeta i formatera, a ne klase.
Ako želite da saznate više o anotacijama, posetite dokumentaciju o anotacijama plugina na drupal.org.
3. Sada kada imamo klasu elementa polja, treba definisati nekoliko metoda. Prvi je schema().
U Drupalu 7, kod kreiranja prilagođenog polja definisali smo njegovu šemu kroz hook_field_schema. U Drupalu 8 to radimo tako što dodajemo metodu schema() u klasu SnippetsItem.
Dokumentacija za schema API sadrži detalje o strukturi i opcijama šema niza.
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field) {
return [
'columns' => [
'source_description' => [
'type' => 'varchar',
'length' => 256,
'not null' => FALSE,
],
'source_code' => [
'type' => 'text',
'size' => 'big',
'not null' => FALSE,
],
'source_lang' => [
'type' => 'varchar',
'length' => 256,
'not null' => FALSE,
],
],
];
}
4. Sada treba dodati metodu isEmpty() i definisati šta znači prazan element polja. Ovo je ekvivalent hook_field_is_empty iz Drupala 7.
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value = $this->get('source_code')->getValue();
return $value === NULL || $value === '';
}
5. Poslednji metod koji dodajemo je propertyDefinitions().
/**
* {@inheritdoc}
*/
static $propertyDefinitions;
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['source_description'] = DataDefinition::create('string')
->setLabel(t('Opis fragmenta'));
$properties['source_code'] = DataDefinition::create('string')
->setLabel(t('Kod fragmenta'));
$properties['source_lang'] = DataDefinition::create('string')
->setLabel(t('Programski jezik'))
->setDescription(t('Jezik fragmenta koda'));
return $properties;
}
Ovaj metod definiše tipove podataka koje polje sadrži. „Snippets“ polje ima samo tri vrednosti: opis, kod i jezik, pa ih ovde definišemo kao stringove.
Za više informacija pogledajte kako Entity API implementira Typed Data API na drupal.org.
Kliknite ovde za ceo fajl. Napomena: fajl treba ažurirati da bude u skladu sa PSR-4 specifikacijom, više informacija na https://www.drupal.org/node/2128865
Korak 2: Implementacija vidžeta polja
Sada kada smo definisali element polja, kreiraćemo vidžet polja. Potreban nam je klasa SnippetsDefaultWidget koja nasleđuje WidgetBase.
1. Kreirajte fajl SnippetsDefaultWidget.php u „modulu“ na putanji /src/Plugin/Field/FieldWidget/SnippetsDefaultWidget.php.
/** * @file * Contains \Drupal\snippets\Plugin\Field\FieldWidget\SnippetsDefaultWidget. */ namespace Drupal\snippets\Plugin\Field\FieldWidget; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface;
Proverite da je namespace fajla Drupal\snippets\Plugin\Field\FieldWidget i dodajte sledeće use naredbe:
- Drupal\Core\Field\FieldItemListInterface
- Drupal\Core\Field\WidgetBase
- Drupal\Core\Form\FormStateInterface
2. Zatim definišite vidžet koristeći anotaciju, što je ekvivalent hook_field_widget_info u Drupalu 7.
/**
* Plugin implementacija vidžeta 'snippets_default'.
*
* @FieldWidget(
* id = "snippets_default",
* label = @Translation("Podrazumevani snippets"),
* field_types = {
* "snippets_code"
* }
* )
*/
class SnippetsDefaultWidget extends WidgetBase { }
Napomena: atribut field_types u anotaciji treba da koristi ID tipa polja. U ovom slučaju to je snippets_code, jer smo u @FieldType anotaciji definisali id = "snippets_code".
3. Na kraju, definišite formu vidžeta dodavanjem metode formElement() u klasu SnippetsDefaultWidget. Ovo je ekvivalent hook_field_widget_form u Drupalu 7.
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['source_description'] = [
'#title' => $this->t('Opis'),
'#type' => 'textfield',
'#default_value' => isset($items[$delta]->source_description) ? $items[$delta]->source_description : NULL,
];
$element['source_code'] = [
'#title' => $this->t('Kod'),
'#type' => 'textarea',
'#default_value' => isset($items[$delta]->source_code) ? $items[$delta]->source_code : NULL,
];
$element['source_lang'] = [
'#title' => $this->t('Izvorni jezik'),
'#type' => 'textfield',
'#default_value' => isset($items[$delta]->source_lang) ? $items[$delta]->source_lang : NULL,
];
return $element;
}
Kliknite ovde da vidite ceo fajl. Napomena: potrebno je ažurirati fajl da bude u skladu sa PSR-4, više informacija na https://www.drupal.org/node/2128865.
Korak 3: Implementacija formaterskog plugina za polja
Poslednji deo slagalice je formaterski plugin za polje, koji pravimo tako što definišemo klasu SnippetsDefaultFormatter koja nasleđuje FormatterBase.
1. Kreirajte fajl SnippetsDefaultFormatter.php u „modulu“ na putanji /src/Plugin/Field/FieldFormatter/SnippetsDefaultFormatter.php.
/** * @file * Contains \Drupal\snippets\Plugin\Field\FieldFormatter\SnippetsDefaultFormatter. */ namespace Drupal\snippets\Plugin\Field\FieldFormatter; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Field\FieldItemListInterface;
Proverite da je namespace fajla Drupal\snippets\Plugin\Field\FieldFormatter i dodajte sledeće use naredbe: Drupal\Core\Field\FormatterBase i Drupal\Core\Field\FieldItemListInterface.
2. Definišite formaterski plugin kao anotaciju, isto kao što smo uradili za vidžet i tip polja, što je ekvivalent hook_field_formatter_info u Drupalu 7.
/**
* Plugin implementacija formaterskog plugina 'snippets_default'.
*
* @FieldFormatter(
* id = "snippets_default",
* label = @Translation("Podrazumevani snippets"),
* field_types = {
* "snippets_code"
* }
* )
*/
class SnippetsDefaultFormatter extends FormatterBase { }
3. Sada dodajte metodu viewElements() i definišite stvarnu logiku formatiranja polja. Ovaj metod je ekvivalent hook_field_formatter_view u Drupalu 7.
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
foreach ($items as $delta => $item) {
// Renderovanje pomoću teme snippets_default.
$source = [
'#theme' => 'snippets_default',
'#source_description' => $item->source_description,
'#source_code' => $item->source_code,
];
$elements[$delta] = ['#markup' => drupal_render($source)];
}
return $elements;
}
Važno je napomenuti da koristim prilagođeni Twig šablon snippets_default za renderovanje fragmenata pre nego što ih formaterski plugin prikaže.
Razlog za to je što nisam želeo da puno logike ili HTML koda bude direktno u metodi viewElements().
Kliknite ovde da vidite ceo fajl. Napomena: fajl treba ažurirati da bude u skladu sa PSR-4, više informacija na https://www.drupal.org/node/2128865.
Zaključak
Kao što je ranije pomenuto, najveća promena u Drupalu 8 je to što se polja kreiraju preko plugin API-ja, a ne preko hook-ova. Kada ovo razumete, koncept kreiranja polja je vrlo sličan kao u Drupalu 7. Mnogi metodi u Drupalu 8 odgovaraju hook-ovima iz Drupala 7.
Ako želite da testirate Snippets modul, preuzmite 8.x-dev verziju i probajte.