9.10.3. Werken met velden in Drupal. Maak je eigen veldtype, widget en formatter voor het invoegen van video's van YouTube.
In eerdere artikelen hebben we gezien hoe het veldtype Link werkt: Storage, Widget, Formatter. In dit artikel gaan we ons eigen veldtype maken voor het weergeven van een YouTube-video op een pagina, met twee verschillende weergaveformaten en instellingen.
Dit artikel richt zich op de Fields API, en als je gewoon een YouTube-videoveld aan je site wilt toevoegen, kun je beter de kant-en-klare module gebruiken:
https://www.drupal.org/project/video_embed_field
Ik heb alle code op GitHub toegevoegd in de module drupalbook_youtube; je kunt de module downloaden en aan je site toevoegen:
https://github.com/levmyshkin/drupalbook8
Laten we de bestanden van deze module bekijken, en ik zal proberen uit te leggen hoe dit type veld werkt:
modules/custom/drupalbook_youtube/drupalbook_youtube.info.yml
name: DrupalBook Youtube
type: module
description: Youtube embed field
core: 8.x
package: Custom
We bepalen hiermee de metadata van de module.
modules/custom/drupalbook_youtube/src/Plugin/Field/FieldType/DrupalbookYoutubeItem.php
<?php
namespace Drupal\drupalbook_youtube\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
/**
* Plugin implementation of the 'drupalbook_youtube' field type.
*
* @FieldType(
* id = "drupalbook_youtube",
* label = @Translation("Embed Youtube video"),
* module = "drupalbook_youtube",
* description = @Translation("Output video from Youtube."),
* default_widget = "drupalbook_youtube",
* default_formatter = "drupalbook_youtube_thumbnail"
* )
*/
class DrupalbookYoutubeItem extends FieldItemBase {
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return array(
'columns' => array(
'value' => array(
'type' => 'text',
'size' => 'tiny',
'not null' => FALSE,
),
),
);
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value = $this->get('value')->getValue();
return $value === NULL || $value === '';
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['value'] = DataDefinition::create('string')
->setLabel(t('Youtube video URL'));
return $properties;
}
}
We maken een veldtype aan zodat Drupal weet wat er in de tabel voor dit veld zal worden opgeslagen.
<?php
namespace Drupal\drupalbook_youtube\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
Definieer namespaces voor ons veldtype.
/**
* Plugin implementation of the 'drupalbook_youtube' field type.
*
* @FieldType(
* id = "drupalbook_youtube",
* label = @Translation("Embed Youtube video"),
* module = "drupalbook_youtube",
* description = @Translation("Output video from Youtube."),
* default_widget = "drupalbook_youtube",
* default_formatter = "drupalbook_youtube_thumbnail"
* )
*/
We schrijven een abstract voor onze klasse; vanuit deze abstractie zal Drupal de naam en machine-naam van ons veldtype afleiden.
class DrupalbookYoutubeItem extends FieldItemBase {
De naam van de klasse eindigt bij voorkeur op Item.
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return array(
'columns' => array(
'value' => array(
'type' => 'text',
'size' => 'tiny',
'not null' => FALSE,
),
),
);
}
We definiëren dat we de waarde van het veld als tekst zullen opslaan.
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value = $this->get('value')->getValue();
return $value === NULL || $value === '';
}
Als er een aanroep van dit veld plaatsvindt vanuit externe code, geven we een lege waarde terug voor het geval het veld leeg is.
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['value'] = DataDefinition::create('string')
->setLabel(t('Youtube video URL'));
return $properties;
}
We beschrijven onze kolommen voor de MySQL-tabel en het entiteitsobject. Als resultaat slaan we de volledige link op:
Nu we het veldtype hebben toegevoegd, maken we een Widget om gegevens in te voeren:
modules/custom/drupalbook_youtube/src/Plugin/Field/FieldWidget/DrupalbookYoutubeWidget.php
<?php
namespace Drupal\drupalbook_youtube\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Plugin implementation of the 'drupalbook_youtube' widget.
*
* @FieldWidget(
* id = "drupalbook_youtube",
* module = "drupalbook_youtube",
* label = @Translation("Youtube video URL"),
* field_types = {
* "drupalbook_youtube"
* }
* )
*/
class DrupalbookYoutubeWidget extends WidgetBase {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$value = isset($items[$delta]->value) ? $items[$delta]->value : '';
$element += array(
'#type' => 'textfield',
'#default_value' => $value,
'#size' => 32,
'#maxlength' => 256,
'#element_validate' => array(
array($this, 'validate'),
),
);
return array('value' => $element);
}
/**
* Validate the color text field.
*/
public function validate($element, FormStateInterface $form_state) {
$value = $element['#value'];
if (strlen($value) == 0) {
$form_state->setValueForElement($element, '');
return;
}
if(!preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+(?=\?)|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $value, $matches)) {
$form_state->setError($element, t("Youtube video URL is not correct."));
}
}
}
De widget maakt het mogelijk om gegevens in te voeren op het bewerkingsformulier van de entiteit.
/**
* Plugin implementation of the 'drupalbook_youtube' widget.
*
* @FieldWidget(
* id = "drupalbook_youtube",
* module = "drupalbook_youtube",
* label = @Translation("Youtube video URL"),
* field_types = {
* "drupalbook_youtube"
* }
* )
*/
In de annotatie bij de klasse moeten we het field_type vermelden dat we eerder hebben aangemaakt, namelijk drupalbook_youtube.
class DrupalbookYoutubeWidget extends WidgetBase {
Aan het einde van de klassenaam voegen we Widget toe, zodat duidelijk is dat deze klasse bedoeld is als Field Widget.