media_mpx-8.x-1.x-dev/src/Plugin/Field/FieldFormatter/PlayerFormatter.php

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

namespace Drupal\media_mpx\Plugin\Field\FieldFormatter;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\media_mpx\DataObjectFactoryCreator;
use Drupal\media_mpx\MpxLogger;
use Drupal\media_mpx\PlayerMetadata;
use Drupal\media_mpx\Plugin\media\Source\Media;
use GuzzleHttp\Exception\TransferException;
use GuzzleHttp\Psr7\Uri;
use Lullabot\Mpx\DataService\ObjectListQuery;
use Lullabot\Mpx\DataService\Player\Player;
use Lullabot\Mpx\DataService\Sort;
use Lullabot\Mpx\Service\Player\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Lullabot\Mpx\DataService\Media\Media as MpxMedia;
use Drupal\media\Entity\Media as DrupalMedia;

/**
 * Field formatter for an mpx player.
 *
 * @todo This needs to only attach to mpx media types.
 *
 * @FieldFormatter(
 *   id = "media_mpx_video",
 *   label = @Translation("mpx Video player"),
 *   field_types = {
 *     "string"
 *   }
 * )
 */
class PlayerFormatter extends FormatterBase implements ContainerFactoryPluginInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The creator used to load player factories.
   *
   * @var \Drupal\media_mpx\DataObjectFactoryCreator
   */
  protected $dataObjectFactoryCreator;

  /**
   * The logger for mpx errors.
   *
   * @var \Drupal\media_mpx\MpxLogger
   */
  protected $mpxLogger;

  /**
   * The system messenger for error reporting.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * Constructs a PlayerFormatter object.
   *
   * @param string $plugin_id
   *   The plugin_id for the formatter.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The definition of the field to which the formatter is associated.
   * @param array $settings
   *   The formatter settings.
   * @param string $label
   *   The formatter label display setting.
   * @param string $view_mode
   *   The view mode.
   * @param array $third_party_settings
   *   Any third party settings.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\media_mpx\DataObjectFactoryCreator $data_object_factory_creator
   *   The creator of mpx data factories.
   * @param \Drupal\media_mpx\MpxLogger $mpx_logger
   *   The logger for mpx errors.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The system messenger for error reporting.
   */
  public function __construct(string $plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, string $label, string $view_mode, array $third_party_settings, EntityTypeManagerInterface $entity_type_manager, DataObjectFactoryCreator $data_object_factory_creator, MpxLogger $mpx_logger, MessengerInterface $messenger) {
    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
    $this->entityTypeManager = $entity_type_manager;
    $this->dataObjectFactoryCreator = $data_object_factory_creator;
    $this->mpxLogger = $mpx_logger;
    $this->messenger = $messenger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $plugin_id,
      $plugin_definition,
      $configuration['field_definition'],
      $configuration['settings'],
      $configuration['label'],
      $configuration['view_mode'],
      $configuration['third_party_settings'],
      $container->get('entity_type.manager'),
      $container->get('media_mpx.data_object_factory_creator'),
      $container->get('media_mpx.exception_logger'),
      $container->get('messenger')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $element = [];

    /** @var \Drupal\media\Entity\Media $entity */
    if (!$entity = $items->getEntity()) {
      return [];
    }
    /** @var \Drupal\media_mpx\Plugin\media\Source\Media $source_plugin */
    $source_plugin = $entity->getSource();

    // @todo Cache this.
    $factory = $this->dataObjectFactoryCreator->forObjectType($source_plugin->getAccount()->getUserEntity(), 'Player Data Service', 'Player', '1.6');

    try {
      $player = $factory->load(new Uri($this->getSetting('player')))->wait();
    }
    catch (TransferException $e) {
      // If we can't load a player, we can't render any elements.
      $this->mpxLogger->logException($e);
      return $element;
    }
    $this->renderIframes($items, $player, $element);

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $elements = parent::settingsForm($form, $form_state);

    // This method is called multiple times during a single request, so we have
    // a basic static cache as the results are slow to fetch.
    static $options = [];

    if (empty($options)) {
      try {
        $options = $this->fetchPlayerOptions();
      }
      catch (TransferException $e) {
        $this->mpxLogger->logException($e);
        $this->messenger->addError($this->t('An unexpected error occurred. The full error has been logged. %error',
          [
            '%error' => $e->getMessage(),
          ])
        );

        return [];
      }
    }

    $elements['player'] = [
      '#type' => 'select',
      '#title' => $this->t('mpx Player'),
      '#description' => $this->t('Select the mpx player to use for playing videos.'),
      '#options' => $options,
      '#default_value' => $this->getSetting('player'),
    ];

    $elements['auto_play'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Auto play'),
      '#description' => $this->t('Will automatically begin playback for the video on page load. See <a href="@url">mpx documentation</a> for details.', ['@url' => 'https://docs.theplatform.com/help/player-player-autoplay']),
      '#default_value' => $this->getSetting('auto_play'),
    ];

    $elements['play_all'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Play all'),
      '#description' => $this->t('Turn on playlist auto-advance for the player. See <a href="@url">mpx documentation</a> for more details.', ['@url' => 'https://docs.theplatform.com/help/player-player-playall']),
      '#default_value' => $this->getSetting('play_all'),
    ];

    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    // @todo Somehow cache the player title so we show that instead of the ID.
    $summary[] = $this->t('mpx Player: @title', ['@title' => $this->getSetting('player')]);
    $summary[] = $this->t('Auto play: @auto_play', ['@auto_play' => $this->getSetting('auto_play') ? 'true' : 'false']);
    $summary[] = $this->t('Play all : @play_all', ['@play_all' => $this->getSetting('play_all') ? 'true' : 'false']);
    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return [
      'player' => '',
      'auto_play' => FALSE,
      'play_all' => FALSE,
    ];
  }

  /**
   * Build the array of available players.
   *
   * @return array
   *   The array of player options.
   */
  protected function fetchPlayerOptions(): array {
    $options = [];
    if (!$bundle = $this->fieldDefinition->getTargetBundle()) {
      return [];
    }
    /** @var \Drupal\media\Entity\MediaType $type */
    $type = $this->entityTypeManager->getStorage('media_type')->load($bundle);
    /** @var \Drupal\media_mpx\Plugin\media\Source\Media $source_plugin */
    $source_plugin = $type->getSource();

    $factory = $this->dataObjectFactoryCreator->forObjectType($source_plugin->getAccount()->getUserEntity(), 'Player Data Service', 'Player', '1.6', $source_plugin->getAccount());
    $query = new ObjectListQuery();
    $sort = new Sort();
    $sort->addSort('title');
    $query->setSort($sort);

    /** @var \Lullabot\Mpx\DataService\Player\Player[] $results */
    $results = $factory->select($query);

    foreach ($results as $player_option) {
      if (!$player_option->getDisabled()) {
        $options[(string) $player_option->getId()] = $player_option->getTitle();
      }
    }
    return $options;
  }

  /**
   * Render the player iframes for this element.
   *
   * @param \Drupal\Core\Field\FieldItemListInterface $items
   *   The items to render.
   * @param \Lullabot\Mpx\DataService\Player\Player $player
   *   The player to render the items with.
   * @param array &$element
   *   The render array.
   */
  protected function renderIframes(FieldItemListInterface $items, Player $player, array &$element) {
    /** @var \Drupal\media\Entity\Media $entity */
    $entity = $items->getEntity();
    /** @var \Drupal\media_mpx\Plugin\media\Source\Media $source_plugin */
    $source_plugin = $entity->getSource();
    foreach ($items as $delta => $item) {
      $element[$delta] = $this->buildWrapper($entity, $source_plugin, $player);
    }
  }

  /**
   * Builds the render array for the wrapper.
   *
   * @param \Drupal\media\Entity\Media $entity
   *   The media entity.
   * @param \Drupal\media_mpx\Plugin\media\Source\Media $source_plugin
   *   The mpx source plugin.
   * @param \Lullabot\Mpx\DataService\Player\Player $player
   *   The mpx player.
   *
   * @return array|null
   *   The render array or null on an error.
   */
  protected function buildWrapper(DrupalMedia $entity, Media $source_plugin, Player $player) {
    try {
      /** @var \Lullabot\Mpx\DataService\Media\Media $mpx_media */
      $mpx_media = $source_plugin->getMpxObject($entity);
    }
    catch (TransferException $e) {
      // If this media item is missing, continue on to the next element.
      $this->mpxLogger->logException($e);
      return NULL;
    }

    $meta = new PlayerMetadata($entity, $mpx_media, $this->buildUrl($source_plugin, $mpx_media, $player));
    $element = [
      '#type' => 'media_mpx_iframe_wrapper',
      '#attributes' => [
        'class' => [
          'mpx-iframe-wrapper',
        ],
      ],
      '#meta' => $meta->toArray(),
      '#content' => $this->buildPlayer($source_plugin, $player, $mpx_media),
      '#entity' => $entity,
      '#mpx_media' => $mpx_media,
    ];
    $this->addMediaFileDetails($element, $mpx_media);

    return $element;
  }

  /**
   * Adds schema.org metadata from the first MediaFile.
   *
   * @param array $element
   *   The individual element to insert the metadata into.
   * @param \Lullabot\Mpx\DataService\Media\Media $mpx_media
   *   The mpx media object.
   */
  protected function addMediaFileDetails(array &$element, MpxMedia $mpx_media) {
    $mpx_media_files = $mpx_media->getContent();

    if (isset($mpx_media_files[0])) {
      $mpx_media_file = $mpx_media_files[0];

      // We want to recalculate the duration so seconds roll over into minutes
      // and hours.
      // @see https://php.net/manual/en/dateinterval.format.php#113204
      $interval = new \DateInterval('PT' . round($mpx_media_file->getDuration()) . 'S');
      $from = new \DateTime();
      $to = clone $from;
      $to->add($interval);
      $diff = $from->diff($to);
      foreach ($diff as $k => $v) {
        $interval->$k = $v;
      }

      $element['#meta']['duration'] = ($interval)->format('PT%hH%iM%sS');
      $element['#meta']['height'] = $mpx_media_file->getHeight();
      $element['#meta']['width'] = $mpx_media_file->getWidth();
    }
  }

  /**
   * Builds the render array of the media player.
   *
   * @param \Drupal\media_mpx\Plugin\media\Source\Media $source_plugin
   *   The media source plugin.
   * @param \Lullabot\Mpx\DataService\Player\Player $player
   *   The media player.
   * @param \Lullabot\Mpx\DataService\Media\Media $mpx_media
   *   The media item.
   *
   * @return array
   *   The render array.
   */
  protected function buildPlayer(Media $source_plugin, Player $player, MpxMedia $mpx_media) {
    return [
      '#type' => 'media_mpx_iframe',
      '#url' => (string) ($this->buildUrl($source_plugin, $mpx_media, $player)),
      '#attributes' => [
        'class' => [
          'mpx-player',
          'mpx-player-account--' . $source_plugin->getAccount()->id(),
        ],
      ],
    ];
  }

  /**
   * Build the URL for a player iframe.
   *
   * @param \Drupal\media_mpx\Plugin\media\Source\Media $source_plugin
   *   The source plugin associated with the media.
   * @param \Lullabot\Mpx\DataService\Media\Media $mpx_media
   *   The mpx media object.
   * @param \Lullabot\Mpx\DataService\Player\Player $player
   *   The player to build the URL for.
   *
   * @return \Lullabot\Mpx\Service\Player\Url
   *   The player URL.
   */
  protected function buildUrl(Media $source_plugin, MpxMedia $mpx_media, Player $player): Url {
    return (new Url($source_plugin->getAccount(), $player, $mpx_media))
      ->withAutoplay($this->getSetting('auto_play'))
      ->withPlayAll($this->getSetting('play_all'));
  }

}

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

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