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;
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc