PageRenderTime 27ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/core/modules/media/src/Plugin/Field/FieldFormatter/OEmbedFormatter.php

http://github.com/drupal/drupal
PHP | 316 lines | 190 code | 27 blank | 99 comment | 11 complexity | 3f29d0ce7fa71480e371ef8fb9b0e439 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. namespace Drupal\media\Plugin\Field\FieldFormatter;
  3. use Drupal\Core\Cache\CacheableMetadata;
  4. use Drupal\Core\Config\ConfigFactoryInterface;
  5. use Drupal\Core\Field\FieldDefinitionInterface;
  6. use Drupal\Core\Field\FieldItemListInterface;
  7. use Drupal\Core\Field\FormatterBase;
  8. use Drupal\Core\Form\FormStateInterface;
  9. use Drupal\Core\Logger\LoggerChannelFactoryInterface;
  10. use Drupal\Core\Messenger\MessengerInterface;
  11. use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
  12. use Drupal\Core\Url;
  13. use Drupal\media\Entity\MediaType;
  14. use Drupal\media\IFrameUrlHelper;
  15. use Drupal\media\OEmbed\Resource;
  16. use Drupal\media\OEmbed\ResourceException;
  17. use Drupal\media\OEmbed\ResourceFetcherInterface;
  18. use Drupal\media\OEmbed\UrlResolverInterface;
  19. use Drupal\media\Plugin\media\Source\OEmbedInterface;
  20. use Symfony\Component\DependencyInjection\ContainerInterface;
  21. /**
  22. * Plugin implementation of the 'oembed' formatter.
  23. *
  24. * @internal
  25. * This is an internal part of the oEmbed system and should only be used by
  26. * oEmbed-related code in Drupal core.
  27. *
  28. * @FieldFormatter(
  29. * id = "oembed",
  30. * label = @Translation("oEmbed content"),
  31. * field_types = {
  32. * "link",
  33. * "string",
  34. * "string_long",
  35. * },
  36. * )
  37. */
  38. class OEmbedFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
  39. /**
  40. * The messenger service.
  41. *
  42. * @var \Drupal\Core\Messenger\MessengerInterface
  43. */
  44. protected $messenger;
  45. /**
  46. * The oEmbed resource fetcher.
  47. *
  48. * @var \Drupal\media\OEmbed\ResourceFetcherInterface
  49. */
  50. protected $resourceFetcher;
  51. /**
  52. * The oEmbed URL resolver service.
  53. *
  54. * @var \Drupal\media\OEmbed\UrlResolverInterface
  55. */
  56. protected $urlResolver;
  57. /**
  58. * The logger service.
  59. *
  60. * @var \Psr\Log\LoggerInterface
  61. */
  62. protected $logger;
  63. /**
  64. * The media settings config.
  65. *
  66. * @var \Drupal\Core\Config\ImmutableConfig
  67. */
  68. protected $config;
  69. /**
  70. * The iFrame URL helper service.
  71. *
  72. * @var \Drupal\media\IFrameUrlHelper
  73. */
  74. protected $iFrameUrlHelper;
  75. /**
  76. * Constructs an OEmbedFormatter instance.
  77. *
  78. * @param string $plugin_id
  79. * The plugin ID for the formatter.
  80. * @param mixed $plugin_definition
  81. * The plugin implementation definition.
  82. * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
  83. * The definition of the field to which the formatter is associated.
  84. * @param array $settings
  85. * The formatter settings.
  86. * @param string $label
  87. * The formatter label display setting.
  88. * @param string $view_mode
  89. * The view mode.
  90. * @param array $third_party_settings
  91. * Any third party settings.
  92. * @param \Drupal\Core\Messenger\MessengerInterface $messenger
  93. * The messenger service.
  94. * @param \Drupal\media\OEmbed\ResourceFetcherInterface $resource_fetcher
  95. * The oEmbed resource fetcher service.
  96. * @param \Drupal\media\OEmbed\UrlResolverInterface $url_resolver
  97. * The oEmbed URL resolver service.
  98. * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
  99. * The logger factory service.
  100. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
  101. * The config factory service.
  102. * @param \Drupal\media\IFrameUrlHelper $iframe_url_helper
  103. * The iFrame URL helper service.
  104. */
  105. 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) {
  106. parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
  107. $this->messenger = $messenger;
  108. $this->resourceFetcher = $resource_fetcher;
  109. $this->urlResolver = $url_resolver;
  110. $this->logger = $logger_factory->get('media');
  111. $this->config = $config_factory->get('media.settings');
  112. $this->iFrameUrlHelper = $iframe_url_helper;
  113. }
  114. /**
  115. * {@inheritdoc}
  116. */
  117. public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
  118. return new static(
  119. $plugin_id,
  120. $plugin_definition,
  121. $configuration['field_definition'],
  122. $configuration['settings'],
  123. $configuration['label'],
  124. $configuration['view_mode'],
  125. $configuration['third_party_settings'],
  126. $container->get('messenger'),
  127. $container->get('media.oembed.resource_fetcher'),
  128. $container->get('media.oembed.url_resolver'),
  129. $container->get('logger.factory'),
  130. $container->get('config.factory'),
  131. $container->get('media.oembed.iframe_url_helper')
  132. );
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. public static function defaultSettings() {
  138. return [
  139. 'max_width' => 0,
  140. 'max_height' => 0,
  141. ] + parent::defaultSettings();
  142. }
  143. /**
  144. * {@inheritdoc}
  145. */
  146. public function viewElements(FieldItemListInterface $items, $langcode) {
  147. $element = [];
  148. $max_width = $this->getSetting('max_width');
  149. $max_height = $this->getSetting('max_height');
  150. foreach ($items as $delta => $item) {
  151. $main_property = $item->getFieldDefinition()->getFieldStorageDefinition()->getMainPropertyName();
  152. $value = $item->{$main_property};
  153. if (empty($value)) {
  154. continue;
  155. }
  156. try {
  157. $resource_url = $this->urlResolver->getResourceUrl($value, $max_width, $max_height);
  158. $resource = $this->resourceFetcher->fetchResource($resource_url);
  159. }
  160. catch (ResourceException $exception) {
  161. $this->logger->error("Could not retrieve the remote URL (@url).", ['@url' => $value]);
  162. continue;
  163. }
  164. if ($resource->getType() === Resource::TYPE_LINK) {
  165. $element[$delta] = [
  166. '#title' => $resource->getTitle(),
  167. '#type' => 'link',
  168. '#url' => Url::fromUri($value),
  169. ];
  170. }
  171. elseif ($resource->getType() === Resource::TYPE_PHOTO) {
  172. $element[$delta] = [
  173. '#theme' => 'image',
  174. '#uri' => $resource->getUrl()->toString(),
  175. '#width' => $max_width ?: $resource->getWidth(),
  176. '#height' => $max_height ?: $resource->getHeight(),
  177. ];
  178. }
  179. else {
  180. $url = Url::fromRoute('media.oembed_iframe', [], [
  181. 'query' => [
  182. 'url' => $value,
  183. 'max_width' => $max_width,
  184. 'max_height' => $max_height,
  185. 'hash' => $this->iFrameUrlHelper->getHash($value, $max_width, $max_height),
  186. ],
  187. ]);
  188. $domain = $this->config->get('iframe_domain');
  189. if ($domain) {
  190. $url->setOption('base_url', $domain);
  191. }
  192. // Render videos and rich content in an iframe for security reasons.
  193. // @see: https://oembed.com/#section3
  194. $element[$delta] = [
  195. '#type' => 'html_tag',
  196. '#tag' => 'iframe',
  197. '#attributes' => [
  198. 'src' => $url->toString(),
  199. 'frameborder' => 0,
  200. 'scrolling' => FALSE,
  201. 'allowtransparency' => TRUE,
  202. 'width' => $max_width ?: $resource->getWidth(),
  203. 'height' => $max_height ?: $resource->getHeight(),
  204. 'class' => ['media-oembed-content'],
  205. ],
  206. '#attached' => [
  207. 'library' => [
  208. 'media/oembed.formatter',
  209. ],
  210. ],
  211. ];
  212. // An empty title attribute will disable title inheritance, so only
  213. // add it if the resource has a title.
  214. $title = $resource->getTitle();
  215. if ($title) {
  216. $element[$delta]['#attributes']['title'] = $title;
  217. }
  218. CacheableMetadata::createFromObject($resource)
  219. ->addCacheTags($this->config->getCacheTags())
  220. ->applyTo($element[$delta]);
  221. }
  222. }
  223. return $element;
  224. }
  225. /**
  226. * {@inheritdoc}
  227. */
  228. public function settingsForm(array $form, FormStateInterface $form_state) {
  229. return parent::settingsForm($form, $form_state) + [
  230. 'max_width' => [
  231. '#type' => 'number',
  232. '#title' => $this->t('Maximum width'),
  233. '#default_value' => $this->getSetting('max_width'),
  234. '#size' => 5,
  235. '#maxlength' => 5,
  236. '#field_suffix' => $this->t('pixels'),
  237. '#min' => 0,
  238. ],
  239. 'max_height' => [
  240. '#type' => 'number',
  241. '#title' => $this->t('Maximum height'),
  242. '#default_value' => $this->getSetting('max_height'),
  243. '#size' => 5,
  244. '#maxlength' => 5,
  245. '#field_suffix' => $this->t('pixels'),
  246. '#min' => 0,
  247. ],
  248. ];
  249. }
  250. /**
  251. * {@inheritdoc}
  252. */
  253. public function settingsSummary() {
  254. $summary = parent::settingsSummary();
  255. if ($this->getSetting('max_width') && $this->getSetting('max_height')) {
  256. $summary[] = $this->t('Maximum size: %max_width x %max_height pixels', [
  257. '%max_width' => $this->getSetting('max_width'),
  258. '%max_height' => $this->getSetting('max_height'),
  259. ]);
  260. }
  261. elseif ($this->getSetting('max_width')) {
  262. $summary[] = $this->t('Maximum width: %max_width pixels', [
  263. '%max_width' => $this->getSetting('max_width'),
  264. ]);
  265. }
  266. elseif ($this->getSetting('max_height')) {
  267. $summary[] = $this->t('Maximum height: %max_height pixels', [
  268. '%max_height' => $this->getSetting('max_height'),
  269. ]);
  270. }
  271. return $summary;
  272. }
  273. /**
  274. * {@inheritdoc}
  275. */
  276. public static function isApplicable(FieldDefinitionInterface $field_definition) {
  277. if ($field_definition->getTargetEntityTypeId() !== 'media') {
  278. return FALSE;
  279. }
  280. if (parent::isApplicable($field_definition)) {
  281. $media_type = $field_definition->getTargetBundle();
  282. if ($media_type) {
  283. $media_type = MediaType::load($media_type);
  284. return $media_type && $media_type->getSource() instanceof OEmbedInterface;
  285. }
  286. }
  287. return FALSE;
  288. }
  289. }