Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EWPP-164: Remove duplicated processing code to style a Media entity using the ECL media container #701

Open
wants to merge 6 commits into
base: 2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/developer-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,25 @@ Provides the following factory methods:

- `ImageValueObject::fromImageItem(ImageItem $image_item)`: accepts a \Drupal\image\Plugin\Field\FieldType\ImageItem object.

#### `MediaValueObject`

Used in the following patterns:

- [`media_container`](../templates/patterns/media_container/media_container.ui_patterns.yml)

Provides the following factory methods:

- `MediaValueObject::fromArray(array $values = [])`: accepts an array with the following properties:
- `video`: Embed media HTML code.
- `ratio`: Ratio of the video.
- `sources`: Media resources for media element.
- `tracks`: Text tracks for video elements.
- `image`: ImageValueObject media element.
- `MediaValueObject::fromMediaObject(Media $media, string $image_style = '', string $view_mode = '')`: accepts these values:
- `media`: \Drupal\media\Entity\Media media element.
- `image_style`: Image style.
- `view_mode`: Video display view mode.

[1]: https://www.drupal.org/project/ui_patterns
[2]: https://ui-patterns.readthedocs.io
[3]: https://ui-patterns.readthedocs.io/en/8.x-1.x/content/developer-documentation.html#working-with-pattern-suggestions
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Drupal\media\MediaInterface;
use Drupal\oe_content_event\EventNodeWrapper;
use Drupal\oe_theme\ValueObject\ImageValueObject;
use Drupal\oe_theme\ValueObject\MediaValueObject;
use Drupal\oe_time_caching\Cache\TimeBasedCacheTagGeneratorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

Expand Down Expand Up @@ -200,7 +201,10 @@ protected function addFeaturedMediaThumbnail(array &$build, ContentEntityInterfa
}

$cache->addCacheableDependency($thumbnail->entity);
$build['#fields']['image'] = ImageValueObject::fromImageItem($thumbnail);
$media = [
'image' => ImageValueObject::fromImageItem($thumbnail),
];
$build['#fields']['media'] = MediaValueObject::fromArray($media);

// Only display a caption if we have an image to be captioned by.
/** @var \Drupal\Core\Entity\EntityViewBuilderInterface $view_builder */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ field.formatter.settings.oe_theme_helper_featured_media_formatter:
image_style:
type: string
label: 'Image style'
view_mode:
type: string
label: 'Media view mode'

field.formatter.settings.oe_theme_helper_featured_media_thumbnail_url_formatter:
type: field.formatter.settings.oe_theme_helper_featured_media_formatter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
namespace Drupal\oe_theme_helper\Plugin\Field\FieldFormatter;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\media\MediaInterface;
use Drupal\media\Plugin\media\Source\OEmbed;
use Drupal\oe_media_iframe\Plugin\media\Source\Iframe;
use Drupal\media_avportal\Plugin\media\Source\MediaAvPortalVideoSource;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\oe_theme\ValueObject\MediaValueObject;
use Drupal\Core\Entity\Entity\EntityViewDisplay;

/**
* Display a featured media field using the ECL media container.
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*
* @FieldFormatter(
* id = "oe_theme_helper_featured_media_formatter",
* label = @Translation("Media container"),
Expand All @@ -47,6 +48,13 @@ class FeaturedMediaFormatter extends EntityReferenceFormatterBase {
*/
protected $entityRepository;

