monster_menus-9.0.x-dev/modules/mm_media/src/Plugin/MMTreeBrowserDisplay/Media.php

modules/mm_media/src/Plugin/MMTreeBrowserDisplay/Media.php
<?php

namespace Drupal\mm_media\Plugin\MMTreeBrowserDisplay;

use Drupal\Core\Database\Query\PagerSelectExtender;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Database\Database;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\mm_media\Plugin\EntityBrowser\Widget\MMTree;
use Drupal\monster_menus\Constants;
use Drupal\monster_menus\MMTreeBrowserDisplay\MMTreeBrowserDisplayInterface;
use Drupal\monster_menus\Plugin\MMTreeBrowserDisplay\Fallback;
use Drupal\paragraphs\Entity\Paragraph;

/**
 * Provides the MM Tree display generator for pages containing Media entities.
 *
 * @MMTreeBrowserDisplay(
 *   id = "mm_tree_browser_display_media",
 *   admin_label = @Translation("MM Tree media display"),
 * )
 */
class Media extends Fallback implements MMTreeBrowserDisplayInterface {

  final public const BROWSER_MODE_MEDIA = 'med';

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * Entity field manager service.
   *
   * @var \Drupal\Core\Entity\EntityFieldManager
   */
  protected $entityFieldManager;

  /**
   * Entity field manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected $entityTypeManager;

  /**
   * The cache.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The HTTP query.
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $httpQuery;

  /**
   * If set, allow the implicit creation of Media entities from File entities.
   *
   * @var bool
   */
  protected $allow_file2media = FALSE;

  /**
   * Constructor.
   */
  public function __construct() {
    $this->entityFieldManager = \Drupal::service('entity_field.manager');
    $this->entityTypeManager = \Drupal::service('entity_type.manager');
    $this->cache = \Drupal::service('cache.default');
    $this->httpQuery = \Drupal::request()->query;
    $this->database = Database::getConnection();
  }

  public static function supportedModes() {
    return [self::BROWSER_MODE_MEDIA];
  }

  public function label($mode) {
    return t('Select a file upload');
  }

  /**
   * {@inheritdoc}
   */
  public function alterLeftQuery($mode, $query, &$params) {
    $segments = [];
    foreach ($this->getFields() as $alias => $fields_list) {
      foreach ($fields_list as $fields) {
        $join = [];
        $last_alias = '';
        foreach ($fields as $field) {
          $join[] = '{' . $field[0] . '} ' . $field[1] . ' ON ' . $field[2];
          $last_alias = $field[1];
        }
        $joined = join(' INNER JOIN ', $join);
        if (str_starts_with($alias, 'file_managed')) {
          // Negate fids in order to count them separately from mids.
          $concat_alias = "-$last_alias.fid";
        }
        else {
          $concat_alias = "$alias.mid";
        }
        $segments[] = "SELECT GROUP_CONCAT($concat_alias) FROM {node_field_data} n INNER JOIN $joined INNER JOIN {mm_node2tree} n2 ON n2.nid = n.nid  WHERE n.status = 1 AND n2.mmtid = o.container";
      }
    }

    // Ideally, we would use a UNION to get all the distinct mids, but can't
    // because then MySQL doesn't let us use o.container from the outer query.
    // Instead, get a concatenated list of all the mids in nodecount and
    // squash the duplicates in PHP to get the count.

    // Start by making sure we can get all the results.
    $this->database->query('SET @@group_concat_max_len = 1000000')->execute();
    $params[Constants::MM_GET_TREE_ADD_SELECT] = "CONCAT_WS(',', (" . join('), (', $segments) . ')) AS fid_list';
    $params[Constants::MM_GET_TREE_FILTER_NORMAL] = $params[Constants::MM_GET_TREE_FILTER_USERS] = TRUE;
  }

