external_entities-8.x-2.x-dev/modules/xntt_views/xntt_views.views.inc

modules/xntt_views/xntt_views.views.inc
<?php

/**
 * @file
 * Views hook implementations for External Entities.
 *
 * Most of this code is inspired or borrowed from Search API module.
 */

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldInterface;
use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
use Drupal\Core\Utility\Error;

/**
 * Implements hook_views_data().
 */
function xntt_views_views_data() {
  $data = [];

  $xntt_type_storage = \Drupal::entityTypeManager()->getStorage('external_entity_type');
  $field_manager = \Drupal::service('entity_field.manager');
  $entity_types = $xntt_type_storage->getQuery()->accessCheck(TRUE)->execute();
  foreach ($entity_types as $entity_type_mname) {
    $entity_type = $xntt_type_storage->load($entity_type_mname);
    $view_id = 'xntt_views_' . $entity_type_mname;

    // Base data.
    $group_name = $entity_type->getLabel();
    $entity_type_name = $entity_type->getLabel();
    $data[$view_id] = [
      'table' => [
        'group' => $group_name,
        'provider' => 'xntt_views',
        'base' => [
          'title' => $entity_type_name,
          'help' => t(
            '@xntttype external entities views mapping.',
            ['@xnttype' => $entity_type_name]
          ),
          'query_id' => 'xntt_views',
          'xntt' => $entity_type_mname,
        ],
        'entity revision' => FALSE,
        'entity type' => $entity_type_mname,
      ],
      'rendered_entity' => [
        'field' => [
          'title' => t('Rendered entity'),
          'help' => t('Renders an entity in a view mode.'),
          'id' => 'rendered_entity',
        ],
      ],
    ];

    // Fields.
    $fields = $field_manager->getFieldDefinitions($entity_type_mname, $entity_type_mname);

    foreach ($fields as $field_id => $field_definition) {
      // @todo Needs refactoring to generate things from distinct functions.
      $field_view_def = _xntt_views_get_view_field($field_definition);
      $field_filter = _xntt_views_get_view_field($field_definition);
      $data[$view_id][$field_id] = [
        'title' => $field_definition->getLabel(),
        'help' => $field_definition->getDescription(),
        'field' => ['id' => 'xnttfield'],
        'argument' => $field_view_def,
        'filter' => $field_filter,
        'sort' => ['id' => 'standard'],
        'entity field' => $field_id,
      ];
    }
  }

  return $data;
}

/**
 * Returns the Views handlers to use for a given field.
 *
 * @param \Drupal\Core\Field\FieldInterface $field
 *   The field to add to the definition.
 *
 * @return array
 *   The Views definition to add for the given field.
 */
function _xntt_views_get_view_field(FieldDefinitionInterface $field) {
  // @todo Set field type according to field.
  // @see /core/modules/views/src/Plugin/views/field
  // And use code below as basis (_xntt_views_views_handler_mapping()).
  $type = $field->getType();
  $view_field = [];
  switch ($type) {
    case 'boolean':
      $view_field = ['id' => 'boolean'];
      break;

    case 'changed':
      $view_field = ['id' => 'date'];
      break;

    case 'created':
      $view_field = ['id' => 'date'];
      break;

    case 'decimal':
      $view_field = ['id' => 'numeric'];
      break;

    case 'email':
      $view_field = ['id' => 'string'];
      break;

    case 'entity_reference':
      $view_field = [
        'id' => 'entity_label',
      ];
      if ($field instanceof BaseFieldDefinition) {
        $view_field['entity type field'] = $field->getName();
      }
      else {
        $view_field['entity type field'] = $field->get('field_name');
      }
      break;

    case 'float':
      $view_field = ['id' => 'numeric'];
      break;

    case 'integer':
      $view_field = ['id' => 'numeric'];
      break;

    case 'language':
      $view_field = ['id' => 'language'];
      break;

    case 'map':
      $view_field = ['id' => 'string'];
      break;

    case 'password':
      $view_field = ['id' => 'string'];
      break;

    case 'string':
      $view_field = ['id' => 'string'];
      break;

    case 'string_long':
      $view_field = ['id' => 'string'];
      break;

    case 'timestamp':
      $view_field = ['id' => 'date'];
      break;

    case 'uri':
      $view_field = ['id' => 'url'];
      break;

    case 'uuid':
      $view_field = ['id' => 'string'];
      break;

    default:
      $view_field = ['id' => 'string'];
      break;
  }

  return $view_field;
}

