og-8.x-1.x-dev/src/Plugin/views/relationship/GroupContentByGroupRelationship.php

src/Plugin/views/relationship/GroupContentByGroupRelationship.php
<?php

declare(strict_types=1);

namespace Drupal\og\Plugin\views\relationship;

use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\og\GroupTypeManagerInterface;
use Drupal\og\OgGroupAudienceHelperInterface;
use Drupal\views\Attribute\ViewsRelationship;
use Drupal\views\Plugin\views\relationship\RelationshipPluginBase;
use Drupal\views\Plugin\ViewsHandlerManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Relates group content to its OG group(s) via any audience fields.
 *
 * This creates a LEFT JOIN to a derived UNION subquery with columns:
 * (entity_id, group_id). Starting from group content, it exposes group fields
 * by further joining to the group base table.
 */
#[ViewsRelationship(
  id: 'og_group_content_to_group',
)]
class GroupContentByGroupRelationship extends RelationshipPluginBase implements ContainerFactoryPluginInterface {

  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    protected readonly EntityTypeManagerInterface $entityTypeManager,
    protected readonly OgGroupAudienceHelperInterface $groupAudienceHelper,
    protected readonly GroupTypeManagerInterface $groupTypeManager,
    protected readonly ViewsHandlerManager $joinManager,
    protected readonly Connection $database,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
      $container->get('og.group_audience_helper'),
      $container->get('og.group_type_manager'),
      $container->get('plugin.manager.views.join'),
      $container->get('database'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function query() {
    // Prefer explicit hints from views data if present.
    $group_content_entity_type = $this->definition['entity_type'] ?? NULL;
    $group_entity_type = $this->definition['group_entity_type'] ?? NULL;

    // Infer implicitly when hints are not provided.
    if (!$group_content_entity_type) {
      // The relationship is attached on the group content base/data table.
      $group_content_entity_type = $this->resolveEntityTypeFromTable($this->table) ?? NULL;
    }
    if (!$group_entity_type && isset($this->definition['base'])) {
      // The 'base' in the relationship definition points to the group table.
      $group_entity_type = $this->resolveEntityTypeFromTable((string) $this->definition['base']) ?? NULL;
    }

    $derived = $this->buildEntityToGroupUnion($group_content_entity_type, $group_entity_type);
    if (!$derived) {
      // If there is no mapping, do nothing — relationship can't apply.
      return;
    }

    // Ensure our base table is available and get its alias.
    $this->ensureMyTable();

    // Determine base entity (group content) identifiers.
    $base_entity_type = $this->view->storage->get('base_entity_type') ?: $group_content_entity_type;
    $base_definition = $this->entityTypeManager->getDefinition($base_entity_type);
    $base_id_key = $base_definition->getKey('id');

    // Determine group entity base table and id field.
    $group_definition = $this->entityTypeManager->getDefinition($group_entity_type);
    $group_id_key = $group_definition->getKey('id');
    $group_base_table = $group_definition->getDataTable() ?? $group_definition->getBaseTable();

    // Join mapping (entity_id, group_id) as a table formula to the base.
    $join_map = $this->joinManager->createInstance('standard', [
      'table' => 'og_group_content_to_group_map',
      'field' => 'entity_id',
      'left_table' => $this->tableAlias,
      'left_field' => $base_id_key,
      'type' => !empty($this->options['required']) ? 'INNER' : 'LEFT',
      'adjusted' => TRUE,
      'table formula' => $derived,
    ]);
    $map_alias = $this->query->addRelationship('og_group_content_to_group_map', $join_map, 'og_group_content_to_group_map', $this->relationship);

    // Join the group base table to the mapping on group_id and expose
    // the group table alias as the relationship alias.
    $join_group = $this->joinManager->createInstance('standard', [
      'table' => $group_base_table,
      'field' => $group_id_key,
      'left_table' => $map_alias,
      'left_field' => 'group_id',
      'type' => !empty($this->options['required']) ? 'INNER' : 'LEFT',
      'adjusted' => TRUE,
    ]);

    $this->alias = $this->query->addRelationship('og_group_from_group_content', $join_group, $group_base_table, $map_alias);
  }

  /**
   * Resolve an entity type ID from a given base or data table name.
   *
   * @internal
   */
  private function resolveEntityTypeFromTable(string $table): ?string {
    foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $definition) {
      $base = $definition->getBaseTable();
      $data = $definition->getDataTable();
      if ($table === $base || ($data && $table === $data)) {
        return (string) $entity_type_id;
      }
    }
    return NULL;
  }

  /**
   * Builds a UNION SELECT mapping group content entities to their groups.
   *
   * Iterates over all group audience fields for the given group content entity
   * type and group entity type, creating a UNION query selecting
   * (entity_id, group_id) pairs. This allows relating group content to its OG
   * groups across any audience field.
   */
  protected function buildEntityToGroupUnion(string $group_content_entity_type, string $group_entity_type): ?SelectInterface {
    try {
      $group_content_bundles = $this->groupTypeManager
        ->getAllGroupContentBundlesByEntityType($group_content_entity_type);
    }
    catch (\InvalidArgumentException $e) {
      return NULL;
    }
    if (empty($group_content_bundles)) {
      return NULL;
    }

    $union = NULL;
    $seen_field_names = [];

    foreach ($group_content_bundles as $bundle_id) {
      // Ask OG which audience fields exist for this bundle and group type.
      $field_definitions = $this->groupAudienceHelper->getAllGroupAudienceFields(
        $group_content_entity_type,
        $bundle_id,
        $group_entity_type
      );

      foreach ($field_definitions as $field_definition) {
        $field_name = $field_definition
          ->getFieldStorageDefinition()
          ->getName();

        // Avoid adding duplicate subqueries if multiple bundles share a field.
        if (isset($seen_field_names[$field_name])) {
          continue;
        }
        $seen_field_names[$field_name] = TRUE;

        $select = $this->database
          ->select($group_content_entity_type . '__' . $field_name, 't')
          ->distinct()
          ->fields('t', ['entity_id']);
        $select->addExpression("t.{$field_name}_target_id", 'group_id');
        $select->condition('t.deleted', 0);

        if ($union instanceof SelectInterface) {
          $union->union($select);
        }
        else {
          $union = $select;
        }
      }
    }

    return $union ?? NULL;
  }

}

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

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