You are here

function dynamic_entity_reference_views_data in Dynamic Entity Reference 8

Same name and namespace in other branches
  1. 8.2 dynamic_entity_reference.views.inc \dynamic_entity_reference_views_data()

Implements hook_views_data().

Adds relationships for dynamic_entity_reference base fields.

@todo remove this when https://www.drupal.org/node/2337515 is in.

File

./dynamic_entity_reference.views.inc, line 119
Provides views data for the dynamic_entity_reference module.

Code

function dynamic_entity_reference_views_data() {
  $entity_manager = \Drupal::entityTypeManager();

  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types = [];
  $sql_entity_types = [];
  $fields_all = [];

  // Ensure origin and target entity types are SQL.
  foreach ($entity_manager
    ->getDefinitions() as $entity_type) {

    // \Drupal\views\EntityViewsData class only allows entities with
    // \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
    if ($entity_type
      ->hasHandlerClass('views_data') && $entity_manager
      ->getStorage($entity_type
      ->id()) instanceof SqlEntityStorageInterface) {
      $sql_entity_types[$entity_type
        ->id()] = $entity_type
        ->id();

      // Only fieldable entities have base fields.
      if ($entity_type
        ->entityClassImplements(FieldableEntityInterface::class)) {
        $entity_types[$entity_type
          ->id()] = $entity_type;
        $entity_field_manager = \Drupal::service('entity_field.manager');
        foreach ($entity_field_manager
          ->getBaseFieldDefinitions($entity_type
          ->id()) as $base_field) {
          if ($base_field
            ->getType() == 'dynamic_entity_reference' && !$base_field
            ->isComputed()) {
            $fields_all[$entity_type
              ->id()][] = $base_field;
          }
        }
      }
    }
  }
  $data = [];
  foreach ($fields_all as $entity_type_id => $fields) {

    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
    $table_mapping = $entity_manager
      ->getStorage($entity_type_id)
      ->getTableMapping();
    $entity_type = $entity_types[$entity_type_id];
    $base_table = $entity_manager
      ->getHandler($entity_type_id, 'views_data')
      ->getViewsTableForEntityType($entity_type);

    /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
    foreach ($fields as $field) {
      $field_name = $field
        ->getName();
      $columns = $table_mapping
        ->getColumnNames($field_name);
      $column_id = $columns['target_id'];
      $column_type = $columns['target_type'];

      // Unlimited (-1) or > 1 store field data in a dedicated table.
      $table = $field
        ->getCardinality() == 1 ? $base_table : $entity_type
        ->getBaseTable() . '__' . $field_name;

      // Filter out non SQL entity types because \Drupal\views\EntityViewsData
      // class only allows entities with
      // \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
      $targets = array_intersect(DynamicEntityReferenceItem::getTargetTypes($field
        ->getSettings()), array_keys($sql_entity_types));
      foreach ($targets as $target_entity_type_id) {
        if ($entity_manager
          ->hasHandler($target_entity_type_id, 'views_data')) {
          $target_entity_type = $entity_types[$target_entity_type_id];
          $target_table = $entity_manager
            ->getHandler($target_entity_type_id, 'views_data')
            ->getViewsTableForEntityType($target_entity_type);
          $t_args = [
            '@origin_label' => $entity_type
              ->getLabel(),
            '@target_label' => $target_entity_type
              ->getLabel(),
            '@field_name' => $field
              ->getLabel() ?: $field_name,
            '@type' => 'base field',
          ];

          // Relationship (Origin -> Target).
          $psuedo_field = $target_entity_type_id . '__' . $field_name;
          $data[$table][$psuedo_field]['relationship'] = [
            'title' => t('@field_name to @target_label entities', $t_args),
            'label' => t('@field_name: @target_label', $t_args),
            'group' => $entity_type
              ->getLabel(),
            'help' => t('References to @target_label entities referenced by @field_name @type on @origin_label entities.', $t_args),
            'id' => 'standard',
            'base' => $target_table,
            'entity type' => $target_entity_type_id,
            'base field' => $target_entity_type
              ->getKey('id'),
            'relationship field' => $column_id,
            'extra' => [
              [
                // Entity reference field only has one target type whereas
                // dynamic entity reference field can have multiple target types
                // that is why extra join condition on target types is needed.
                'left_field' => $column_type,
                'value' => $target_entity_type_id,
              ],
            ],
          ];

          // Reverse Relationship (Target -> Origin).
          $psuedo_field = 'reverse__' . $entity_type_id . '__' . $field_name;
          $data[$target_table][$psuedo_field]['relationship'] = [
            'title' => t('Reverse reference to @field_name @type on @origin_label', $t_args),
            'label' => t('Reverse reference to @field_name @type on @origin_label', $t_args),
            'group' => $target_entity_type
              ->getLabel(),
            'help' => t('Reverse reference from @target_label entities referenced by @field_name @type on @origin_label entities.', $t_args),
          ];

          // When base field cardinality is 1 then the 'base' and 'field table'
          // are same because field column(s) exist in entity base table
          // therefore we can't use entity_reverse relationship plugin.
          if ($field
            ->getCardinality() == 1) {
            $data[$target_table][$psuedo_field]['relationship'] += [
              'id' => 'standard',
              'base' => $table,
              'entity type' => $entity_type_id,
              'base field' => $column_id,
              'field' => $target_entity_type
                ->getKey('id'),
              'extra' => [
                [
                  // Entity reference field only has one target type whereas
                  // dynamic entity reference field can have multiple target
                  // types that is why an extra join condition on target types
                  // is needed.
                  'field' => $column_type,
                  'value' => $target_entity_type_id,
                ],
              ],
            ];
          }
          else {
            $data[$target_table][$psuedo_field]['relationship'] += [
              'id' => 'entity_reverse',
              'base' => $base_table,
              'entity_type' => $entity_type_id,
              'base field' => $entity_type
                ->getKey('id'),
              'field_name' => $field_name,
              'field table' => $table,
              'field field' => $column_id,
              // Entity reference field only has one target type whereas dynamic
              // entity reference field can have multiple target types that is
              // why an extra join condition on target types is needed.
              'join_extra' => [
                [
                  'field' => $column_type,
                  'value' => $target_entity_type_id,
                ],
              ],
            ];
          }
        }
      }
    }
  }
  return $data;
}