/**
 * Finds an unused field alias for a field in a Views table definition.
 *
 * @param string $field_id
 *   The original ID of the field.
 * @param array $table
 *   The Views table definition.
 *
 * @return string
 *   The field alias to use.
 */
function _xntt_views_views_find_field_alias($field_id, array &$table) {
  $base = $field_alias = preg_replace('/[^a-zA-Z0-9]+/S', '_', $field_id);
  $i = 0;
  while (isset($table[$field_alias])) {
    $field_alias = $base . '_' . ++$i;
  }
  return $field_alias;
}

/**
 * Returns the Views handlers to use for a given field.
 *
 * @param \Drupal\Core\Field\FieldInterface $field
 *   The field to add to the definition.
 *
 * @return array
 *   The Views definition to add for the given field.
 */
function _xntt_views_views_get_handlers(FieldDefinitionInterface $field) {
  $mapping = _xntt_views_views_handler_mapping();

  try {
    $types = [];

    $definition = $field->getDataDefinition();
    $entity_type_id = $definition->getSetting('target_type');
    if ($entity_type_id) {
      $entity_type = \Drupal::entityTypeManager()
        ->getDefinition($entity_type_id);
      $bundle_of = $entity_type->getBundleOf();
      if ($bundle_of) {
        $types[] = "bundle_of:$bundle_of";
        $types[] = ['bundle_of', $bundle_of];
      }

      $types[] = "entity:$entity_type_id";
      $types[] = ['entity', $entity_type_id];
    }

    // Special treatment for languages (as we have no specific data type for
    // those).
    if ($definition->getSetting('views_type') === 'language') {
      $types[] = 'language';
    }

    if ($definition->getSetting('allowed_values')) {
      $types[] = 'options';
    }

    $types[] = $field->getDataType();
    $data_type = \Drupal::service('plugin.manager.xntt_views.data_type')->createInstance($field->getDataType());
    if (!$data_type->isDefault()) {
      $types[] = $data_type->getFallbackType();
    }

    foreach ($types as $type) {
      $sub_type = NULL;
      if (is_array($type)) {
        [$type, $sub_type] = $type;
      }
      if (isset($mapping[$type])) {
        _xntt_views_views_handler_adjustments($type, $field, $mapping[$type], $sub_type);
        return $mapping[$type];
      }
    }
  }
  // @todo Replace with multi-catch once we depend on PHP 7.1+.
  catch (PluginNotFoundException $e) {
    $vars['%index'] = $field->getIndex()->label();
    $vars['%field'] = $field->getPrefixedLabel();
    Error::logException(\Drupal::logger('xntt_views'), $e, '%type while adding Views handlers for field %field on index %index: @message in %function (line %line of %file).', $vars);
  }

  return [];
}

/**
 * Determines the mapping of data types to their Views handlers.
 *
 * @return array
 *   An associative array with data types as the keys and Views field data
 *   definitions as the values. In addition to all normally defined data types,
 *   keys can also be "options" for any field with an options list, "entity" for
 *   general entity-typed fields or "entity:ENTITY_TYPE" (with "ENTITY_TYPE"
 *   being the machine name of an entity type) for entities of that type.
 *
 * @see xntt_views_views_handler_mapping_alter()
 */
