Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

9.10.3. Աշխատանք Drupal-ում դաշտերի հետ։ Ստեղծեք ձեր սեփական դաշտի տեսակը, վիջեթը, ձևաչափիչը Youtube-ից տեսանյութեր տեղադրելու համար։

19/04/2025, by Ivan

Menu

Նախորդ հոդվածներում մենք ուսումնասիրել ենք Link դաշտի տեսակը՝ պահեստավորում (Storage), մուտքագրում (Widget), ցուցադրում (Formatter): Այս հոդվածում մենք կստեղծենք մեր սեփական դաշտի տեսակը՝ էջում YouTube տեսանյութ ցուցադրելու համար՝ երկու տարբեր ձևաչափով և կարգավորումներով:

Այս հոդվածը կենտրոնացած է Fields API-ի վրա, իսկ եթե Ձեզ անհրաժեշտ է YouTube տեսանյութի դաշտ ավելացնել կայքին, ապա ավելի լավ է օգտվել պատրաստի մոդուլից՝

https://www.drupal.org/project/video_embed_field

Ես բոլոր կոդերը ավելացրել եմ GitHub-ում՝ drupalbook_youtube մոդուլի մեջ, կարող եք ներբեռնել և տեղադրել ձեր կայքում.

https://github.com/levmyshkin/drupalbook8

Եկեք նայենք մոդուլի կառուցվածքին և փորձենք բացատրել, թե ինչպես է աշխատում այս դաշտի տեսակը.

modules/custom/drupalbook_youtube/drupalbook_youtube.info.yml

name: DrupalBook Youtube
type: module
description: Youtube embed field
core: 8.x
package: Custom

Նշում ենք մոդուլի մետատվյալները։

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,
        ),
      ),
    );
  }

