View source
<?php
namespace Drupal\commerce;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Sql\TableMappingInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\entity\BundleFieldDefinition;
use Drupal\views\EntityViewsData;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CommerceEntityViewsData extends EntityViewsData {
protected $entityTypeBundleInfo;
protected $tableMapping;
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
$instance = parent::createInstance($container, $entity_type);
$instance->entityTypeBundleInfo = $container
->get('entity_type.bundle.info');
return $instance;
}
public function getViewsData() {
$data = parent::getViewsData();
$this->tableMapping = $this->storage
->getTableMapping();
$entity_type_id = $this->entityType
->id();
if ($this->entityType
->isRevisionable()) {
$revision_table = $this->tableMapping
->getRevisionTable();
$data[$revision_table]['table']['entity revision'] = TRUE;
}
$base_fields = $this->entityFieldManager
->getBaseFieldDefinitions($entity_type_id);
$entity_reference_fields = array_filter($base_fields, function (BaseFieldDefinition $field) {
return $field
->getType() === 'entity_reference' && !$field
->isComputed();
});
if (in_array($entity_type_id, [
'commerce_order',
'commerce_product',
])) {
unset($entity_reference_fields['variations']);
unset($entity_reference_fields['order_items']);
}
$this
->addReverseRelationships($data, $entity_reference_fields);
if ($this->entityType
->hasHandlerClass('bundle_plugin')) {
$bundles = $this->entityTypeBundleInfo
->getBundleInfo($entity_type_id);
foreach (array_keys($bundles) as $bundle) {
$field_definitions = $this->entityFieldManager
->getFieldDefinitions($entity_type_id, $bundle);
foreach ($field_definitions as $field_definition) {
if ($field_definition instanceof BundleFieldDefinition) {
$this
->addBundleFieldData($data, $field_definition);
}
}
}
}
if ($bundle_key = $this->entityType
->getKey('bundle')) {
$base_table = $this
->getViewsTableForEntityType($this->entityType);
$data[$base_table][$bundle_key]['field']['id'] = 'commerce_entity_bundle';
$data[$base_table][$bundle_key]['filter']['id'] = 'commerce_entity_bundle';
}
return $data;
}
protected function addBundleFieldData(array &$data, BundleFieldDefinition $bundle_field) {
$field_name = $bundle_field
->getName();
$entity_type_id = $this->entityType
->id();
$base_table = $this
->getViewsTableForEntityType($this->entityType);
$revision_table = '';
if ($this->entityType
->isRevisionable()) {
$revision_table = $this->tableMapping
->getRevisionDataTable();
if (!$revision_table) {
$revision_table = $this->tableMapping
->getRevisionTable();
}
}
$field_tables = [];
$field_tables[EntityStorageInterface::FIELD_LOAD_CURRENT] = [
'table' => $this->tableMapping
->getDedicatedDataTableName($bundle_field),
'alias' => "{$entity_type_id}__{$field_name}",
];
if ($this->entityType
->isRevisionable()) {
$field_tables[EntityStorageInterface::FIELD_LOAD_REVISION] = [
'table' => $this->tableMapping
->getDedicatedRevisionTableName($bundle_field),
'alias' => "{$entity_type_id}_revision__{$field_name}",
];
}
$table_alias = $field_tables[EntityStorageInterface::FIELD_LOAD_CURRENT]['alias'];
$data[$table_alias]['table']['group'] = $this->entityType
->getLabel();
$data[$table_alias]['table']['join'][$base_table] = [
'table' => $this->tableMapping
->getDedicatedDataTableName($bundle_field),
'left_field' => $this->entityType
->getKey('id'),
'field' => 'entity_id',
'extra' => [
[
'field' => 'deleted',
'value' => 0,
'numeric' => TRUE,
],
],
];
if ($bundle_field
->isTranslatable()) {
$data[$table_alias]['table']['join'][$base_table]['extra'][] = [
'left_field' => 'langcode',
'field' => 'langcode',
];
}
if ($this->entityType
->isRevisionable()) {
$table_alias = $field_tables[EntityStorageInterface::FIELD_LOAD_REVISION]['alias'];
$data[$table_alias]['table']['group'] = $this
->t('@group (historical data)', [
'@group' => $this->entityType
->getLabel(),
]);
$data[$table_alias]['table']['join'][$revision_table] = [
'table' => $this->tableMapping
->getDedicatedRevisionTableName($bundle_field),
'left_field' => $this->entityType
->getKey('revision'),
'field' => 'revision_id',
'extra' => [
[
'field' => 'deleted',
'value' => 0,
'numeric' => TRUE,
],
],
];
if ($bundle_field
->isTranslatable()) {
$data[$table_alias]['table']['join'][$revision_table]['extra'][] = [
'left_field' => 'langcode',
'field' => 'langcode',
];
}
}
foreach ($field_tables as $type => $table_info) {
$table_alias = $table_info['alias'];
$data[$table_alias]['table']['title'] = $bundle_field
->getLabel();
$data[$table_alias]['table']['help'] = $bundle_field
->getDescription();
$data[$table_alias]['table']['entity type'] = $this->entityType
->id();
$data[$table_alias]['table']['provider'] = $this->entityType
->getProvider();
$this
->mapFieldDefinition($table_info['table'], $field_name, $bundle_field, $this->tableMapping, $data[$table_alias]);
}
}
protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterface $field_definition, TableMappingInterface $table_mapping, &$table_data) {
$field_column_mapping = $table_mapping
->getColumnNames($field_name);
$field_storage = $this
->getFieldStorageDefinitions()[$field_name];
$field_schema = $field_storage
->getSchema();
$field_definition_type = $field_definition
->getType();
$main_property = $field_storage
->getMainPropertyName();
if (!$main_property) {
$property_names = array_keys($field_column_mapping);
$main_property = reset($property_names);
}
foreach ($field_column_mapping as $field_column_name => $schema_field_name) {
$first = $main_property == $field_column_name;
$table_data[$schema_field_name] = $this
->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition);
$table_data[$schema_field_name]['entity field'] = $field_name;
if (!$first && $table_data[$schema_field_name]['field']['id'] == 'field') {
$table_data[$schema_field_name]['field']['id'] = 'standard';
}
foreach ([
'argument',
'filter',
'sort',
] as $handler_type) {
if (isset($table_data[$schema_field_name][$handler_type])) {
$table_data[$schema_field_name][$handler_type]['field_name'] = $field_name;
}
}
}
if ($field_storage
->isMultiple()) {
$label = $field_definition
->getLabel();
$table_data['delta'] = [
'title' => $this
->t('@label (@name:delta)', [
'@label' => $label,
'@name' => $field_name,
]),
'title short' => t('@label:delta', [
'@label' => $label,
]),
];
$table_data['delta']['field'] = [
'id' => 'numeric',
];
$table_data['delta']['argument'] = [
'field' => 'delta',
'table' => $table,
'id' => 'numeric',
'empty field name' => $this
->t('- No value -'),
'field_name' => $field_name,
'entity_type' => $this->entityType
->id(),
];
$table_data['delta']['filter'] = [
'field' => 'delta',
'table' => $table,
'id' => 'numeric',
'field_name' => $field_name,
'entity_type' => $this->entityType
->id(),
'allow empty' => TRUE,
];
$table_data['delta']['sort'] = [
'field' => 'delta',
'table' => $table,
'id' => 'standard',
'field_name' => $field_name,
'entity_type' => $this->entityType
->id(),
];
}
}
protected function processViewsDataForAddress($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
$handlers_by_property = [
'country_code' => 'country',
'administrative_area' => 'subdivision',
'locality' => 'subdivision',
'dependent_locality' => 'subdivision',
'postal_code' => 'standard',
'sorting_code' => 'standard',
'address_line1' => 'standard',
'address_line2' => 'standard',
'organization' => 'standard',
'given_name' => 'standard',
'additional_name' => 'standard',
'family_name' => 'standard',
];
if (!isset($handlers_by_property[$field_column_name])) {
return;
}
$views_field['field'] = [
'id' => $handlers_by_property[$field_column_name],
'field_name' => $field_definition
->getName(),
'property' => $field_column_name,
];
if ($field_column_name == 'country_code') {
$views_field['filter']['id'] = 'country';
$views_field['sort']['id'] = 'country';
}
elseif ($field_column_name == 'administrative_area') {
$views_field['filter']['id'] = 'administrative_area';
}
}
protected function processViewsDataForAddressCountry($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
if ($field_column_name == 'value') {
$views_field['field'] = [
'id' => 'country',
'field_name' => $field_definition
->getName(),
'property' => 'value',
];
$views_field['filter']['id'] = 'country';
$views_field['sort']['id'] = 'country';
}
}
protected function processViewsDataForCommercePrice($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
if ($field_column_name == 'number') {
$views_field['filter']['id'] = 'numeric';
}
elseif ($field_column_name == 'currency_code') {
$views_field['filter']['id'] = 'commerce_currency';
}
}
protected function processViewsDataForDatetime($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
if ($field_column_name == 'value') {
$views_field['filter']['id'] = 'datetime';
$views_field['argument']['id'] = 'datetime';
$views_field['sort']['id'] = 'datetime';
}
}
protected function processViewsDataForListFloat($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
$this
->processViewsDataForListInteger($table, $field_definition, $views_field, $field_column_name);
}
protected function processViewsDataForListInteger($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
if ($field_column_name == 'value') {
$views_field['filter']['id'] = 'list_field';
$views_field['argument']['id'] = 'number_list_field';
}
}
protected function processViewsDataForListString($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
if ($field_column_name == 'value') {
$views_field['filter']['id'] = 'list_field';
$views_field['argument']['id'] = 'string_list_field';
}
}
protected function processViewsDataForState($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
if ($field_column_name == 'value') {
$views_field['filter']['id'] = 'state_machine_state';
}
}
protected function addReverseRelationships(array &$data, array $fields) {
$entity_type_id = $this->entityType
->id();
$base_table = $this
->getViewsTableForEntityType($this->entityType);
assert($this->entityType instanceof ContentEntityType);
$revision_metadata_field_names = array_flip($this->entityType
->getRevisionMetadataKeys());
foreach ($fields as $field) {
$target_entity_type_id = $field
->getSettings()['target_type'];
$target_entity_type = $this->entityTypeManager
->getDefinition($target_entity_type_id);
if (!$target_entity_type instanceof ContentEntityType) {
continue;
}
$target_table = $this
->getViewsTableForEntityType($target_entity_type);
$field_name = $field
->getName();
$field_storage = $field
->getFieldStorageDefinition();
$args = [
'@label' => $target_entity_type
->getSingularLabel(),
'@entity' => $this->entityType
->getLabel(),
'@field_name' => $field_name,
];
$pseudo_field_name = 'reverse__' . $entity_type_id . '__' . $field_name;
$relationship_data = [
'label' => $this->entityType
->getLabel(),
'group' => $target_entity_type
->getLabel(),
'entity_type' => $entity_type_id,
];
if ($this->tableMapping
->requiresDedicatedTableStorage($field_storage)) {
$data[$target_table][$pseudo_field_name]['relationship'] = [
'id' => 'entity_reverse',
'title' => $this
->t('@entity using @field_name', $args),
'help' => $this
->t('Relate each @entity with a @field_name field set to the @label.', $args),
'base' => $base_table,
'base field' => $this->entityType
->getKey('id'),
'field_name' => $field_name,
'field table' => $this->tableMapping
->getFieldTableName($field_name),
'field field' => $this->tableMapping
->getFieldColumnName($field_storage, 'target_id'),
] + $relationship_data;
}
elseif (isset($revision_metadata_field_names[$field_name])) {
$revision_table = $this->tableMapping
->getRevisionTable();
$data[$target_table][$pseudo_field_name]['relationship'] = [
'id' => 'standard',
'title' => $this
->t('@entity revision using @field_name', $args),
'help' => $this
->t('Relate each @entity revision with a @field_name field set to the @label.', $args),
'base' => $revision_table,
'base field' => $this->tableMapping
->getFieldColumnName($field_storage, 'target_id'),
'relationship field' => $target_entity_type
->getKey('id'),
] + $relationship_data;
}
else {
$data[$target_table][$pseudo_field_name]['relationship'] = [
'id' => 'standard',
'title' => $this
->t('@entity using @field_name', $args),
'help' => $this
->t('Relate each @entity with a @field_name field set to the @label.', $args),
'base' => $base_table,
'base field' => $this->tableMapping
->getFieldColumnName($field_storage, 'target_id'),
'relationship field' => $target_entity_type
->getKey('id'),
] + $relationship_data;
}
}
}
}