  /**
   * @return array
   */
  private function getFields() {
    $file_types = $this->getFileTypes();
    $cid = 'mm_media.get_fields:' . implode(':', $file_types) . ':' . $this->allow_file2media;
    if ($cache = $this->cache->get($cid)) {
      return $cache->data;
    }
    $output = [];
    $paragraph_data = [];
    $cache_tags = ['mm_media_get_fields'];

    foreach ($this->entityFieldManager->getFieldStorageDefinitions('paragraph') as $field_name => $field_def) {
      $type = '.entity.bundle';
      if ($field_def->getType() == 'entity_reference' && $field_def->getSetting('target_type') == 'media' ||
        $this->allow_file2media && in_array($field_def->getType(), $file_types) && !$field_def->hasCustomStorage() && ($type = '.entity')) {
        foreach ($this->entityFieldManager->getFieldMap()['paragraph'][$field_name]['bundles'] ?? [] as $paragraph) {
          $ids = $this->entityTypeManager->getStorage('paragraph')->getQuery()
            ->accessCheck(FALSE)
            ->condition('type', $paragraph)
            ->execute();
          if ($loaded = Paragraph::load(reset($ids))) {
            if ($loaded->get('parent_type')->value == 'node') {
              $key = $loaded->get('parent_field_name')->value;
              $cache_tags = Cache::mergeTags($field_def->getCacheTags(), $cache_tags);
              $paragraph_data[$key][] = $field_name . $type;
            }
          }
        }
      }
    }

    foreach ($this->entityFieldManager->getFieldStorageDefinitions('node') as $field_name => $field_def) {
      // Perform a dummy entity query, in order to have it map the table
      // relationships.
      if ($field_def->getType() == 'entity_reference' && $field_def->getSetting('target_type') == 'media') {
        $this->getTablesForField("$field_name.entity.bundle", $field_def, $cache_tags, $output);
      }
      elseif ($this->allow_file2media && in_array($field_def->getType(), $file_types) && !$field_def->hasCustomStorage()) {
        $this->getTablesForField("$field_name.entity", $field_def, $cache_tags, $output);
      }
      elseif (isset($paragraph_data[$field_name])) {
        foreach ($paragraph_data[$field_name] as $paragraph_field) {
          $this->getTablesForField("$field_name.entity:paragraph." . $paragraph_field, $field_def, $cache_tags, $output);
        }
      }
    }

    $this->cache->set($cid, $output, Cache::PERMANENT, $cache_tags);
    return $output;
  }

  private function getTablesForField($field, FieldStorageDefinitionInterface $field_def, &$cache_tags, &$output) {
    $query = \Drupal::entityQuery('node')
      ->accessCheck(FALSE);
    $query->condition($field, 1);
    $cache_tags = Cache::mergeTags($field_def->getCacheTags(), $cache_tags);
    // Sadly, entityQuery doesn't have public methods for most things, so hack
    // it.
    // Start with $query->prepare().
    $prepare = new \ReflectionMethod($query::class, 'prepare');
    $prepare->setAccessible(TRUE);
    $prepare->invoke($query);
    // $query->compile().
    $compile = new \ReflectionMethod($query::class, 'compile');
    $compile->setAccessible(TRUE);
    $compile->invoke($query);
    // Get $query->sqlQuery.
    $rp = new \ReflectionProperty($query::class, 'sqlQuery');
    $rp->setAccessible(TRUE);
    $sqlQuery = $rp->getValue($query);

    $join = [];
    $last_alias = '';
    foreach ($sqlQuery->getTables() as $table_name => $table_def) {
      if ($table_name != 'base_table' && $table_name != 'media_field_data') {
        if ($join && preg_match('{ \[?base_table\]?\.}', $table_def['condition'])) {
          $output[$last_alias][] = $join;
          $join = [];
        }
        $last_alias = $table_def['alias'];
        $join[] = [
          $table_def['table'],
          $table_def['alias'],
          preg_replace('{ \[?base_table\]?\.}', ' n.', $table_def['condition']),
        ];
      }
    }
    $output[$last_alias][] = $join;
  }

  /**
   * Sanitize and expand the browserFileTypes query parameter.
   *
   * @return array
   */
  private function getFileTypes() {
    if ($types = $this->httpQuery->get('browserFileTypes')) {
      $types = array_map(fn($mime) => preg_replace('/[^A-Za-z0-9_.]+/', '', $mime), explode(',', $types));
      if (($i = array_search(MMTree::FILE2MEDIA_TYPE, $types)) !== FALSE) {
        unset($types[$i]);
        $this->allow_file2media = TRUE;
        $types[] = 'file';
      }
      return $types;
    }
    return [];
  }

