3 namespace Drupal\media\Plugin\Field\FieldFormatter;
5 use Drupal\Core\Cache\CacheableMetadata;
6 use Drupal\Core\Config\ConfigFactoryInterface;
7 use Drupal\Core\Field\FieldDefinitionInterface;
8 use Drupal\Core\Field\FieldItemListInterface;
9 use Drupal\Core\Field\FormatterBase;
10 use Drupal\Core\Form\FormStateInterface;
11 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
12 use Drupal\Core\Messenger\MessengerInterface;
13 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
15 use Drupal\media\Entity\MediaType;
16 use Drupal\media\IFrameUrlHelper;
17 use Drupal\media\OEmbed\Resource;
18 use Drupal\media\OEmbed\ResourceException;
19 use Drupal\media\OEmbed\ResourceFetcherInterface;
20 use Drupal\media\OEmbed\UrlResolverInterface;
21 use Drupal\media\Plugin\media\Source\OEmbedInterface;
22 use Symfony\Component\DependencyInjection\ContainerInterface;
25 * Plugin implementation of the 'oembed' formatter.
28 * This is an internal part of the oEmbed system and should only be used by
29 * oEmbed-related code in Drupal core.
33 * label = @Translation("oEmbed content"),
41 class OEmbedFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
44 * The messenger service.
46 * @var \Drupal\Core\Messenger\MessengerInterface
51 * The oEmbed resource fetcher.
53 * @var \Drupal\media\OEmbed\ResourceFetcherInterface
55 protected $resourceFetcher;
58 * The oEmbed URL resolver service.
60 * @var \Drupal\media\OEmbed\UrlResolverInterface
62 protected $urlResolver;
67 * @var \Psr\Log\LoggerInterface
72 * The media settings config.
74 * @var \Drupal\Core\Config\ImmutableConfig
79 * The iFrame URL helper service.
81 * @var \Drupal\media\IFrameUrlHelper
83 protected $iFrameUrlHelper;
86 * Constructs an OEmbedFormatter instance.
88 * @param string $plugin_id
89 * The plugin ID for the formatter.
90 * @param mixed $plugin_definition
91 * The plugin implementation definition.
92 * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
93 * The definition of the field to which the formatter is associated.
94 * @param array $settings
95 * The formatter settings.
96 * @param string $label
97 * The formatter label display setting.
98 * @param string $view_mode
100 * @param array $third_party_settings
101 * Any third party settings.
102 * @param \Drupal\Core\Messenger\MessengerInterface $messenger
103 * The messenger service.
104 * @param \Drupal\media\OEmbed\ResourceFetcherInterface $resource_fetcher
105 * The oEmbed resource fetcher service.
106 * @param \Drupal\media\OEmbed\UrlResolverInterface $url_resolver
107 * The oEmbed URL resolver service.
108 * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
109 * The logger factory service.
110 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
111 * The config factory service.
112 * @param \Drupal\media\IFrameUrlHelper $iframe_url_helper
113 * The iFrame URL helper service.
115 public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, MessengerInterface $messenger, ResourceFetcherInterface $resource_fetcher, UrlResolverInterface $url_resolver, LoggerChannelFactoryInterface $logger_factory, ConfigFactoryInterface $config_factory, IFrameUrlHelper $iframe_url_helper) {
116 parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
117 $this->messenger = $messenger;
118 $this->resourceFetcher = $resource_fetcher;
119 $this->urlResolver = $url_resolver;
120 $this->logger = $logger_factory->get('media');
121 $this->config = $config_factory->get('media.settings');
122 $this->iFrameUrlHelper = $iframe_url_helper;
128 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
132 $configuration['field_definition'],
133 $configuration['settings'],
134 $configuration['label'],
135 $configuration['view_mode'],
136 $configuration['third_party_settings'],
137 $container->get('messenger'),
138 $container->get('media.oembed.resource_fetcher'),
139 $container->get('media.oembed.url_resolver'),
140 $container->get('logger.factory'),
141 $container->get('config.factory'),
142 $container->get('media.oembed.iframe_url_helper')
149 public static function defaultSettings() {
153 ] + parent::defaultSettings();
159 public function viewElements(FieldItemListInterface $items, $langcode) {
161 $max_width = $this->getSetting('max_width');
162 $max_height = $this->getSetting('max_height');
164 foreach ($items as $delta => $item) {
165 $main_property = $item->getFieldDefinition()->getFieldStorageDefinition()->getMainPropertyName();
166 $value = $item->{$main_property};
173 $resource_url = $this->urlResolver->getResourceUrl($value, $max_width, $max_height);
174 $resource = $this->resourceFetcher->fetchResource($resource_url);
176 catch (ResourceException $exception) {
177 $this->logger->error("Could not retrieve the remote URL (@url).", ['@url' => $value]);
181 if ($resource->getType() === Resource::TYPE_LINK) {
183 '#title' => $resource->getTitle(),
185 '#url' => Url::fromUri($value),
188 elseif ($resource->getType() === Resource::TYPE_PHOTO) {
191 '#uri' => $resource->getUrl()->toString(),
192 '#width' => $max_width ?: $resource->getWidth(),
193 '#height' => $max_height ?: $resource->getHeight(),
197 $url = Url::fromRoute('media.oembed_iframe', [], [
200 'max_width' => $max_width,
201 'max_height' => $max_height,
202 'hash' => $this->iFrameUrlHelper->getHash($value, $max_width, $max_height),
206 $domain = $this->config->get('iframe_domain');
208 $url->setOption('base_url', $domain);
211 // Render videos and rich content in an iframe for security reasons.
212 // @see: https://oembed.com/#section3
214 '#type' => 'html_tag',
217 'src' => $url->toString(),
219 'scrolling' => FALSE,
220 'allowtransparency' => TRUE,
221 'width' => $max_width ?: $resource->getWidth(),
222 'height' => $max_height ?: $resource->getHeight(),
226 CacheableMetadata::createFromObject($resource)
227 ->addCacheTags($this->config->getCacheTags())
228 ->applyTo($element[$delta]);
237 public function settingsForm(array $form, FormStateInterface $form_state) {
238 return parent::settingsForm($form, $form_state) + [
241 '#title' => $this->t('Maximum width'),
242 '#default_value' => $this->getSetting('max_width'),
245 '#field_suffix' => $this->t('pixels'),
250 '#title' => $this->t('Maximum height'),
251 '#default_value' => $this->getSetting('max_height'),
254 '#field_suffix' => $this->t('pixels'),
263 public function settingsSummary() {
264 $summary = parent::settingsSummary();
265 if ($this->getSetting('max_width') && $this->getSetting('max_height')) {
266 $summary[] = $this->t('Maximum size: %max_width x %max_height pixels', [
267 '%max_width' => $this->getSetting('max_width'),
268 '%max_height' => $this->getSetting('max_height'),
271 elseif ($this->getSetting('max_width')) {
272 $summary[] = $this->t('Maximum width: %max_width pixels', [
273 '%max_width' => $this->getSetting('max_width'),
276 elseif ($this->getSetting('max_height')) {
277 $summary[] = $this->t('Maximum height: %max_height pixels', [
278 '%max_height' => $this->getSetting('max_height'),
287 public static function isApplicable(FieldDefinitionInterface $field_definition) {
288 if ($field_definition->getTargetEntityTypeId() !== 'media') {
292 if (parent::isApplicable($field_definition)) {
293 $media_type = $field_definition->getTargetBundle();
296 $media_type = MediaType::load($media_type);
297 return $media_type && $media_type->getSource() instanceof OEmbedInterface;