easy_360-1.x-dev/src/Plugin/Field/FieldFormatter/Viewer.php
src/Plugin/Field/FieldFormatter/Viewer.php
<?php
namespace Drupal\easy_360\Plugin\Field\FieldFormatter;
use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatterBase;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Renders an image field as an Easy 360 Viewer.
*
* @FieldFormatter(
* id = "easy_360_viewer",
* label = @Translation("Easy 360 viewer"),
* field_types = {
* "image"
* },
* quickedit = {
* "editor" = "image"
* }
* )
*/
class Viewer extends ImageFormatterBase implements
ContainerFactoryPluginInterface {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The image style entity storage.
*
* @var \Drupal\image\ImageStyleStorageInterface
*/
protected $imageStyleStorage;
/**
* Constructs a Viewer 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 settings.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Entity\EntityStorageInterface $image_style_storage
* The image style storage.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation service.
*/
public function __construct(
$plugin_id,
$plugin_definition,
FieldDefinitionInterface $field_definition,
array $settings,
$label,
$view_mode,
array $third_party_settings,
AccountInterface $current_user,
EntityStorageInterface $image_style_storage,
TranslationInterface $string_translation
) {
parent::__construct(
$plugin_id,
$plugin_definition,
$field_definition,
$settings,
$label,
$view_mode,
$third_party_settings
);
$this->currentUser = $current_user;
$this->imageStyleStorage = $image_style_storage;
$this->stringTranslation = $string_translation;
}
/**
* {@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('current_user'),
$container->get('entity_type.manager')->getStorage('image_style'),
$container->get('string_translation')
);
}
/**
* {@inheritdoc}
*
* @I Move image style settings to profiles
* type : improvement
* priority : high
* labels : config
*/
public static function defaultSettings() {
return [
'large_image_style' => '',
'small_image_style' => '',
] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$image_styles = image_style_options(FALSE);
$description_texts = [
'large' => $this->t('It will be used when zooming into the image.'),
'small' => $this->t('It will be used in the viewer.'),
];
// An additional link to the image style configuration page, if the user has
// the relevant permission.
$description_link = Link::fromTextAndUrl(
$this->t('Configure image styles'),
Url::fromRoute('entity.image_style.collection')
);
$description_link = $description_link->toRenderable() + [
'#access' => $this->currentUser->hasPermission('administer image styles'),
];
// Configure the image styles for the large and small images.
$element = [];
foreach (['large', 'small'] as $size) {
$element[$size . '_image_style'] = $this->buildImageStyleSettingForm(
$size,
$image_styles,
$description_texts[$size],
$description_link
);
}
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];
// Styles could be lost because of enabled/disabled modules that define
// their styles in code.
foreach (['large', 'small'] as $size) {
$summary[] = $this->imageStyleSettingSummary($size);
}
return $summary;
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
$files = $this->getEntitiesToView($items, $langcode);
// Early opt-out if the field is empty.
if (empty($files)) {
return $elements;
}
$item_urls = [];
$cache_tags = [];
foreach (['large', 'small'] as $size) {
[$style, $style_cache_tags] = $this->getStyleAndCacheTags($size);
$cache_tags = Cache::mergeTags($cache_tags, $style_cache_tags);
foreach ($files as $delta => $file) {
if (!$style) {
$item_urls[$delta][$size . '_image'] = $file->createFileUrl();
}
else {
$item_urls[$delta][$size . '_image'] = file_url_transform_relative(
$style->buildUrl($file->getFileUri())
);
}
}
}
$elements = [
'#theme' => 'easy_360_viewer',
'#items' => $item_urls,
'#attached' => ['library' => ['easy_360/viewer']],
'#cache' => [
'tags' => $cache_tags,
],
];
return $elements;
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() {
// If this formatter uses valid image styles to display the small and large
// images of the 360 viewer, add the image styles configuration entity as
// dependencies.
$dependencies = parent::calculateDependencies();
$style_ids = [
$this->getSetting('large_image_style'),
$this->getSetting('small_image_style'),
];
foreach ($style_ids as $style_id) {
if (!$style_id) {
continue;
}
$style = $this->imageStyleStorage->load($style_id);
if (!$style) {
continue;
}
$key = $style->getConfigDependencyKey();
$dependencies[$key][] = $style->getConfigDependencyName();
}
return $dependencies;
}
/**
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
$changed = parent::onDependencyRemoval($dependencies);
$style_ids = [
$this->getSetting('large_image_style'),
$this->getSetting('small_image_style'),
];
foreach ($style_ids as $style_id) {
if (!$style_id) {
continue;
}
$style = $this->imageStyleStorage->load($style_id);
if (!$style) {
continue;
}
$key = $style->getConfigDependencyKey();
$name = $style->getConfigDependencyName();
if (!empty($dependencies[$key][$name])) {
$replacement_id = $this->imageStyleStorage->getReplacementId($style_id);
// If a valid replacement has been provided in the storage, replace the
// image style with the replacement and signal that the formatter plugin
// settings were updated.
if (!$replacement_id) {
continue;
}
if ($this->imageStyleStorage->load($replacement_id)) {
$this->setSetting('image_style', $replacement_id);
$changed = TRUE;
}
}
}
return $changed;
}
/**
* Generates the form for the image style settings.
*
* @param string $size
* The Easy 360 Viewer size that the image style will be used for
* i.e. `large` or `small`.
* @param array $image_styles
* Array of all image styles with both key and value set to the style name.
* @param \Drupal\Core\StringTranslation\TranslatableMarkup $description_text
* The translated text that will be used as the description of the form
* field.
* @param array $description_link
* The render array for an additional link that will be appended to the
* description.
*
* @return array
* The render array for the image style setting of the given size.
*/
protected function buildImageStyleSettingForm(
$size,
array $image_styles,
TranslatableMarkup $description_text,
array $description_link
) {
return [
'#title' => $this->t(
'@size image style',
['@size' => ucfirst($size)]
),
'#type' => 'select',
'#default_value' => $this->getSetting($size . '_image_style'),
'#empty_option' => $this->t('None (original image)'),
'#options' => $image_styles,
'#description' => [
['#markup' => $description_text . '<br />'],
$description_link,
],
];
}
/**
* Generates the summary for the image style settings.
*
* @param string $size
* The Easy 360 Viewer size that the image style will be used for
* i.e. `large` or `small`.
*
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The setting summary.
*/
protected function imageStyleSettingSummary($size) {
$style_id = $this->getSetting($size . '_image_style');
$styles = image_style_options(FALSE);
// Unset possible 'No defined styles' option.
unset($styles['']);
if (!isset($styles[$style_id])) {
return $this->t('Original image');
}
return $this->t(
'@size image style: @style',
[
'@size' => ucfirst($size),
'@style' => $styles[$style_id],
]
);
}
/**
* Returns the image style entity and its cache tags for the given size.
*
* @param string $size
* The Easy 360 Viewer size that the image style will be used for
* i.e. `large` or `small`.
*
* @return array
* An array containing the image style entity as the first element and the
* cache tags array as the second.
*/
protected function getStyleAndCacheTags($size) {
$style = NULL;
$cache_tags = [];
$style_id = $this->getSetting($size . '_image_style');
if ($style_id) {
$style = $this->imageStyleStorage->load($style_id);
$cache_tags = $style->getCacheTags();
}
return [$style, $cache_tags];
}
}