  public function showReservedEntries($mode) {
    return FALSE;
  }

  public function alterRightButtons($mode, $query, $item, $permissions, &$actions, &$dialogs) {
    $this->addSearchAction($query, $actions, t('Filter by filename/ALT text'));
    parent::alterRightButtons($mode, $query, $item, $permissions, $actions, $dialogs);
  }

  /**
   * Get a list of file upload thumbnails for the right hand column.
   *
   * {@inheritdoc}
   */
  public function viewRight($mode, $query, $perms, $item, $database) {
    $mmtid = $item->mmtid;
    if (!$perms[Constants::MM_PERMS_APPLY]) {
      $out = '';
      if ($mmtid > 0) {
        $out = '<div id="mmtree-browse-thumbnails"><br />' . t('You do not have permission to use the file uploads on this page.') . '</div>';
      }
      $json = [
        'title' => mm_content_get_name($mmtid),
        'body' => $out,
      ];
      return mm_json_response($json);
    }

    foreach ($this->getFields() as $fields_list) {
      foreach ($fields_list as $fields) {
        $segment = $this->database->select('node_field_data', 'n');
        foreach ($fields as $i => $field) {
          if (!$i) {
            $segment->addTag(__FUNCTION__ . '__' . $field[0] . '.' . $field[1]);
          }
          $segment->join($field[0], $field[1], $field[2]);
          if ($field[0] == 'media') {
            $segment->addExpression($field[1] . '.mid', 'mid');
            $segment->addExpression(-1, 'fid');
          }
          elseif ($field[0] == 'file_managed') {
            $segment->addExpression(-1, 'mid');
            $segment->addExpression($field[1] . '.fid', 'fid');
          }
        }
        $segment->addExpression('n.changed', 'changed');
        $segment->join('mm_node2tree', 'n2', 'n2.nid = n.nid');
        $segment->where('n.status = 1')
          ->where('n2.mmtid = ' . intval($mmtid));

        if (empty($qquery)) {
          $qquery = $segment;
        }
        else {
          $qquery->union($segment);
        }
      }
    }

    $content = [];
    if (!empty($qquery)) {
      $qquery = $this->database->select($qquery, 'subquery');
      $qquery->addTag(__FUNCTION__);
      if ($mode == self::BROWSER_MODE_MEDIA) {
        $qquery->addField('subquery', 'mid');
      }

      $qquery->leftJoin('file_managed', 'fm', 'fm.fid = subquery.fid');
      $qquery->fields('fm');

      if ($search_terms = $this->getSearchTerms($query)) {
        $qquery->leftJoin('media_field_data', 'fd', 'fd.mid = subquery.mid');
        foreach ($search_terms as $term) {
          // $term is already sanitized in ::getSearchTerms().
          $qquery->where("(fd.name REGEXP '" . $term . "' OR fd.thumbnail__alt REGEXP '" . $term . "' OR fm.filename REGEXP '" . $term . "')");
        }
      }

      $result = $qquery->extend(PagerSelectExtender::class)
        ->orderBy('subquery.changed', 'DESC')
        ->limit(mm_get_setting('nodes.nodelist_pager_limit'))
        ->execute();

      $min_wh[0] = $this->httpQuery->getInt('browserMinW', 0);
      $min_wh[1] = $this->httpQuery->getInt('browserMinH', 0);

      foreach ($result as $file) {
        $content['icons'][] = [
          '#theme' => 'mm_browser_thumbnail',
          '#file' => $file,
          '#style_name' => 'thumbnail',
          '#mode' => $mode,
          '#mmtid' => $mmtid,
          '#min_wh' => $min_wh,
        ];
      }
    }

    if (!$content) {
      $msg = !empty($search_terms) ? t('There is no selectable content on this page which matches the filter.') : t('There is no selectable content on this page.');
      $content = [['#prefix' => '<p>', '#markup' => $msg, '#suffix' => '</p>']];
      $this->removeSearchAction();
    }
    else {
      $content['pager'] = [
        '#type' => 'pager',
        '#route_name' => 'monster_menus.browser_getright',
      ];
    }

    return ['#prefix' => '<div id="mmtree-browse-thumbnails">', $content, '#suffix' => '</div>'];
  }

}

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

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