bynder-4.0.0-beta1/src/Plugin/Field/FieldFormatter/BynderFormatter.php

src/Plugin/Field/FieldFormatter/BynderFormatter.php
<?php

namespace Drupal\bynder\Plugin\Field\FieldFormatter;

use Drupal\bynder\Plugin\media\Source\Bynder;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\media\MediaTypeInterface;
use GuzzleHttp\Exception\ConnectException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Plugin implementation of the 'Bynder' formatter.
 *
 * @FieldFormatter(
 *   id = "bynder",
 *   label = @Translation("Bynder (Image)"),
 *   field_types = {"string", "string_long", "entity_reference"}
 * )
 */
class BynderFormatter extends BynderFormatterBase implements ContainerFactoryPluginInterface {

  /**
   * The entity repository service.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface;
   */
  protected $entityRepository;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->entityRepository = $container->get('entity.repository');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return [
        'thumbnail' => 'webimage',
        'alt_field' => '',
        'title_field' => '',
        'dat_query' => '',
        'responsive_sizes' => '',
        'dat_query_responsive' => '',
        'use_custom_transformations' => '',
        'image_loading' => [
          'attribute' => 'eager',
        ],
      ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $elements = parent::settingsForm($form, $form_state);
    try {
      $derivatives = array_merge(
        ['mini', 'webimage', 'thul'],
        array_map(function ($item) {
          return $item['prefix'];
        }, $this->bynder->getDerivatives())
      );
    }
    catch (ConnectException $e) {
      $derivatives = [];
    }

    $elements['thumbnail'] = [
      '#type' => 'select',
      '#options' => array_combine($derivatives, $derivatives),
      '#title' => $this->t('Derivative'),
      '#description' => $this->t('Select the name of the derivative to be used to display the image. Besides custom derivatives that you created in Bynder there are also default thumbnail sizes available that can be used. Go to @form and reload derivatives.', ['@form' => Link::createFromRoute($this->t('Bynder configuration form'), 'bynder.configuration_form')->toString()]),
      '#default_value' => $this->getSetting('thumbnail'),
      '#attributes' => ['class' => ['bynder-derivative']],
    ];

    $field_candidates = $this->getFieldAndMetadataCandidates();

    $elements['alt_field'] = [
      '#type' => 'select',
      '#options' => $field_candidates,
      '#title' => $this->t('Alt attribute field'),
      '#description' => $this->t('Select the name of the field that should be used for the "alt" attribute of the image.'),
      '#default_value' => $this->getSetting('alt_field'),
      '#empty_value' => '',
    ];

    $elements['title_field'] = [
      '#type' => 'select',
      '#options' => $field_candidates,
      '#title' => $this->t('Title attribute field'),
      '#description' => $this->t('Select the name of the field that should be used for the "title" attribute of the image.'),
      '#default_value' => $this->getSetting('title_field'),
      '#empty_value' => '',
    ];

    $dat_documentation = 'https://support.bynder.com/hc/en-us/articles/360018559260-Dynamic-Asset-Transformations-DAT-';
    $elements['dat_query'] = [
      '#type' => 'textfield',
      '#title' => $this->t('DAT query field'),
      '#description' => $this->t('Attributes that should be applied to the images. See  <a href=":dat_help">here</a> for explanation on possible values. Should start right after the "?", e.g. "io=transform:fill,width:100,height:200" If the following Responsive image fields are filled, this field defines the fallback image if the responsive settings are broken.', array(
        ':dat_help' => $dat_documentation,
      )),
      '#default_value' => $this->getSetting('dat_query'),
      '#states' => [
        'visible' => [
          ':input.bynder-derivative' => ['value' => 'DAT'],
        ],
        'required' => [
          ':input.bynder-derivative' => ['value' => 'DAT'],
        ],
      ],
    ];

    $elements['responsive_sizes'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Sizes for responsive images'),
      '#description' => $this->t('With this and the next field filled, a set of responsive images is generated. String that will be fed in the "sizes" attribute of the img object.'),
      '#default_value' => $this->getSetting('responsive_sizes'),
      '#states' => [
        'visible' => [
          ':input.bynder-derivative' => ['value' => 'DAT'],
        ],
      ],
    ];

    $elements['dat_query_responsive'] = [
      '#type' => 'textarea',
      '#title' => $this->t('The set of responsive images (srcset)'),
      '#description' => $this->t('The different images to be used in a responsive setting. It should have the form: "io=transform:fill,width:100,height:200 100w, io=transform:fill,width:200,height:400 200w, ...", with the "io=..." following <a href=":dat_help">these</a> guidelines, and the second argument being the width of the image. Make sure to separate each setting with ", ".', array(
        ':dat_help' => $dat_documentation,
      )),
      '#default_value' => $this->getSetting('dat_query_responsive'),
      '#states' => [
        'visible' => [
          ':input.bynder-derivative' => ['value' => 'DAT'],
        ],
      ],
    ];

    $elements['use_custom_transformations'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Use user-selected asset transformations if available'),
      '#description' => $this->t('If the search widget is in single_file_selection mode, on-the-fly transformations may be applied. Use them if the asset has a corresponding transformation.'),
      '#default_value' => $this->getSetting('use_custom_transformations'),
    ];

    $image_loading = $this->getSetting('image_loading');
    $elements['image_loading'] = [
      '#type' => 'details',
      '#title' => $this->t('Image loading'),
      '#weight' => 10,
      '#description' => $this->t('Lazy render images with native image loading attribute (<em>loading="lazy"</em>). This improves performance by allowing browsers to lazily load images.'),
    ];
    $loading_attribute_options = [
      'lazy' => $this->t('Lazy (<em>loading="lazy"</em>)'),
      'eager' => $this->t('Eager (<em>loading="eager"</em>)'),
    ];
    $elements['image_loading']['attribute'] = [
      '#title' => $this->t('Image loading attribute'),
      '#type' => 'radios',
      '#default_value' => $image_loading['attribute'],
      '#options' => $loading_attribute_options,
      '#description' => $this->t('Select the loading attribute for images. <a href=":link">Learn more about the loading attribute for images.</a>', [
        ':link' => 'https://html.spec.whatwg.org/multipage/urls-and-fetching.html#lazy-loading-attributes',
      ]),
    ];
    $elements['image_loading']['attribute']['lazy']['#description'] = $this->t('Delays loading the image until that section of the page is visible in the browser. When in doubt, lazy loading is recommended.');
    $elements['image_loading']['attribute']['eager']['#description'] = $this->t('Force browsers to download an image as soon as possible. This is the browser default for legacy reasons. Only use this option when the image is always expected to render.');


    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = parent::settingsSummary();

    $settings = $this->getSettings();

    if ($settings['thumbnail'] == 'DAT') {
      if (!empty($settings['dat_query_responsive']) && !empty($settings['responsive_sizes'])) {
        $summary[] = $this->t('DAT configuration: Responsive, fallback: @dat', ['@dat' => $settings['dat_query']]);
      }
      else {
        $summary[] = $this->t('DAT configuration: @dat', ['@dat' => $settings['dat_query']]);
      }
    }
    else {
      $summary[] = $this->t('Derivative: @style', ['@style' => $settings['thumbnail']]);
    }
    $field_candidates = $this->getFieldAndMetadataCandidates(FALSE);
    if (empty($settings['title_field'])) {
      $summary[] = $this->t('Title attribute not displayed (not recommended).');
    }
    else {
      $summary[] = $this->t('Title attribute field: @field', ['@field' => $field_candidates[$settings['title_field']]]);
    }

    if (empty($settings['alt_field'])) {
      $summary[] = $this->t('Alt attribute not displayed (not recommended).');
    }
    else {
      $summary[] = $this->t('Alt attribute field: @field', ['@field' => $field_candidates[$settings['alt_field']]]);
    }

    if (!empty($settings['use_custom_transformations'])) {
      $summary[] = $this->t('Using user-selected transformations if available.');
    }

    $image_loading = $this->getSetting('image_loading');
    $summary[] = $this->t('Image loading: @attribute', [
      '@attribute' => $image_loading['attribute'],
    ]);

    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $settings = $this->getSettings();
    $element = [];
    $is_entityreference = $this->fieldDefinition->getType() == 'entity_reference';

    foreach ($items as $delta => $item) {
      /** @var \Drupal\media\MediaInterface $media_entity */
      if ($media_entity = $is_entityreference ? $item->entity : $items->getEntity()) {
        /** @var \Drupal\media\MediaInterface $media_entity */
        $media_entity = $this->entityRepository->getTranslationFromContext($media_entity, $langcode);
        /** @var \Drupal\media\MediaSourceInterface $source_plugin */
        $source_plugin = $media_entity->getSource();
        if ($source_plugin instanceof Bynder && ($thumbnails = $source_plugin->getMetadata($media_entity, 'thumbnail_urls'))) {
          $element['#attached']['library'][] = 'bynder/formatter';
          $element[$delta]['bynder_wrapper'] = [
            '#type' => 'container',
            '#attributes' => [
              'class' => ['bynder-wrapper'],
            ],
          ];

          $image_loading_settings = $this->getSetting('image_loading');
          $element[$delta]['bynder_wrapper']['image'] = [
            '#theme' => 'image',
            '#uri' => '',
            '#attributes' => [
              'class' => ['bynder-image'],
              'loading' => $image_loading_settings['attribute'] ?? 'eager',
            ],
            // TODO width, height - we don't have this info (unless we
            // download the thumbnail). Would be nice to have support in the
            // API.
          ];

          // DAT and on-the-fly transformation query.
          $use_transform_base = FALSE;
          $use_preset = FALSE;
          $transform_query = [];
          if (isset($thumbnails['transformBaseUrl'])) {
            if ($this->getSetting('use_custom_transformations') && !$media_entity->get(Bynder::TRANSFORMATIONS_FIELD_NAME)->isEmpty()) {
              $transformationsValue = $media_entity->get(Bynder::TRANSFORMATIONS_FIELD_NAME)->value;

              // Check if the transformations value starts with "preset"
              if (strpos($transformationsValue, 'preset') === 0) {
                // Remove "preset:" from the beginning
                $preset = substr($transformationsValue, 7);
                $use_preset = TRUE;
              } else {
                // Current code for handling transformations that do not start with "preset"
                $transform_query[] = $transformationsValue;
                $use_transform_base = TRUE;
              }
            }
            elseif ($settings['thumbnail'] == 'DAT' && !empty($settings['dat_query'])) {
              $transform_query[] = $this->getSetting('dat_query');
              $use_transform_base = TRUE;

              // Set responsive specific attributes.
              if ($this->getSetting('thumbnail') == 'DAT' && isset($thumbnails['transformBaseUrl']) && isset($settings['dat_query_responsive']) && isset($settings['responsive_sizes'])) {
                $element[$delta]['bynder_wrapper']['image']['#attributes']['srcset'] = str_replace('io=', $thumbnails['transformBaseUrl'] . '?io=', $settings['dat_query_responsive']);
                $element[$delta]['bynder_wrapper']['image']['#attributes']['sizes'] = $settings['responsive_sizes'];
              }
            }
          }

          if ($use_transform_base) {
            $element[$delta]['bynder_wrapper']['image']['#uri'] = $thumbnails['transformBaseUrl'] . '?' . implode('&', $transform_query);;
          }
          elseif($use_preset) {
            $element[$delta]['bynder_wrapper']['image']['#uri'] = $thumbnails[$preset];
          }
          else {
            $element[$delta]['bynder_wrapper']['image']['#uri'] = $thumbnails[$settings['thumbnail']] ?? $thumbnails['webimage'];
          }

          if ($settings['title_field'] && $title = $this->getValueFromFieldOrMetadata($media_entity, $settings['title_field'])) {
            $element[$delta]['bynder_wrapper']['image']['#title'] = $title;
          }
          if ($settings['alt_field'] && $alt = $this->getValueFromFieldOrMetadata($media_entity, $settings['alt_field'])) {
            $element[$delta]['bynder_wrapper']['image']['#alt'] = $alt;
          }
          $this->renderer->addCacheableDependency($element[$delta]['bynder_wrapper']['image'], $item);
          $element[$delta]['bynder_wrapper']['tooltip'] = [
            '#type' => 'html_tag',
            '#access' => AccessResult::allowedIfHasPermission($this->currentUser, 'view bynder media usage'),
            '#tag' => 'div',
            '#attributes' => [
              'role' => 'tooltip',
              'class' => ['bynder-tooltip'],
            ],
            // @todo Information is not available yet. Fix when API supports it.
            '#value' => $this->t('Usage info is not available yet. Usage restriction level: @restriction', [
              '@restriction' => get_media_restriction($source_plugin->getMetadata($media_entity, 'propertyOptions')),
            ]),
          ];
          $this->renderer->addCacheableDependency($element[$delta]['bynder_wrapper']['tooltip'], $this->configFactory->get('bynder.settings'));
        }
      }
    }

    return $element;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc