AudioFieldPluginBase.php in AudioField 8
Namespace
Drupal\audiofieldFile
src/AudioFieldPluginBase.phpView source
<?php
namespace Drupal\audiofield;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\file\FileInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Random;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Asset\LibraryDiscovery;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\Entity\File;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Base class for audiofield plugins. Includes global functions.
*/
abstract class AudioFieldPluginBase extends PluginBase implements ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
* Library discovery service.
*
* @var Drupal\Core\Asset\LibraryDiscovery
*/
protected $libraryDiscovery;
/**
* Messenger service.
*
* @var Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* File System service.
*
* @var Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* Messenger service.
*
* @var Drupal\Core\Logger\LoggerChannelFactoryInterface
*/
protected $loggerFactory;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LibraryDiscovery $library_discovery, MessengerInterface $messenger, LoggerChannelFactoryInterface $logger_factory, FileSystemInterface $file_system) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->libraryDiscovery = $library_discovery;
$this->messenger = $messenger;
$this->loggerFactory = $logger_factory;
$this->fileSystem = $file_system;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('library.discovery'), $container
->get('messenger'), $container
->get('logger.factory'), $container
->get('file_system'));
}
/**
* Renders the player.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The uploaded item list.
* @param string $langcode
* The language code.
* @param array $settings
* An array of additional render settings.
*
* @return array
* Returns the rendered array.
*/
public abstract function renderPlayer(FieldItemListInterface $items, $langcode, array $settings);
/**
* Gets the plugin_id of the plugin instance.
*
* @return string
* The plugin_id of the plugin instance.
*/
public function getPluginId() {
return $this->pluginDefinition['id'];
}
/**
* Gets the title of the plugin instance.
*
* @return string
* The title of the plugin instance.
*/
public function getPluginTitle() {
return $this->pluginDefinition['title'];
}
/**
* Gets the name of the main library of the plugin instance.
*
* @return string
* The name of the main library of the plugin instance.
*/
public function getPluginLibraryName() {
return $this->pluginDefinition['libraryName'];
}
/**
* Gets the main library instance of this plugin.
*
* @return array
* The definition of the main library for this plugin.
*/
public function getPluginLibrary() {
// Get the main library for this plugin.
return $this->libraryDiscovery
->getLibraryByName('audiofield', 'audiofield.' . $this
->getPluginLibraryName());
}
/**
* Parses library to get version number of installed library.
*
* @return string
* The version number of the currently installed library.
*/
public function getPluginLibraryVersion() {
// Default to 1. This is implemented in the plugins.
return '1';
}
/**
* Gets the location of this plugin's library installation.
*
* @return string
* The library path of the plugin instance.
*/
public function getPluginLibraryPath() {
// Get the main library for this plugin.
$library = $this
->getPluginLibrary();
return preg_filter('%(^libraries/[^//]+).*%', '/$1', $library['js'][0]['data']);
}
/**
* Gets the remote download source from the plugin's main library.
*
* @return string
* The remote download source of the plugin instance.
*/
public function getPluginRemoteSource() {
// Get the main library for this plugin.
$library = $this
->getPluginLibrary();
return $library['remote'];
}
/**
* Gets the definition of the plugin implementation.
*
* @return array
* The plugin definition, as returned by the discovery object used by the
* plugin manager.
*/
public function getPluginDefinition() {
return $this
->t('@title: @description. Plugin library can be found at %librarySource.', [
'@title' => $this
->getPluginTitle(),
'@description' => $this->pluginDefinition['description'],
'%librarySource' => $this
->getPluginRemoteSource(),
]);
}
/**
* Checks to see if this audio plugin has been properly installed.
*
* @param bool $log_error
* Flag to indicate whether or not alert should be logged/shown.
*
* @return bool
* Returns a boolean indicating install state.
*/
public function checkInstalled($log_error = TRUE) {
// Get the main library for this plugin.
$library = $this
->getPluginLibrary();
// Check if the library is installed.
if (file_exists(DRUPAL_ROOT . '/' . $library['js'][0]['data'])) {
// Check to make sure the installed version is up to date.
$this
->checkVersion($log_error);
return TRUE;
}
return FALSE;
}
/**
* Checks to see if this audio plugin version is up to date.
*
* @param bool $log_error
* Flag to indicate whether or not alert should be logged/shown.
*
* @return bool
* Returns a boolean indicating if version is up to date.
*/
public function checkVersion($log_error = TRUE) {
// Get the main library for this plugin.
$library = $this
->getPluginLibrary();
// Check to make sure the installed version is up to date.
if (version_compare($this
->getPluginLibraryVersion(), $library['version'], '<')) {
// Log the warning if necessary.
if ($log_error) {
$message_data = [
'@plugin' => $this
->getPluginTitle(),
'@version' => $this
->getPluginLibraryVersion(),
'@newversion' => $library['version'],
'@download-link' => Link::fromTextAndUrl($this
->getPluginRemoteSource(), Url::fromUri($this
->getPluginRemoteSource()))
->toString(),
'%command' => 'drush audiofield-update',
'@status_report' => Link::createFromRoute('status report', 'system.status')
->toString(),
];
$this->loggerFactory
->get('audiofield')
->warning('Warning: @plugin library is out of date. You should upgrade from version @version to version @newversion. You can manually download the required version here: @download-link or you can install automatically by running the command %command. See the @status_report for more information', $message_data);
$this->messenger
->addWarning($this
->t('Warning: @plugin library is out of date. You should upgrade from version @version to version @newversion. You can manually download the required version here: @download-link or you can install automatically by running the command %command. See the @status_report for more information', $message_data));
}
return FALSE;
}
return TRUE;
}
/**
* Shows library installation errors for in-use libraries.
*/
public function showInstallError() {
$message_data = [
'@library_name' => $this
->getPluginLibraryName(),
'@status_report' => Link::createFromRoute('status report', 'system.status')
->toString(),
];
$this->loggerFactory
->get('audiofield')
->error('Error: @library_name library is not currently installed! See the @status_report for more information.', $message_data);
$this->messenger
->addWarning($this
->t('Error: @library_name library is not currently installed! See the @status_report for more information.', $message_data));
}
/**
* Validate that a file entity will work with this player.
*
* @param \Drupal\file\FileInterface $file
* A file entity.
*
* @return bool
* Indicates if the file is valid for this player or not.
*/
private function validateFileAgainstPlayer(FileInterface $file) {
// Validate the file extension agains the list of valid extensions.
$errors = file_validate_extensions($file, implode(' ', $this->pluginDefinition["fileTypes"]));
if (count($errors) > 0) {
$message_data = [
'%filename' => $file
->getFilename(),
'@player' => $this
->getPluginLibraryName(),
'%extensions' => implode(', ', $this->pluginDefinition["fileTypes"]),
];
$this->loggerFactory
->get('audiofield')
->error('Error playing file %filename: currently selected audio player only supports the following extensions: %extensions', $message_data);
$this->messenger
->addWarning($this
->t('Error playing file %filename: currently selected audio player only supports the following extensions: %extensions', $message_data));
return FALSE;
}
return TRUE;
}
/**
* Validate that a link entity will work with this player.
*
* @param \Drupal\Core\Url $link
* Url to the link.
*
* @return bool
* Indicates if the link is valid for this player or not.
*/
private function validateLinkAgainstPlayer(Url $link) {
// Check for a valid link and a valid extension.
$extension = pathinfo($link
->toString(), PATHINFO_EXTENSION);
if (!UrlHelper::isValid($link
->toString(), FALSE) || empty($extension)) {
// We are currently not validating file types for links.
$message_data = [
'%link' => $link
->toString(),
];
$this->loggerFactory
->get('audiofield')
->error('Error playing file: invalid link: %link', $message_data);
$this->messenger
->addWarning($this
->t('Error playing file: invalid link: %link', $message_data));
return FALSE;
}
return TRUE;
}
/**
* Get the class type for an entity.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which we are determining class type.
*
* @return string
* The class type for the item.
*/
protected function getClassType($item) {
// Handle File entity.
if (get_class($item) == 'Drupal\\file\\Plugin\\Field\\FieldType\\FileItem') {
return 'FileItem';
}
elseif (get_class($item) == 'Drupal\\link\\Plugin\\Field\\FieldType\\LinkItem') {
return 'LinkItem';
}
return NULL;
}
/**
* Validate that this entity will work with this player.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item which we are validating works with the player.
*
* @return bool
* Indicates if the entity is valid for this player or not.
*/
protected function validateEntityAgainstPlayer($item) {
// Handle File entity.
if ($this
->getClassType($item) == 'FileItem') {
// Load the associated file.
$file = $this
->loadFileFromItem($item);
// Be certain that the file itself actually exists.
if (!$file instanceof FileInterface) {
$this->loggerFactory
->get('audiofield')
->error('Error: file does not exist.');
$this->messenger
->addWarning($this
->t('Error: file does not exist.'));
return FALSE;
}
// Validate that this file will work with this player.
return $this
->validateFileAgainstPlayer($file);
}
elseif ($this
->getClassType($item) == 'LinkItem') {
// Get the source URL for this item.
$source_url = $this
->getAudioSource($item);
// Be certain that the URL itself actually exists.
if (!$source_url instanceof Url) {
$this->loggerFactory
->get('audiofield')
->error('Error: file does not exist.');
$this->messenger
->addWarning($this
->t('Error: file does not exist.'));
return FALSE;
}
// Validate that this link will work with this player.
return $this
->validateLinkAgainstPlayer($source_url);
}
return FALSE;
}
/**
* Load a file from an audio file entity.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which we are loading the file entity.
*
* @return \Drupal\file\FileInterface
* FileInterface from the item.
*/
private function loadFileFromItem($item) {
// Load the associated file.
return File::load($item
->get('target_id')
->getCastedValue());
}
/**
* Get a unique audofield ID.
*
* @return string
* Unique ID for this audio player.
*/
protected function getUniqueRenderId() {
return Html::getUniqueId('audiofield');
}
/**
* Get a unique ID for an item.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which we are generating a unique ID.
*
* @return string
* Unique ID for the item.
*/
private function getUniqueId($item) {
// Used to generate unique container.
$random_generator = new Random();
// Handle File entity.
if ($this
->getClassType($item) == 'FileItem') {
// Load the associated file.
$file = $this
->loadFileFromItem($item);
// Craft a unique ID.
return Html::getUniqueId('file_' . $file
->get('fid')
->getValue()[0]['value'] . '_' . $random_generator
->name(16, TRUE));
}
elseif ($this
->getClassType($item) == 'LinkItem') {
// Craft a unique ID.
return Html::getUniqueId('item_' . $random_generator
->name(16, TRUE));
}
return Html::getUniqueId($random_generator
->name(16, TRUE));
}
/**
* Get the filetype for an item.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which we are determining filetype.
*
* @return string
* Filetype for the item.
*/
private function getFiletype($item) {
// Handle File entity.
if ($this
->getClassType($item) == 'FileItem') {
// Load the associated file.
$file = $this
->loadFileFromItem($item);
return pathinfo($file
->getFilename(), PATHINFO_EXTENSION);
}
elseif ($this
->getClassType($item) == 'LinkItem') {
return pathinfo($this
->getAudioSource($item)
->toString(), PATHINFO_EXTENSION);
}
return '';
}
/**
* Get source URL from an audiofield entity.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which we are determining source.
*
* @return \Drupal\Core\Url|string
* The source URL of an entity.
*/
private function getAudioSource($item) {
if ($this
->getClassType($item) == 'FileItem') {
// Load the associated file.
$file = $this
->loadFileFromItem($item);
// Get the file URL.
return Url::fromUri(file_create_url($file
->getFileUri()));
}
elseif ($this
->getClassType($item) == 'LinkItem') {
// Get the file URL.
return $item
->getUrl();
}
return '';
}
/**
* Get a title description from an audiofield entity.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which a title is being generated.
*
* @return string
* The description of an entity.
*/
private function getAudioDescription($item) {
if ($this
->getClassType($item) == 'FileItem') {
// Get the file description - use the filename if it doesn't exist.
$entity_description = $item
->get('description')
->getString();
if (empty($entity_description)) {
// Load the associated file.
$file = $this
->loadFileFromItem($item);
return $file
->getFilename();
}
return $entity_description;
}
elseif ($this
->getClassType($item) == 'LinkItem') {
// Get the file description - use the filename if it doesn't exist.
$entity_description = $item
->get('title')
->getString();
if (empty($entity_description)) {
return $item
->getUrl()
->toString();
}
return $entity_description;
}
return '';
}
/**
* Get required rendering information from an entity.
*
* @param \Drupal\file\Plugin\Field\FieldType\FileItem|\Drupal\link\Plugin\Field\FieldType\LinkItem $item
* Item for which we are getting render information.
*
* @return object
* Render information for an item.
*/
public function getAudioRenderInfo($item) {
return (object) [
'item' => $item,
'description' => $this
->getAudioDescription($item),
'url' => $this
->getAudioSource($item),
'id' => $this
->getUniqueId($item),
'filetype' => $this
->getFiletype($item),
];
}
/**
* Used to format file entities for use in the twig themes.
*
* @param object $items
* A list of items for which we need to generate render information.
* @param int $limit
* An upper limit for the number of files to return. 0 indicates unlimited.
*
* @return array
* A render array containing files in the proper format for rendering.
*/
public function getItemRenderList($items, $limit = 0) {
$template_files = [];
foreach ($items as $item) {
// If this entity has passed validation, we render it.
if ($this
->validateEntityAgainstPlayer($item)) {
// Get render information for this item.
$renderInfo = $this
->getAudioRenderInfo($item);
// Add the file to the render array.
$template_files[] = $renderInfo;
// Return list if we have hit the limit.
if ($limit > 0 && count($template_files) == $limit) {
return $template_files;
}
}
}
return $template_files;
}
/**
* Used to render list of downloads as an item list.
*
* @param object $items
* A list of items for which we need to generate download links..
* @param array $settings
* An array of additional render settings.
*
* @return array
* A render array containing download links.
*/
public function createDownloadList($items, array $settings) {
// Check if download links are turned on and there are items.
if (!$settings['download_link'] || count($items) == 0) {
return [];
}
$links = [];
// Loop over each item.
foreach ($items as $item) {
if ($this
->validateEntityAgainstPlayer($item)) {
// Get the source URL for this item.
$source_url = $this
->getAudioSource($item);
// Set the download attribute to the filename.
$source_path = $source_url
->getUri();
$filename = basename($source_path);
$attributes = $source_url
->getOption('attributes');
$attributes['download'] = urldecode($filename);
$source_url
->setOption('attributes', $attributes);
// Get the entity description for this item.
$entity_description = $this
->getAudioDescription($item);
// Add the link.
$links[] = [
'link' => Link::fromTextAndUrl($entity_description, $source_url)
->toString(),
];
}
}
return [
'#theme' => 'audiofield_download_links',
'#links' => $links,
];
}
/**
* Used to render a default player (for fallback).
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The uploaded item list.
* @param array $settings
* An array of additional render settings.
*/
public function renderDefaultPlayer(FieldItemListInterface $items, array $settings) {
return [
'audioplayer' => [
'#theme' => 'audioplayer',
'#plugin_id' => 'default',
'#settings' => $settings,
'#files' => $this
->getItemRenderList($items),
],
'downloads' => $this
->createDownloadList($items, $settings),
];
}
}
Classes
Name | Description |
---|---|
AudioFieldPluginBase | Base class for audiofield plugins. Includes global functions. |