/**
* The entity display repository.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected $entityDisplayRepository;

/**
* Constructs a FeaturedMediaFormatter object.
*
Expand All @@ -68,18 +76,21 @@ class FeaturedMediaFormatter extends EntityReferenceFormatterBase {
* The entity type manager.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* The entity display repository.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository) {
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, EntityDisplayRepositoryInterface $entity_display_repository) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
$this->entityTypeManager = $entity_type_manager;
$this->entityRepository = $entity_repository;
$this->entityDisplayRepository = $entity_display_repository;
}

/**
* {@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('entity.repository'));
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('entity.repository'), $container->get('entity_display.repository'));
}

/**
Expand All @@ -88,20 +99,37 @@ public static function create(ContainerInterface $container, array $configuratio
public static function defaultSettings() {
return [
'image_style' => '',
'view_mode' => 'oe_theme_main_content',
] + parent::defaultSettings();
}

/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$view_mode = [];

foreach ($this->entityDisplayRepository->getViewModes('media') as $key => $value) {
if ($value['status']) {
$view_mode[$key] = $value['label'];
}
}

$element['image_style'] = [
'#title' => t('Image style'),
'#title' => $this->t('Image style'),
'#type' => 'select',
'#default_value' => $this->getSetting('image_style'),
'#empty_option' => t('None (original image)'),
'#empty_option' => $this->t('None (original image)'),
'#options' => image_style_options(FALSE),
'#description' => t('Image style to be used if the Media is an image.'),
'#description' => $this->t('Image style to be used if the Media is an image.'),
];
$element['view_mode'] = [
'#title' => $this->t('View mode'),
'#type' => 'select',
'#default_value' => $this->getSetting('view_mode'),
'#required' => TRUE,
'#options' => $view_mode,
'#description' => $this->t('View mode of the media element.'),
];

return $element;
Expand All @@ -120,10 +148,10 @@ public function settingsSummary() {
// their styles in code.
$image_style_setting = $this->getSetting('image_style');
if (isset($image_styles[$image_style_setting])) {
$summary[] = t('@image_style image style', ['@image_style' => $image_styles[$image_style_setting]]);
$summary[] = $this->t('@image_style image style', ['@image_style' => $image_styles[$image_style_setting]]);
}
else {
$summary[] = t('Original image style.');
$summary[] = $this->t('Original image style.');
}

return $summary;
Expand Down Expand Up @@ -154,88 +182,36 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
* The ECL media-container parameters.
*/
protected function viewElement(FieldItemInterface $item, string $langcode): array {
$build = ['#theme' => 'oe_theme_helper_featured_media'];
$params = ['description' => $item->caption];
$pattern = [];
$media = $item->entity;
$cacheability = CacheableMetadata::createFromRenderArray($build);

if (!$media instanceof MediaInterface) {
return [];
return $pattern;
}

$image_style = $this->getSetting('image_style');
$view_mode = $this->getSetting('view_mode');
$cacheability = CacheableMetadata::createFromRenderArray($pattern);
// Retrieve the correct media translation.
$media = $this->entityRepository->getTranslationFromContext($media, $langcode);

// Caches are handled by the formatter usually. Since we are not rendering
// the original render arrays, we need to propagate our caches to the
// oe_theme_helper_featured_media template.
// the original render arrays, we need to propagate our caches.
$cacheability->addCacheableDependency($media);
$cacheability->addCacheableDependency($this->entityTypeManager->getStorage('media_type')->load($media->bundle()));
$cacheability->addCacheableDependency(EntityViewDisplay::collectRenderDisplay($media, $view_mode));

$pattern = [
'#type' => 'pattern',
'#id' => 'media_container',
'#fields' => [
'media' => MediaValueObject::fromMediaObject($media, $image_style, $view_mode),
'description' => $item->caption,
],
];

// Get the media source.
$source = $media->getSource();

if ($source instanceof MediaAvPortalVideoSource || $source instanceof OEmbed || $source instanceof Iframe) {
// Default video aspect ratio is set to 16:9.
$params['ratio'] = '16-9';

// Load information about the media and the display.
$media_type = $this->entityTypeManager->getStorage('media_type')->load($media->bundle());
$cacheability->addCacheableDependency($media_type);
$source_field = $source->getSourceFieldDefinition($media_type);
$display = EntityViewDisplay::collectRenderDisplay($media, 'oe_theme_main_content');
$cacheability->addCacheableDependency($display);
$display_options = $display->getComponent($source_field->getName());
$oembed_type = $source->getMetadata($media, 'type');

// If it is an OEmbed resource, render it and pass it as embeddable data
// only if it is of type video or html.
if ($source instanceof OEmbed && in_array($oembed_type, ['video', 'html'])) {
$params['embedded_media'] = $media->{$source_field->getName()}->view($display_options);
$build['#params'] = $params;
$cacheability->applyTo($build);

return $build;
}

// If its an AvPortal video or an iframe video, render it.
$params['embedded_media'] = $media->{$source_field->getName()}->view($display_options);

// When dealing with iframe videos, also respect its given aspect ratio.
if ($media->bundle() === 'video_iframe') {
$ratio = $media->get('oe_media_iframe_ratio')->value;
$params['ratio'] = str_replace('_', '-', $ratio);
}

$build['#params'] = $params;
$cacheability->applyTo($build);

return $build;
}

// If its an image media, render it and assign it to the image variable.
/** @var \Drupal\image\Plugin\Field\FieldType\ImageItem $thumbnail */
$thumbnail = $media->get('thumbnail')->first();
/** @var \Drupal\Core\Entity\Plugin\DataType\EntityAdapter $file */
$file = $thumbnail->get('entity')->getTarget();
$image_style = $this->getSetting('image_style');
$style = $this->entityTypeManager->getStorage('image_style')->load($image_style);

if ($style) {
// Use image style url if set.
$image_url = $style->buildUrl($file->get('uri')->getString());
$cacheability->addCacheableDependency($image_style);
}
else {
// Use original file url.
$image_url = file_create_url($file->get('uri')->getString());
}

$params['alt'] = $thumbnail->get('alt')->getString();
$params['image'] = $image_url;
$build['#params'] = $params;
$cacheability->applyTo($build);
$cacheability->applyTo($pattern);

return $build;
return $pattern;
}

}
2 changes: 2 additions & 0 deletions modules/oe_theme_helper/src/TwigExtension/TwigExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Drupal\oe_theme_helper\EuropeanUnionLanguages;
use Drupal\smart_trim\Truncate\TruncateHTML;
use Drupal\Core\Template\TwigExtension as CoreTwigExtension;
use Drupal\oe_theme\ValueObject\MediaValueObject;