function _xntt_views_views_handler_mapping() {
  $mapping = &drupal_static(__FUNCTION__);

  if ($mapping === NULL) {
    $mapping = [
      'boolean' => [
        'argument' => [
          'id' => 'xntt_views',
        ],
        'filter' => [
          'id' => 'xntt_views_boolean',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'date' => [
        'argument' => [
          'id' => 'xntt_views_date',
        ],
        'filter' => [
          'id' => 'xntt_views_date',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'decimal' => [
        'argument' => [
          'id' => 'xntt_views',
          'filter' => 'floatval',
        ],
        'filter' => [
          'id' => 'xntt_views_numeric',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'integer' => [
        'argument' => [
          'id' => 'xntt_views',
          'filter' => 'intval',
        ],
        'filter' => [
          'id' => 'xntt_views_numeric',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'string' => [
        'argument' => [
          'id' => 'xntt_views',
        ],
        'filter' => [
          'id' => 'xntt_views_string',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'text' => [
        'argument' => [
          'id' => 'xntt_views',
        ],
        'filter' => [
          'id' => 'xntt_views_text',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'language' => [
        'argument' => [
          'id' => 'xntt_views',
        ],
        'filter' => [
          'id' => 'xntt_views_language',
          'allow empty' => FALSE,
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'options' => [
        'argument' => [
          'id' => 'xntt_views',
        ],
        'filter' => [
          'id' => 'xntt_views_options',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'entity:taxonomy_term' => [
        'argument' => [
          'id' => 'xntt_views_term',
        ],
        'filter' => [
          'id' => 'xntt_views_term',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'entity:user' => [
        'argument' => [
          'id' => 'xntt_views',
          'filter' => 'intval',
        ],
        'filter' => [
          'id' => 'xntt_views_user',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
      'bundle_of' => [
        'argument' => [
          'id' => 'xntt_views',
        ],
        'filter' => [
          'id' => 'xntt_views_options',
        ],
        'sort' => [
          'id' => 'xntt_views',
        ],
      ],
    ];
  }

  return $mapping;
}

/**
 * Creates a Views table definition for an entity type.
 *
 * @param string $entity_type_id
 *   The ID of the entity type.
 * @param array $data
 *   The existing Views data definitions, passed by reference.
 *
 * @return array
 *   A Views table definition for the given entity type. Or an empty array if
 *   the entity type could not be found.
 */
function _xntt_views_views_entity_type_table($entity_type_id, array &$data) {
  $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
  if (!$entity_type || !$entity_type->entityClassImplements(FieldableEntityInterface::class)) {
    return [];
  }
  $table = [];

  return $table;
}

/**
 * Makes necessary field-specific adjustments to Views handler definitions.
 *
 * @param string $type
 *   The type of field, as defined in _xntt_views_views_handler_mapping().
 * @param \Drupal\Core\Field\FieldInterface $field
 *   The field whose handler definitions are being created.
 * @param array $definitions
 *   The handler definitions for the field, as a reference.
 * @param string|null $sub_type
 *   (optional) If applicable, the field's sub-type.
 */
function _xntt_views_views_handler_adjustments($type, FieldInterface $field, array &$definitions, ?string $sub_type = NULL) {
  // By default, all fields can be empty (or at least have to be treated that
  // way).
  if (!isset($definitions['filter']['allow empty'])) {
    $definitions['filter']['allow empty'] = TRUE;
  }
  // For taxonomy term references, set the referenced vocabulary.
  $data_definition = $field->getDataDefinition();
  if ($type == 'entity:taxonomy_term') {
    if (isset($data_definition->getSettings()['handler_settings']['target_bundles'])) {
      $target_bundles = $data_definition->getSettings()['handler_settings']['target_bundles'];
      if (count($target_bundles) == 1) {
        $definitions['filter']['vocabulary'] = reset($target_bundles);
      }
    }
  }
  elseif ($type == 'options') {
    if ($data_definition instanceof FieldItemDataDefinition) {
      // If this is a normal Field API field, dynamically retrieve the options
      // list at query time.
      $field_definition = $data_definition->getFieldDefinition();
      $bundle = $field_definition->getTargetBundle();
      $field_name = $field_definition->getName();
      $entity_type = $field_definition->getTargetEntityTypeId();
      $definitions['filter']['options callback'] = '_xntt_views_views_get_allowed_values';
      $definitions['filter']['options arguments'] = [$entity_type, $bundle, $field_name];
    }
    else {
      // Otherwise, include the options list verbatim in the Views data, unless
      // it's too big (or doesn't look valid).
      $options = $data_definition->getSetting('allowed_values');
      if (is_array($options) && count($options) <= 50) {
        // Since the Views InOperator filter plugin doesn't allow just including
        // the options in the definition, we use this workaround.
        $definitions['filter']['options callback'] = 'array_filter';
        $definitions['filter']['options arguments'] = [$options];
      }
    }
  }
  elseif ($type === 'bundle_of' && $sub_type) {
    $definitions['filter']['options callback'] = '_xntt_views_views_get_bundle_names';
    $definitions['filter']['options arguments'] = [$sub_type];
  }
}

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

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