monster_menus-9.0.x-dev/modules/mm_media/mm_media.module
modules/mm_media/mm_media.module
<?php
/**
* @file
* UI for uploading media nodes
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Image\Image;
use Drupal\Core\Render\Element;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\file\Entity\File;
use Drupal\file\FileInterface;
use Drupal\media\Entity\Media as MediaEntity;
use Drupal\mm_media\Plugin\EntityBrowser\Widget\MMTree;
use Drupal\mm_media\Plugin\MMTreeBrowserDisplay\Media;
use Drupal\monster_menus\Constants;
use Drupal\monster_menus\Plugin\MMTreeBrowserDisplay\Groups;
use Drupal\monster_menus\Plugin\MMTreeBrowserDisplay\Nodes;
use Drupal\node\Entity\Node;
use Drupal\user\Entity\User;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Mime\Header\UnstructuredHeader;
use Symfony\Component\Routing\RouteCollection;
/**
* Implements hook_theme
*/
function mm_media_theme() {
return [
'mm_browser_thumbnail' => [
'variables' => [
'file' => NULL,
'style_name' => '',
'mode' => '',
'mmtid' => 0,
'min_wh' => NULL,
'onclick' => '',
'attributes' => [],
'div_state' => '',
'short_title' => '',
'link' => '',
'thumbnail' => '',
],
],
];
}
/**
* Implements hook_help
*/
function mm_media_help($path, $arg = NULL) {
switch ($path) {
case 'admin/help#file upload':
return t('This module is used to create and administer media (images, PDF files, Word documents, etc.) for your site. Each media item is stored as a post. For images, thumbnails of the original item are generated automatically.
There are three default sizes: thumbnail, icon and original.
The thumbnail size is shown as the preview for image posts and when browsing image galleries.
"Original" is the default size when first displaying an image.');
case 'admin/modules#description':
return t('Allows uploading of media and inserting media into content.');
case 'node/add#media':
return t('Upload images, PDFs, audio and other media files (after uploading files, you can insert them into articles).');
}
}
/**
* Implements hook_mm_browser_navigation().
*/
function mm_media_mm_browser_navigation($mode, $top_mmtid) {
if (!in_array($mode, Groups::supportedModes())) {
$user = \Drupal::currentUser();
if (isset($user->user_file_mmtid) && is_numeric($user->user_file_mmtid) && $user->user_file_mmtid > 0) {
return '<button onclick="Drupal.mm_browser_reload_data(\'' . mm_content_get_full_path($user->user_file_mmtid) . '\');" class="ui-button ui-widget ui-corner-all" id="my-uploaded-files-link">' . t('My uploaded files') . '</button>';
}
}
}
/**
* Implements hook_field_widget_single_element_WIDGET_TYPE_form_alter().
*/
function mm_media_field_widget_single_element_entity_browser_entity_reference_form_alter(&$element, FormStateInterface $form_state, &$context) {
foreach ($element['current']['items'] as &$item) {
$item['edit_button']['#value'] = t('Edit Properties');
}
if ($form_state->getBuildInfo()['callback_object']->getEntity()->getEntityTypeId() == 'node') {
$element['#process'][] = '_mm_media_entity_browser_process';
}
}
function _mm_media_entity_browser_process(array $element, FormStateInterface $form_state, &$complete_form) {
if (isset($complete_form['actions']['submit']['#submit']) && isset($element['entity_browser'])) {
$entity = $form_state->getBuildInfo()['callback_object']->getEntity();
$media_id = $entity->id() . ':' . $complete_form['#form_id'] . ':' . implode(':', $element['#field_parents']) . ':' . $element['#field_name'];
$media_id_draft = MMTree::getDraftID($media_id);
$element['entity_browser']['#widget_context'] = [
'mm_media_id' => $media_id,
'mm_media_id_draft' => $media_id_draft,
] + ($element['entity_browser']['#widget_context'] ?? []);
$storage = &$form_state->getStorage();
$storage['mm_media']['ids'][$media_id] = $media_id_draft;
$submit_handlers = &$complete_form['actions']['submit']['#submit'];
if (empty($submit_handlers) || !in_array('_mm_media_entity_browser_submit', $submit_handlers)) {
$submit_handlers[] = '_mm_media_entity_browser_submit';
}
}
return $element;
}
function _mm_media_entity_browser_submit(array $element, FormStateInterface $form_state) {
// Find any draft Media items and convert them to final items.
$storage = &$form_state->getStorage();
if (!empty($storage['mm_media']['ids'])) {
foreach ($storage['mm_media']['ids'] as $media_id => $media_id_draft) {
if ($draft_media = MMTree::getMedia($media_id_draft)) {
// If there is already a final version, delete it.
if ($final_media = MMTree::getMedia($media_id, TRUE)) {
$final_media->delete();
}
// Change draft to final.
$draft_media
->setRevisionLogMessage($media_id)
->save();
}
}
unset($storage['mm_media']);
}
}
/**
* Implements hook_form_FORMID_alter().
*/
function mm_media_form_media_admin_config_browser_alter(&$form, &$form_state) {
if (isset($form['media__file_extensions'])) {
$form['media__file_extensions']['#type'] = 'textarea';
}
}
/**
* Implements hook_form_FORMID_alter().
*/
function mm_media_form_system_performance_settings_alter(&$form, &$form_state) {
$form['caching']['mm_media_cache_public_media'] = [
'#type' => 'checkbox',
'#title' => t('Allow external caching of world-readable media files'),
'#default_value' => \Drupal::config('mm_media.settings')->get('cache_public_media'),
'#description' => t('If enabled, media files will be checked to see if they are readable by everyone, even if the current user is logged-in. This has a slight performance penalty for the first hit, but subsequent hits are faster because they are cached.'),
'#weight' => -0.5,
];
$form['caching']['mm_media_cache_images_permanently'] = [
'#type' => 'checkbox',
'#title' => t('Cache world-readable images permanently'),
'#default_value' => \Drupal::config('mm_media.settings')->get('cache_images_permanently'),
'#description' => t('If enabled, world-readable images with URLs containing <code>?__=value</code> cache-buster strings will be cached permanently. Other media types will use the <strong>Browser and proxy cache maximum age</strong> setting, below.'),
'#weight' => -0.4,
];
$form['#submit'][] = '_mm_media_form_system_performance_settings_submit';
}
function _mm_media_form_system_performance_settings_submit(&$form, FormStateInterface $form_state) {
\Drupal::service('config.factory')
->getEditable('mm_media.settings')
->set('cache_public_media', $form_state->getValue('mm_media_cache_public_media'))
->set('cache_images_permanently', $form_state->getValue('mm_media_cache_images_permanently'))
->save();
}
/**
* Implements hook_form_FORMID_alter().
*/
function mm_media_form_entity_browser_widgets_config_form_alter(&$form) {
// Make file extensions for element a textarea.
foreach (Element::children($form['widgets']['table']) as $child) {
if (isset($form['widgets']['table'][$child]['form']['extensions'])) {
$form['widgets']['table'][$child]['form']['extensions']['#type'] = 'textarea';
// In some cases the limit on the length of all extensions is set to 256.
unset($form['widgets']['table'][$child]['form']['extensions']['#maxlength']);
}
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function mm_media_form_media_form_alter(&$form, FormStateInterface $form_state) {
$current_request = \Drupal::request();
$route = $current_request->get('_route');
if ($route == 'mm_media_library.edit_media' && $form_state->getFormObject() instanceof EntityForm) {
// Hide all actions except Save.
foreach (Element::children($form['actions']) as $key) {
if ($key == 'submit') {
// Use Ajax.
unset($form['actions']['submit']['#ajax_processed']);
$form['actions']['submit']['#ajax'] = [
'url' => Url::createFromRequest($current_request),
'disable-refocus' => TRUE,
];
}
else {
$form['actions'][$key]['#access'] = FALSE;
}
}
}
}
/**
* Theme a thumbnail.
*
* @param $variables
* An associative array containing:
* - file: A file object to display.
* - mode: Media::BROWSER_MODE_MEDIA or another mode.
* - mmtid: Currently unused. Holds the mmtid of the page.
* - (optional) style_name: The name of the image style to use, such as
* 'thumbnail'.
* - (optional) onclick: Javascript onclick event code for
* Nodes::BROWSER_MODE_NODE.
* @return array|null
* Render array
* @ingroup themeable
*/
function template_preprocess_mm_browser_thumbnail(&$variables) {
$obj = $variables['file'];
$style_name = empty($variables['style_name']) ? 'thumbnail' : $variables['style_name'];
if (empty($obj)) {
return [];
}
if ($obj->filemime && str_contains($obj->filemime, 'image')) {
$filename = $obj->filename;
$thumbnail = [
'#theme' => 'image_style',
'#uri' => $obj->uri,
'#style_name' => $style_name,
'#alt' => t('Thumbnail for @filename.', ['@filename' => $filename]),
];
}
// Display the file icon for other file types.
else {
$media = $obj->mid > 0 ? MediaEntity::load($obj->mid) : NULL;
if ($thumbnail_uri = $media ? $media->getSource()->getMetadata($media, 'thumbnail_uri') : NULL) {
$filename = $obj->filename ?: basename($thumbnail_uri);
$thumbnail = [
'#theme' => 'image_style',
'#style_name' => 'media_library',
'#uri' => $thumbnail_uri,
'#alt' => t('Thumbnail for @filename.', ['@filename' => $filename]),
];
}
else if (($thumbnail_fid = $media->thumbnail->target_id ?? NULL) && ($thumbnail_file = File::load($thumbnail_fid))) {
$filename = basename($thumbnail_file->getFilename());
$thumbnail = [
'#theme' => 'image_style',
'#uri' => $thumbnail_file->getFileUri(),
'#style_name' => $style_name,
'#alt' => t('Thumbnail for @filename.', ['@filename' => $filename]),
];
}
else {
$thumbnail = [];
$type = $obj->filemime ? explode('/', $obj->filemime)[0] : 'file';
$media = MediaEntity::create(['bundle' => $type]);
$filename = $obj->filename ?? (string) t('file');
foreach ($media->getFieldDefinitions() as $field) {
if ($field instanceof FieldConfig && $field->getFieldStorageDefinition()->getSetting('target_type') === 'file') {
$media->set($field->getName(), ['target_id' => $obj->fid]);
$media->set('mid', 0);
$media->updateQueuedThumbnail();
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('media');
$thumbnail = $view_builder->view($media, 'media_library');
break;
}
}
}
}
$link = match ($variables['mode']) {
Media::BROWSER_MODE_MEDIA => "return Drupal.mm_browser_gallery_add($variables[mmtid], '" . mm_ui_js_escape($filename) . "', " . ($obj->fid < 0 ? 0 : intval($obj->fid)) . ', ' . ($obj->mid < 0 ? 0 : intval($obj->mid)) . ');',
Nodes::BROWSER_MODE_NODE => $variables['onclick'],
default => '#',
};
$div_attributes = new Attribute(['class' => 'ui-state-default']);
if ($obj->uri && is_array($variables['min_wh']) && ($variables['min_wh'][0] || $variables['min_wh'][1])) {
/** @var Image $image */
$image = Drupal::service('image.factory')->get($obj->uri);
if ($image && ($variables['min_wh'][0] && $image->getWidth() < $variables['min_wh'][0] || $variables['min_wh'][1] && $image->getHeight() < $variables['min_wh'][1])) {
$msg = t('The image must be at least @min pixels. This image is @this.', ['@min' => $variables['min_wh'][0] . ' x ' . $variables['min_wh'][1], '@this' => $image->getWidth() . ' x ' . $image->getHeight()]);
$link = "alert('" . mm_ui_js_escape($msg) . "'); event.stopPropagation();";
$div_attributes = new Attribute(['class' => 'ui-state-disabled', 'style' => 'pointer-events: initial']);
}
}
if ($obj->filename && $obj->filesize) {
$short_title = Html::escape($obj->filename);
$long_title = empty($obj->title) ?
t('@name (@size)', ['@name' => $short_title, '@size' => mm_format_size($obj->filesize)]) :
t('@name (@size) on page "@title"', ['@name' => $obj->filename, '@title' => $obj->title, '@size' => mm_format_size($obj->filesize)]);
}
else {
$url = $media ? $media->getSource()->getMetadata($media, 'url') : '';
$long_title = $short_title = $url ?: t('Media item');
}
$variables['attributes'] = new Attribute([
'onclick' => $link,
'title' => Html::escape($long_title),
]);
$variables['div_attributes'] = $div_attributes;
$variables['short_title'] = $short_title;
$variables['link'] = $link;
$variables['thumbnail'] = $thumbnail;
}
function mm_media_mm_routing_alter(RouteCollection $collection) {
if ($route = $collection->get('media.filter.preview')) {
// The default CKEditor media preview code can let through <a> tags, which
// cause the user to leave the editor if they are accidentally clicked.
// Replace the built-in handler with our own, which sanitizes <a> tags.
$route->setDefault('_controller', '\Drupal\mm_media\Controller\MediaFilterController::preview');
}
}
/**
* Implements module_implements_alter().
*/
function mm_media_module_implements_alter(&$impls, $hook) {
if ($hook == 'file_download') {
// Don't use file_file_download() because it prevents the correct cache-
// control headers from being returned in the case where the file is
// world-readable via MM.
unset($impls['file']);
// Don't use image_file_download() because it calls file_file_download()
// directly.
unset($impls['image']);
}
}
/**
* Implements hook_ENTITY_TYPE_access() for the Media entity.
*/
function mm_media_media_access(EntityInterface $entity, $operation, AccountInterface $account) {
// If this is a view operation, test readability.
if (str_starts_with($operation, 'view') || $operation == 'download') {
foreach ($entity->getFieldDefinitions() as $field) {
if ($field instanceof FieldConfig && $field->getFieldStorageDefinition()->getSetting('target_type') === 'file') {
if ($fid = $entity->get($field->getName())) {
if ($file = File::load($fid[0]->target_id)) {
return mm_media_file_access($file, 'view', $account);
}
}
}
}
}
// No opinion.
return AccessResult::neutral();
}
/**
* Implements hook_ENTITY_TYPE_access() for the File entity.
*/
function mm_media_file_access(FileInterface $file, $operation, AccountInterface $account) {
// If this is a view operation, test readability.
if (str_starts_with($operation, 'view') || $operation == 'download') {
$readable = mm_media_is_readable($file->getFileUri(), $account, [$file]);
if ($readable === -1) {
return AccessResult::forbidden();
}
if ($readable === TRUE) {
return AccessResult::allowed();
}
}
// No opinion.
return AccessResult::neutral();
}
/**
* Implements hook_ENTITY_TYPE_insert() for node entities.
*/
function mm_media_node_insert(EntityInterface $node) {
if (!empty($node->__get('body')[0])) {
$dom = Html::load($node->__get('body')[0]->value ?? '');
$xpath = new \DOMXPath($dom);
/** @var \DOMElement $tag */
foreach ($xpath->query('//drupal-media[@data-entity-type="media" and normalize-space(@data-entity-uuid)!=""]') as $tag) {
if ($uuid = $tag->getAttribute('data-entity-uuid')) {
/** @var MediaEntity $media */
if ($media = \Drupal::service('entity.repository')->loadEntityByUuid('media', $uuid)) {
foreach ($media->getFieldDefinitions() as $field) {
if ($field instanceof FieldConfig && $field->getFieldStorageDefinition()->getSetting('target_type') === 'file') {
if ($fid = $media->get($field->getName())) {
if ($file = File::load($fid[0]->target_id)) {
if (empty($file_usage_service)) {
$file_usage_service = \Drupal::service('file.usage');
}
$file_usage_service->add($file, 'mm_media', 'node', $node->id());
}
}
}
}
}
}
}
}
}
/**
* Implements hook_ENTITY_TYPE_update() for node entities.
*/
function mm_media_node_update(EntityInterface $node) {
mm_media_node_delete($node);
mm_media_node_insert($node);
}
/**
* Implements hook_ENTITY_TYPE_delete() for node entities.
*/
function mm_media_node_delete(EntityInterface $node) {
\Drupal::database()->delete('file_usage')
->condition('module', 'mm_media')
->condition('type', 'node')
->condition('id', $node->id())
->execute();
}
/**
* Implements hook_file_download().
*/
function mm_media_file_download($uri) {
// Get the file record based on the URI. If not in the database just return.
$files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri]);
if ($files) {
return mm_media_is_readable($uri, \Drupal::currentUser(), $files, TRUE);
}
return NULL;
}
function mm_media_is_readable($uri, AccountInterface $account, $files, $want_headers = FALSE) {
/** @var File $files[] */
$current_is_anon = $account->isAnonymous();
if (!$current_is_anon) {
$anon_user = User::getAnonymousUser();
}
$current_user_can = NULL;
$is_public = FALSE;
$allowed_func = $want_headers ?
'mm_media_get_content_headers' :
fn() => TRUE;
$cache_public_media = \Drupal::config('mm_media.settings')->get('cache_public_media');
foreach ($files as $file) {
// Since some database servers sometimes use a case-insensitive comparison
// by default, double check that the filename is an exact match.
if ($file->getFileUri() === $uri) {
// This section is taken directly from image_file_download(). We can't
// include the direct call to file_file_download(), though.
$path = StreamWrapperManager::getTarget($uri);
// Private file access for image style derivatives.
if (str_starts_with($path, 'styles/')) {
$args = explode('/', $path);
// Discard the first part of the path (styles), the style name, and
// the scheme from the path.
$args = array_slice($args, 3);
// Then the remaining parts are the path to the image.
$original_uri = StreamWrapperManager::getScheme($uri) . '://' . implode('/', $args);
// Check that the file exists and is an image.
if (\Drupal::service('image.factory')->get($uri)) {
// Check the permissions of the original to grant access to this image.
$headers = \Drupal::moduleHandler()->invokeAll('file_download', [$original_uri]);
// Confirm there's at least one module granting access and none denying access.
if (!empty($headers) && !in_array(-1, $headers)) {
return $want_headers ? [
// Send headers describing the image's size, and MIME-type...
'Content-Type' => $file->getMimeType(),
'Content-Length' => $file->getFileSize(),
// By not explicitly setting them here, this uses normal Drupal
// Expires, Cache-Control and ETag headers to prevent proxy or
// browser caching of private images.
] : TRUE;
}
}
return -1;
}
if ($file->getOwnerId() == $account->id()) {
$current_user_can = TRUE;
if ($current_is_anon) {
$is_public = TRUE;
}
}
else if ($file->isTemporary()) {
// Denied.
return -1;
}
if (is_null($current_user_can) || $cache_public_media) {
// If the current user can read any of the nodes containing the file,
// let it through. Otherwise, return denied. We also calculate whether
// or not the anonymous user can view the file, so that the correct
// cache headers can be sent.
$usage = \Drupal::service('file.usage')->listUsage($file);
// Filter the usage list by module name.
$usage = array_intersect_key($usage, ['editor' => 1, 'file' => 1, 'image' => 1, 'media' => 1, 'mm_media' => 1]);
foreach ($usage as $use) {
if (!empty($use['node']) || !empty($use['media'])) {
if (!empty($use['media'])) {
$use['node'] ??= [];
$use['node'] += _mm_media_nodes_containing_media(array_keys($use['media']));
}
if (is_null($current_user_can)) {
$current_user_can = FALSE;
}
foreach (array_keys($use['node']) as $nid) {
/** @var Node $node */
if ($node = Node::load($nid)) {
// Check readability for the current user.
if (!$current_user_can) {
$perms = mm_content_user_can_node($node, '', $account);
// Either the node is published and the user can read it, or
// the user can write to it.
if ($perms[Constants::MM_PERMS_WRITE] || $node->isPublished() && $perms[Constants::MM_PERMS_READ]) {
$current_user_can = TRUE;
if (!$cache_public_media) {
return $allowed_func($file, FALSE);
}
if ($current_is_anon) {
return $allowed_func($file, TRUE);
}
}
}
// Check readability for the anonymous user.
if ($cache_public_media && !$current_is_anon && mm_content_user_can_node($node, Constants::MM_PERMS_READ, $anon_user)) {
return $allowed_func($file, TRUE);
}
}
}
}
}
}
if ($current_user_can) {
return $allowed_func($file, $is_public);
}
if ($current_user_can === FALSE) {
// Denied.
return -1;
}
}
}
}
function mm_media_get_content_headers(File $file, $is_public) {
$headers = [
'Content-Type' => _mm_media_mime_header_decode($file->getMimeType()),
'Content-Disposition' => "filename*=UTF-8''" . rawurlencode($file->getFilename()),
'Content-Length' => $file->getSize(),
'Cache-Control' => 'private',
];
if ($is_public) {
// If the request has a "?__=something" cache-buster string and the file
// being served is an image, then max-age can be large. Non-images shouldn't
// be permanently cached because their permissions might change over time.
$max_age = \Drupal::config('system.performance')->get('cache.page.max_age');
if (\Drupal::config('mm_media.settings')->get('cache_images_permanently') && \Drupal::request()->query->has('__') && str_starts_with($file->getMimeType(), 'image/')) {
$max_age = 0;
}
$expires = new DateTime();
if ($max_age) {
$headers['Cache-Control'] = 'public, max-age=' . _mm_media_mime_header_decode($max_age);
$expires->modify("+$max_age second");
}
else {
$headers['Cache-Control'] = 'public';
$expires->modify('+10 year');
}
$headers['Expires'] = $expires->format('r');
// See if the client has provided the required HTTP headers.
$_server = \Drupal::request()->server->all();
$if_modified_since = isset($_server['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_server['HTTP_IF_MODIFIED_SINCE']) : FALSE;
$if_none_match = isset($_server['HTTP_IF_NONE_MATCH']) ? stripslashes($_server['HTTP_IF_NONE_MATCH']) : FALSE;
$moddate = @filemtime($file->getFileUri());
if ($if_modified_since && $if_none_match && $if_modified_since === $moddate) {
$headers = ['Cache-Control' => $headers['Cache-Control'], 'Expires' => $headers['Expires']];
throw new HttpException(304, $_server['SERVER_PROTOCOL'] . ' 304 Not Modified', NULL, $headers);
}
if ($moddate) {
$headers['Last-Modified'] = gmdate(DATE_RFC1123, $moddate);
}
}
return $headers;
}
function _mm_media_mime_header_decode($header) {
return (new UnstructuredHeader('subject', $header))->getBodyAsString();
}
function _mm_media_nodes_containing_media($mids) {
static $paragraph_media_fields;
static $node_paragraph_fields;
static $node_media_fields;
$entity_field_manager = \Drupal::service('entity_field.manager');
$output_list = [];
// A UNION is much faster than multiple ORed conditions.
$make_union = function ($entity_type, $fields, $ids) {
$queries = [];
foreach ($fields as $field_name) {
$queries[] = (string) \Drupal::entityQuery($entity_type)
->accessCheck(FALSE)
->condition($field_name, $ids, 'IN');
}
return implode(' UNION ', $queries);
};
if (is_null($paragraph_media_fields)) {
// Find paragraphs containing media reference fields.
/** @var BaseFieldDefinition $field_def */
foreach ($entity_field_manager->getActiveFieldStorageDefinitions('paragraph') as $field_name => $field_def) {
if ($field_def->getType() == 'entity_reference' && $field_def->getSetting('target_type') == 'media') {
$paragraph_media_fields[] = "$field_name.target_id";
}
}
}
if ($paragraph_media_fields) {
// Find paragraphs referring to the Media.
$outer_select = $make_union('paragraph', $paragraph_media_fields, $mids);
if ($paragraphs = \Drupal::database()->query($outer_select)->fetchCol(1)) {
if (is_null($node_paragraph_fields)) {
// Find nodes referring to paragraphs.
/** @var BaseFieldDefinition $field_def */
foreach ($entity_field_manager->getActiveFieldStorageDefinitions('node') as $field_name => $field_def) {
if ($field_def->getType() == 'entity_reference_revisions' && $field_def->getSetting('target_type') == 'paragraph') {
$node_paragraph_fields[] = "$field_name.target_id";
}
}
}
if ($node_paragraph_fields) {
// Find nodes referring to paragraphs which refer to the media items.
$outer_select = $make_union('node', $node_paragraph_fields, $paragraphs);
$query = \Drupal::database()->query($outer_select);
foreach ($query->fetchCol(1) as $nid) {
$output_list[$nid] = 1;
}
}
}
}
if (is_null($node_media_fields)) {
// Find all media fields in base nodes.
/** @var BaseFieldDefinition $field_def */
foreach ($entity_field_manager->getActiveFieldStorageDefinitions('node') as $field_name => $field_def) {
if ($field_def->getType() == 'entity_reference' && $field_def->getSetting('target_type') == 'media') {
$node_media_fields[] = "$field_name.target_id";
}
}
}
if ($node_media_fields) {
// Find any base node(s) that refer to the media items.
$outer_select = $make_union('node', $node_media_fields, $mids);
$query = \Drupal::database()->query($outer_select);
foreach ($query->fetchCol(1) as $nid) {
$output_list[$nid] = 1;
}
}
return $output_list;
}