/**
* Collection of extra Twig extensions as filters and functions.
Expand Down Expand Up @@ -69,6 +70,7 @@ public function getFilters(): array {
new \Twig_SimpleFilter('smart_trim', [$this, 'smartTrim'], ['needs_environment' => TRUE]),
new \Twig_SimpleFilter('is_external_url', [UrlHelper::class, 'isExternal']),
new \Twig_SimpleFilter('filter_empty', [$this, 'filterEmpty']),
new \Twig_SimpleFilter('validate_ratio', [MediaValueObject::class, 'validateRatio']),
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class FeaturedMediaFormatterTest extends AbstractKernelTestBase {
'node',
'media',
'file',
'file_link',
'filter',
'link',
'image',
'views',
'entity_browser',
Expand All @@ -34,13 +36,8 @@ class FeaturedMediaFormatterTest extends AbstractKernelTestBase {
'oe_media',
'oe_media_avportal',
'oe_media_iframe',
'oe_media_oembed_mock',
'media_avportal_mock',
'oe_content_featured_media_field',
'system',
'file_link',
'link',
'options',
];

/**
Expand All @@ -64,7 +61,14 @@ protected function setUp(): void {
'oe_media_avportal',
'oe_media_iframe',
'oe_content_featured_media_field',
'oe_theme_helper',
]);
// Enable and set OpenEuropa Theme as default.
\Drupal::service('theme_installer')->install(['oe_theme']);
\Drupal::configFactory()->getEditable('system.theme')->set('default', 'oe_theme')->save();
// Rebuild the ui_pattern definitions to collect the ones provided by
// oe_theme itself.
\Drupal::service('plugin.manager.ui_patterns')->clearCachedDefinitions();

// Create a content type.
$type = NodeType::create(['name' => 'Test content type', 'type' => 'test_ct']);
Expand Down Expand Up @@ -106,7 +110,7 @@ protected function setUp(): void {
/**
* Test the featured media formatter.
*/
public function testFormatter(): void {
public function testFeaturedMediaFormatter(): void {
$this->container->get('file_system')->copy($this->root . '/core/misc/druplicon.png', 'public://example.jpg');
$image = File::create(['uri' => 'public://example.jpg']);
$image->save();
Expand Down
Loading