9.10.3. Arbeiten mit Feldern in Drupal. Erstellen Sie Ihren eigenen Feldtyp, Widget und Formatter zum Einfügen von Videos von Youtube.
In früheren Artikeln haben wir gesehen, wie der Feldtyp Link funktioniert: Storage, Widget, Formatter. In diesem Artikel erstellen wir unseren eigenen Feldtyp, um Videos von YouTube auf einer Seite in zwei verschiedenen Formaten und mit Einstellungen auszugeben.
Dieser Artikel konzentriert sich auf die Fields API. Wenn Sie jedoch einfach nur ein YouTube-Video-Feld auf Ihrer Seite hinzufügen möchten, ist es besser, das fertige Modul zu verwenden:
https://www.drupal.org/project/video_embed_field
Ich habe den gesamten Code auf GitHub im Modul drupalbook_youtube hinzugefügt, Sie können das Modul herunterladen und auf Ihrer Seite installieren:
https://github.com/levmyshkin/drupalbook8
Schauen wir uns den Code des Moduls an und ich werde versuchen zu beschreiben, wie dieser Feldtyp funktioniert:
modules/custom/drupalbook_youtube/drupalbook_youtube.info.yml
name: DrupalBook Youtube
type: module
description: Youtube embed field
core: 8.x
package: Custom
Hier definieren wir die Metadaten für das Modul.
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-Implementierung des Feldtyps 'drupalbook_youtube'.
*
* @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 [
'columns' => [
'value' => [
'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;
}
}
Diese Klasse definiert den Feldtyp, damit Drupal weiß, was in der Datenbanktabelle für dieses Feld gespeichert wird.
Nun erstellen wir ein Widget, um Daten einzugeben:
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-Implementierung des Widgets 'drupalbook_youtube'.
*
* @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 += [
'#type' => 'textfield',
'#default_value' => $value,
'#size' => 32,
'#maxlength' => 256,
'#element_validate' => [
[$this, 'validate'],
],
];
return ['value' => $element];
}
/**
* Validiert das Textfeld für die YouTube-URL.
*/
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 ist nicht korrekt."));
}
}
}
Das Widget ermöglicht es, beim Bearbeiten der Entität Daten einzugeben. Die Validierung stellt sicher, dass die eingegebene URL eine gültige YouTube-Video-URL ist.
Nun fügen wir den Field Formatter hinzu, um die Daten auszugeben.
modules/custom/drupalbook_youtube/src/Plugin/Field/FieldFormatter/DrupalbookYoutubeThumbnailFormatter.php
<?php
namespace Drupal\drupalbook_youtube\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
/**
* Plugin-Implementierung des Formatters 'drupalbook_youtube_thumbnail'.
*
* @FieldFormatter(
* id = "drupalbook_youtube_thumbnail",
* module = "drupalbook_youtube",
* label = @Translation("Displays video thumbnail"),
* field_types = {
* "drupalbook_youtube"
* }
* )
*/
class DrupalbookYoutubeThumbnailFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
foreach ($items as $delta => $item) {
preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+(?=\?)|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $item->value, $matches);
if (!empty($matches)) {
$content = '
';
$elements[$delta] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $content,
];
}
}
return $elements;
}
}
Dieser Formatter zeigt das Vorschaubild des Videos mit einem Link zum YouTube-Video an.
Jetzt ein komplexerer Formatter mit Template und Einstellmöglichkeiten:
modules/custom/drupalbook_youtube/src/Plugin/Field/FieldFormatter/DrupalbookYoutubeVideoFormatter.php
<?php
namespace Drupal\drupalbook_youtube\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Plugin-Implementierung des Formatters 'drupalbook_youtube_video'.
*
* @FieldFormatter(
* id = "drupalbook_youtube_video",
* module = "drupalbook_youtube",
* label = @Translation("Displays Youtube video"),
* field_types = {
* "drupalbook_youtube"
* }
* )
*/
class DrupalbookYoutubeVideoFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'width' => '600',
'height' => '450',
] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$elements['width'] = [
'#type' => 'textfield',
'#title' => t('Youtube video width'),
'#default_value' => $this->getSetting('width'),
];
$elements['height'] = [
'#type' => 'textfield',
'#title' => t('Youtube video height'),
'#default_value' => $this->getSetting('height'),
];
return $elements;
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
$width = $this->getSetting('width');
$height = $this->getSetting('height');
foreach ($items as $delta => $item) {
preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+(?=\?)|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $item->value, $matches);
if (!empty($matches)) {
$elements[$delta] = [
'#theme' => 'drupalbook_youtube_video_formatter',
'#width' => $width,
'#height' => $height,
'#video_id' => $matches[0],
];
}
}
return $elements;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];
$settings = $this->getSettings();
if (!empty($settings['width']) && !empty($settings['height'])) {
$summary[] = t('Video size: @width x @height', ['@width' => $settings['width'], '@height' => $settings['height']]);
}
else {
$summary[] = t('Define video size');
}
return $summary;
}
}
Am Anfang stehen die üblichen Namespaces und Annotations.
Der Klassennamen endet auf Formatter, um anzuzeigen, dass es sich um einen Field Formatter handelt.
Wir definieren Standard-Einstellungen für die Bildgröße und ein Einstellungsformular, das auf der Seite "Anzeige verwalten" erscheint.
Die Methode settingsSummary()
liefert eine Zusammenfassung, die in der Feldbeschreibung angezeigt wird.
Die wichtigste Methode ist viewElements()
, in der wir die Daten vorbereiten und ein Template aufrufen:
$elements[$delta] = [
'#theme' => 'drupalbook_youtube_video_formatter',
'#width' => $width,
'#height' => $height,
'#video_id' => $matches[0],
];
Im Modul selbst registrieren wir das Template:
modules/custom/drupalbook_youtube/drupalbook_youtube.module
/**
* Implements hook_theme().
*/
function drupalbook_youtube_theme() {
return [
'drupalbook_youtube_video_formatter' => [
'variables' => ['width' => 600, 'height' => 450, 'video_id' => NULL],
],
];
}
Das Template selbst liegt hier:
modules/custom/drupalbook_youtube/templates/drupalbook-youtube-video-formatter.html.twig
{#
/**
* @file
* Standard-Theme-Implementierung für ein einfaches Youtube-Video.
*
* Verfügbare Variablen:
* - width: Breite des Youtube-Videos.
* - height: Höhe des Youtube-Videos.
* - video_id: Youtube-Video-ID.
*
* @see template_preprocess()
* @see template_drupalbook_youtube_video_formatter()
*
* @ingroup themeable
*/
#}
{% spaceless %}
<iframe width="{{ width }}" height="{{ height }}" src="https://www.youtube.com/embed/{{ video_id }}" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
{% endspaceless %}
Jetzt können Sie das YouTube-Video-Feld erstellen und auf der Seite verwenden:
Damit beenden wir die Erstellung benutzerdefinierter Felder und wenden uns der Entity API zu, wo wir eigene Entitätstypen erstellen werden.