Ստեղծում ենք դաշտի տեսակը՝ որպեսզի Drupal-ը հասկանա, թե տվյալները ինչ կերպով են պահվելու բազայում:

  /**
   * {@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;
  }

}

Նշում ենք, որ դաշտի արժեքը պահվում է որպես տեքստային «value» սյունակ։

Եթե երրորդ կողմի կոդից դաշտը կանչվի, ապա isEmpty() մեթոդը թույլ է տալիս ապահով fallback դատարկ արդյունքի համար։

propertyDefinitions մեթոդի միջոցով նկարագրում ենք MySQL աղյուսակում սյունակների տեսակը և այն, թե ինչպես է Drupal-ը ճանաչում այդ տվյալները որպես entity-ի մաս։ Արդյունքում մենք պահում ենք ամբողջական հղումը՝

select

Այժմ, երբ մենք ավելացրել ենք դաշտի տեսակը, անցնենք Widget-ի ստեղծմանը՝ տվյալների մուտքագրման համար։

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);
  }

Այս widget-ը թույլ է տալիս մուտքագրել YouTube հղումը՝ նյութը կամ բլոկը խմբագրելիս։ Ստեղծում ենք սովորական տեքստային դաշտ՝ օգտագործելով Form API։

  /**
   * 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."));
    }
  }

}

Վավերացման callback-ը սահմանել ենք #element_validate պարամետրի միջոցով։ Այս ֆունկցիան ստուգում է, որ օգտագործողը մուտքագրել է ճիշտ YouTube հղում։ Regular expression-ը վերցված է StackOverflow-ից և կարելի է փոխարինել ըստ անհրաժեշտության։

Հիմա մենք կարող ենք մուտքագրել տվյալները, մնացել է միայն դաշտի համար Field Formatter-ը՝ արդյունքը էջում ցուցադրելու համար։

modules/custom/drupalbook_youtube/src/Plugin/FieldFieldFormatter/DrupalbookYoutubeThumbnailFormatter.php

Մենք կունենանք երկու formatter. Սկսենք պարզ տարբերակից, որը ցուցադրում է տեսանյութի մանրապատկերը՝ հղումով դեպի YouTube։

<?php

namespace Drupal\drupalbook_youtube\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;

/**
 * Plugin implementation of the 'drupalbook_youtube_thumbnail' formatter.
 *
 * @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 = array();

    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 = '<a href="' . $item->value . '" target="_blank"><img src="http://img.youtube.com/vi/' . $matches[0] . '/0.jpg"></a>';
        $elements[$delta] = array(
          '#type' => 'html_tag',
          '#tag' => 'p',
          '#value' => $content,
        );
      }

    }

    return $elements;
  }

}

Formatter-ի անոտացիայում field_types պարամետրում նշվում է՝ որ դաշտի տեսակին է վերաբերելու տվյալ formatter-ը։

viewElements() մեթոդը օգտագործվում է՝ դաշտի արժեքները տեսանելի դարձնելու համար։ Յուրաքանչյուր $item պարունակում է մուտքագրված հղումը, որից regex-ի օգնությամբ ստանում ենք տեսանյութի ID-ն։ Այնուհետև img.youtube.com ծառայությունից բերում ենք մանրապատկերը և փաթաթում հղման մեջ։

Դիտման պատկերի հասցեն արդեն գոյություն ունի YouTube-ում, և մենք կարող ենք ուղղակիորեն օգտվել դրանից՝ տեսանյութի ID-ն իմանալով։

Օգտագործում ենք $delta, որպեսզի աջակցենք բազմարժեք դաշտերի, այսինքն՝ մեկ դաշտում մի քանի տեսանյութեր ցուցադրելու հնարավորության։

Հիմա դիտենք ավելի բարդ formatter՝ ձևանմուշով և կարգավորումներով։

modules/custom/drupalbook_youtube/src/Plugin/FieldFieldFormatter/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 implementation of the 'drupalbook_youtube_video' formatter.
 *
 * @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 array(
      'width' => '600',
      'height' => '450',
    ) + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $elements['width'] = array(
      '#type' => 'textfield',
      '#title' => t('Youtube video width'),
      '#default_value' => $this->getSetting('width'),
    );
    $elements['height'] = array(
      '#type' => 'textfield',
      '#title' => t('Youtube video height'),
      '#default_value' => $this->getSetting('height'),
    );

    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = array();
    $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] = array(
          '#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;
  }

}

Սա Field Formatter է, որն ունի տեսանյութի լայնության և բարձրության կարգավորումներ։ settingsForm() մեթոդը սահմանում է դաշտ, որտեղ կարող եք մուտքագրել լայնությունը և բարձրությունը։ Այս արժեքները պահվում են կարգավորումներում և ստացվում են getSetting() միջոցով։

Ի տարբերություն նախորդ formatter-ի՝ այստեղ մենք օգտագործում ենք #theme և փոխանցում ենք փոփոխականներ Twig ձևանմուշին՝ տեսանյութը iframe-ով ցուցադրելու համար։

Ի տարբերություն նախորդ ձևաչափի, այստեղ մենք օգտագործում ենք #theme՝ ձևանմուշի անունը, որը մշակելու է դաշտի տարրերը։ Դրա համար մենք կստեղծենք drupalbook_youtube_video_formatter անունով նոր Twig ձևանմուշ։ Այդ ձևանմուշը սահմանելու ենք drupalbook_youtube.module ֆայլում։

modules/custom/drupalbook_youtube/drupalbook_youtube.module

/**
 * Implements hook_theme().
 */
function drupalbook_youtube_theme() {
  return array(
    'drupalbook_youtube_video_formatter' => array(
      'variables' => array('width' => 600, 'height' => 450, 'video_id' => NULL),
    ),
  );
}

Այստեղ մենք նշում ենք նաև width, height և video_id փոփոխականների կանխադրված արժեքները։ Դրանք փոխանցվելու են Twig ձևանմուշին՝ $elements զանգվածից։

Հաջորդ քայլում ավելացնում ենք ձևանմուշի ֆայլը՝

modules/custom/drupalbook_youtube/templates/drupalbook-youtube-video-formatter.html.twig

{#
/**
 * @file
 * Default theme implementation of a simple Youtube video.
 *
 * Available variables:
 * - width: Youtube video width.
 * - height: Youtube video height.
 * - 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 %}

Այս ձևանմուշը ցուցադրում է YouTube-ի iframe, որը ներառում է տեսանյութի ID-ն։ Դուք կարող եք փոխել այս HTML-ի տեսքը՝ ըստ ձեր պահանջների։

Եվ հիմա կարող եք ստեղծել Youtube տեսանյութի դաշտ ձեր նյութերում կամ բլոկներում։

link

Սրանով ավարտում ենք custom դաշտերի ստեղծման գործընթացը։ Հաջորդ հոդվածներում կծանոթանանք Entity API-ին և կսովորենք ստեղծել մեր սեփական Entity տեսակները։