Issue #1740492 by dawehner, damiankloip, dasjo, xjm: Implement a default entity views data handler.
parent
7f69cb4456
commit
35b3d0faeb
|
@ -28,7 +28,7 @@ class SqlContentEntityStorageSchema implements EntitySchemaHandlerInterface {
|
|||
/**
|
||||
* The storage field definitions for this entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldDefinitionInterface[]
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]
|
||||
*/
|
||||
protected $fieldStorageDefinitions;
|
||||
|
||||
|
|
|
@ -7,118 +7,47 @@
|
|||
|
||||
namespace Drupal\file;
|
||||
|
||||
use Drupal\views\EntityViewsDataInterface;
|
||||
use Drupal\views\EntityViewsData;
|
||||
|
||||
/**
|
||||
* Provides views data for the file entity type.
|
||||
*/
|
||||
class FileViewsData implements EntityViewsDataInterface {
|
||||
class FileViewsData extends EntityViewsData {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewsData() {
|
||||
$data = array();
|
||||
// Sets 'group' index for file_managed table.
|
||||
$data['file_managed']['table']['group'] = t('File');
|
||||
$data = parent::getViewsData();
|
||||
|
||||
// Advertise this table as a possible base table.
|
||||
$data['file_managed']['table']['base'] = array(
|
||||
'field' => 'fid',
|
||||
'title' => t('File'),
|
||||
'help' => t("Files maintained by Drupal and various modules."),
|
||||
'defaults' => array(
|
||||
'field' => 'filename'
|
||||
),
|
||||
);
|
||||
$data['file_managed']['table']['entity type'] = 'file';
|
||||
// @TODO There is no corresponding information in entity metadata.
|
||||
$data['file_managed']['table']['base']['help'] = t('Files maintained by Drupal and various modules.');
|
||||
$data['file_managed']['table']['base']['defaults']['field'] = 'filename';
|
||||
$data['file_managed']['table']['wizard_id'] = 'file_managed';
|
||||
|
||||
// Describes fid field in file_managed table.
|
||||
$data['file_managed']['fid'] = array(
|
||||
'title' => t('File ID'),
|
||||
'help' => t('The ID of the file.'),
|
||||
'field' => array(
|
||||
'id' => 'file',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'file_fid',
|
||||
// The field to display in the summary.
|
||||
'name field' => 'filename',
|
||||
'numeric' => TRUE,
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'relationship' => array(
|
||||
'title' => t('File usage'),
|
||||
'help' => t('Relate file entities to their usage.'),
|
||||
'id' => 'standard',
|
||||
'base' => 'file_usage',
|
||||
'base field' => 'fid',
|
||||
'field' => 'fid',
|
||||
'label' => t('File usage'),
|
||||
),
|
||||
$data['file_managed']['fid']['field']['id'] ='file';
|
||||
$data['file_managed']['fid']['argument'] = array(
|
||||
'id' => 'file_fid',
|
||||
// The field to display in the summary.
|
||||
'name field' => 'filename',
|
||||
'numeric' => TRUE,
|
||||
);
|
||||
$data['file_managed']['fid']['relationship'] = array(
|
||||
'title' => t('File usage'),
|
||||
'help' => t('Relate file entities to their usage.'),
|
||||
'id' => 'standard',
|
||||
'base' => 'file_usage',
|
||||
'base field' => 'fid',
|
||||
'field' => 'fid',
|
||||
'label' => t('File usage'),
|
||||
);
|
||||
|
||||
// Describes filename field in file_managed table.
|
||||
$data['file_managed']['filename'] = array(
|
||||
'title' => t('Name'),
|
||||
'help' => t('The name of the file.'),
|
||||
'field' => array(
|
||||
'id' => 'file',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
);
|
||||
$data['file_managed']['filename']['field']['id'] = 'file';
|
||||
|
||||
// Describes uri field in file_managed table.
|
||||
$data['file_managed']['uri'] = array(
|
||||
'title' => t('Path'),
|
||||
'help' => t('The path of the file.'),
|
||||
'field' => array(
|
||||
'id' => 'file_uri',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
);
|
||||
$data['file_managed']['uri']['field']['id'] = 'file_uri';
|
||||
|
||||
// Describes filemime field in file_managed table.
|
||||
$data['file_managed']['filemime'] = array(
|
||||
'title' => t('Mime type'),
|
||||
'help' => t('The mime type of the file.'),
|
||||
'field' => array(
|
||||
'id' => 'file_filemime',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
);
|
||||
$data['file_managed']['filemime']['field']['id'] = 'file_filemime';
|
||||
|
||||
// Describes extension field in file_managed table.
|
||||
$data['file_managed']['extension'] = array(
|
||||
'title' => t('Extension'),
|
||||
'help' => t('The extension of the file.'),
|
||||
|
@ -129,79 +58,14 @@ class FileViewsData implements EntityViewsDataInterface {
|
|||
),
|
||||
);
|
||||
|
||||
// Describes filesize field in file_managed table.
|
||||
$data['file_managed']['filesize'] = array(
|
||||
'title' => t('Size'),
|
||||
'help' => t('The size of the file.'),
|
||||
'field' => array(
|
||||
'id' => 'file_size',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
);
|
||||
$data['file_managed']['filesize']['field']['id'] = 'file_size';
|
||||
|
||||
// Describes status field in file_managed table.
|
||||
$data['file_managed']['status'] = array(
|
||||
'title' => t('Status'),
|
||||
'help' => t('The status of the file.'),
|
||||
'field' => array(
|
||||
'id' => 'file_status',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'file_status',
|
||||
),
|
||||
);
|
||||
$data['file_managed']['status']['field']['id'] = 'file_status';
|
||||
$data['file_managed']['status']['filter']['id'] = 'file_status';
|
||||
|
||||
// Describes created field in file_managed table.
|
||||
$data['file_managed']['created'] = array(
|
||||
'title' => t('Upload date'),
|
||||
'help' => t('The date the file was uploaded.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
$data['file_managed']['uid']['relationship']['title'] = t('User who uploaded');
|
||||
$data['file_managed']['uid']['relationship']['label'] = t('User who uploaded');
|
||||
|
||||
// Describes changed field in file_managed table.
|
||||
$data['file_managed']['changed'] = array(
|
||||
'title' => t('Modified date'),
|
||||
'help' => t('The date the file was last changed.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
|
||||
// Describes uid field in file_managed table.
|
||||
$data['file_managed']['uid'] = array(
|
||||
'title' => t('User who uploaded'),
|
||||
'help' => t('The user that uploaded the file.'),
|
||||
'relationship' => array(
|
||||
'title' => t('User who uploaded'),
|
||||
'label' => t('User who uploaded'),
|
||||
'base' => 'users',
|
||||
'base field' => 'uid',
|
||||
),
|
||||
);
|
||||
|
||||
// Sets 'group' index for file_usage table.
|
||||
$data['file_usage']['table']['group'] = t('File Usage');
|
||||
|
||||
// Provide field-type-things to several base tables; on the core files table
|
||||
|
@ -499,4 +363,3 @@ class FileViewsData implements EntityViewsDataInterface {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,169 +7,48 @@
|
|||
|
||||
namespace Drupal\node;
|
||||
|
||||
use Drupal\views\EntityViewsData;
|
||||
use Drupal\views\EntityViewsDataInterface;
|
||||
|
||||
/**
|
||||
* Provides the views data for the node entity type.
|
||||
*/
|
||||
class NodeViewsData implements EntityViewsDataInterface {
|
||||
class NodeViewsData extends EntityViewsData implements EntityViewsDataInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewsData() {
|
||||
// Define the base group of this table. Fields that don't have a group defined
|
||||
// will go into this field by default.
|
||||
$data['node']['table']['group'] = t('Content');
|
||||
$data = parent::getViewsData();
|
||||
|
||||
// Advertise this table as a possible base table.
|
||||
$data['node']['table']['base'] = array(
|
||||
'field' => 'nid',
|
||||
'title' => t('Content'),
|
||||
'weight' => -10,
|
||||
'access query tag' => 'node_access',
|
||||
'defaults' => array(
|
||||
'field' => 'title',
|
||||
),
|
||||
);
|
||||
$data['node']['table']['entity type'] = 'node';
|
||||
$data['node']['table']['base']['weight'] = -10;
|
||||
$data['node']['table']['base']['access query tag'] = 'node_access';
|
||||
$data['node']['table']['wizard_id'] = 'node';
|
||||
|
||||
$data['node_field_data']['table']['group'] = t('Content');
|
||||
$data['node_field_data']['table']['entity type'] = 'node';
|
||||
$data['node_field_data']['table']['join']['node'] = array(
|
||||
'type' => 'INNER',
|
||||
'left_field' => 'nid',
|
||||
'field' => 'nid',
|
||||
);
|
||||
$data['node']['nid']['field']['id'] = 'node';
|
||||
$data['node']['nid']['field']['argument'] = [
|
||||
'id' => 'node_nid',
|
||||
'name field' => 'title',
|
||||
'numeric' => TRUE,
|
||||
'validate type' => 'nid',
|
||||
];
|
||||
|
||||
$data['node']['nid'] = array(
|
||||
'title' => t('Nid'),
|
||||
'help' => t('The node ID.'),
|
||||
'field' => array(
|
||||
'id' => 'node',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_nid',
|
||||
'name field' => 'title',
|
||||
'numeric' => TRUE,
|
||||
'validate type' => 'nid',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['title']['field']['id'] = 'node';
|
||||
$data['node_field_data']['title']['field']['link_to_node default'] = TRUE;
|
||||
|
||||
// This definition has more items in it than it needs to as an example.
|
||||
$data['node_field_data']['title'] = array(
|
||||
'title' => t('Title'),
|
||||
'help' => t('The content title.'),
|
||||
'field' => array(
|
||||
// This is the real field which could be left out since it is the same.
|
||||
'field' => 'title',
|
||||
// This is the UI group which could be left out since it is the same.
|
||||
'group' => t('Content'),
|
||||
'id' => 'node',
|
||||
'link_to_node default' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['type']['field']['id'] = 'node_type';
|
||||
$data['node_field_data']['type']['argument']['id'] = 'node_type';
|
||||
|
||||
$data['node_field_data']['created'] = array(
|
||||
'title' => t('Post date'),
|
||||
'help' => t('The date the content was posted.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date'
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['langcode']['help'] = t('The language of the content or translation.');
|
||||
$data['node_field_data']['langcode']['field']['id'] = 'node_language';
|
||||
|
||||
$data['node_field_data']['changed'] = array(
|
||||
'title' => t('Updated date'),
|
||||
'help' => t('The date the content was last updated.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date'
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
|
||||
$data['node_field_data']['type'] = array(
|
||||
'title' => t('Type'),
|
||||
'help' => t('The content type (for example, "blog entry", "forum post", "story", etc).'),
|
||||
'field' => array(
|
||||
'id' => 'node_type',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'bundle',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_type',
|
||||
),
|
||||
);
|
||||
|
||||
if (\Drupal::moduleHandler()->moduleExists('language')) {
|
||||
$data['node_field_data']['langcode'] = array(
|
||||
'title' => t('Translation language'),
|
||||
'help' => t('The language of the content or translation.'),
|
||||
'field' => array(
|
||||
'id' => 'node_language',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'language',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'language',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$data['node_field_data']['status'] = array(
|
||||
'title' => t('Published status'),
|
||||
'help' => t('Whether or not the content is published.'),
|
||||
'field' => array(
|
||||
'id' => 'boolean',
|
||||
'output formats' => array(
|
||||
'published-notpublished' => array(t('Published'), t('Not published')),
|
||||
),
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'boolean',
|
||||
'label' => t('Published status'),
|
||||
'type' => 'yes-no',
|
||||
// Use status = 1 instead of status <> 0 in WHERE statement.
|
||||
'use_equal' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['status']['field']['output formats'] = [
|
||||
'published-notpublished' => array(t('Published'), t('Not published')),
|
||||
];
|
||||
$data['node_field_data']['status']['filter']['label'] = t('Published status');
|
||||
$data['node_field_data']['status']['filter']['type'] = 'yes-no';
|
||||
// Use status = 1 instead of status <> 0 in WHERE statement.
|
||||
$data['node_field_data']['status']['filter']['use_equal'] = TRUE;
|
||||
|
||||
$data['node_field_data']['status_extra'] = array(
|
||||
'title' => t('Published status or admin user'),
|
||||
|
@ -181,44 +60,18 @@ class NodeViewsData implements EntityViewsDataInterface {
|
|||
),
|
||||
);
|
||||
|
||||
$data['node_field_data']['promote'] = array(
|
||||
'title' => t('Promoted to front page status'),
|
||||
'help' => t('Whether or not the content is promoted to the front page.'),
|
||||
'field' => array(
|
||||
'id' => 'boolean',
|
||||
'output formats' => array(
|
||||
'promoted-notpromoted' => array(t('Promoted'), t('Not promoted')),
|
||||
),
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'boolean',
|
||||
'label' => t('Promoted to front page status'),
|
||||
'type' => 'yes-no',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['promote']['field']['output formats'] = [
|
||||
'promoted-notpromoted' => array(t('Promoted'), t('Not promoted')),
|
||||
];
|
||||
$data['node_field_data']['promote']['filter']['label'] = t('Promoted to front page status');
|
||||
$data['node_field_data']['promote']['filter']['type'] = 'yes-no';
|
||||
|
||||
$data['node_field_data']['sticky'] = array(
|
||||
'title' => t('Sticky status'),
|
||||
'help' => t('Whether or not the content is sticky.'),
|
||||
'field' => array(
|
||||
'id' => 'boolean',
|
||||
'output formats' => array(
|
||||
'sticky' => array(t('Sticky'), t('Not sticky')),
|
||||
),
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'boolean',
|
||||
'label' => t('Sticky status'),
|
||||
'type' => 'yes-no',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
'help' => t('Whether or not the content is sticky. To list sticky content first, set this to descending.'),
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['sticky']['field']['output formats'] = [
|
||||
'sticky' => array(t('Sticky'), t('Not sticky')),
|
||||
];
|
||||
$data['node_field_data']['sticky']['filter']['label'] = t('Sticky status');
|
||||
$data['node_field_data']['sticky']['filter']['type'] = 'yes-no';
|
||||
$data['node_field_data']['sticky']['sort']['help'] = t('Whether or not the content is sticky. To list sticky content first, set this to descending.');
|
||||
|
||||
if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
|
||||
$data['node']['translation_link'] = array(
|
||||
|
@ -264,6 +117,8 @@ class NodeViewsData implements EntityViewsDataInterface {
|
|||
|
||||
// Bogus fields for aliasing purposes.
|
||||
|
||||
// @todo Add similar support to any date field
|
||||
// @see https://drupal.org/node/2337507
|
||||
$data['node_field_data']['created_fulldate'] = array(
|
||||
'title' => t('Created date'),
|
||||
'help' => t('Date in the form of CCYYMMDD.'),
|
||||
|
@ -372,27 +227,12 @@ class NodeViewsData implements EntityViewsDataInterface {
|
|||
),
|
||||
);
|
||||
|
||||
$data['node_field_data']['uid'] = array(
|
||||
'title' => t('Author uid'),
|
||||
'help' => t('The user authoring the content. If you need more fields than the uid add the content: author relationship'),
|
||||
'relationship' => array(
|
||||
'title' => t('Content author'),
|
||||
'help' => t('Relate content to the user who created it.'),
|
||||
'id' => 'standard',
|
||||
'base' => 'users',
|
||||
'field' => 'uid',
|
||||
'label' => t('author'),
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'user_name',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'field' => array(
|
||||
'id' => 'user',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['uid']['help'] = t('The user authoring the content. If you need more fields than the uid add the content: author relationship');
|
||||
$data['node_field_data']['uid']['filter']['id'] = 'user_name';
|
||||
$data['node_field_data']['uid']['field']['id'] = 'user';
|
||||
$data['node_field_data']['uid']['relationship']['title'] = t('Content author');
|
||||
$data['node_field_data']['uid']['relationship']['help'] = t('Relate content to the user who created it.');
|
||||
$data['node_field_data']['uid']['relationship']['label'] = t('author');
|
||||
|
||||
$data['node']['node_listing_empty'] = array(
|
||||
'title' => t('Empty Node Frontpage behavior'),
|
||||
|
@ -402,83 +242,36 @@ class NodeViewsData implements EntityViewsDataInterface {
|
|||
),
|
||||
);
|
||||
|
||||
$data['node_field_data']['uid_revision'] = array(
|
||||
'title' => t('User has a revision'),
|
||||
'help' => t('All nodes where a certain user has a revision'),
|
||||
'real field' => 'nid',
|
||||
'filter' => array(
|
||||
'id' => 'node_uid_revision',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_uid_revision',
|
||||
),
|
||||
);
|
||||
$data['node_field_data']['uid_revision']['title'] = t('User has a revision');
|
||||
$data['node_field_data']['uid_revision']['help'] = t('All nodes where a certain user has a revision');
|
||||
$data['node_field_data']['uid_revision']['real field'] = 'nid';
|
||||
$data['node_field_data']['uid_revision']['filter']['id'] = 'node_uid_revision';
|
||||
$data['node_field_data']['uid_revision']['argument']['id'] = 'node_uid_revision';
|
||||
|
||||
$data['node_revision']['table']['entity type'] = 'node';
|
||||
// Define the base group of this table. Fields that don't have a group defined
|
||||
// will go into this field by default.
|
||||
$data['node_revision']['table']['group'] = t('Content revision');
|
||||
$data['node_revision']['table']['wizard_id'] = 'node_revision';
|
||||
|
||||
// Advertise this table as a possible base table.
|
||||
$data['node_revision']['table']['base'] = array(
|
||||
'field' => 'vid',
|
||||
'title' => t('Content revision'),
|
||||
'help' => t('Content revision is a history of changes to content.'),
|
||||
'defaults' => array(
|
||||
'field' => 'title',
|
||||
),
|
||||
);
|
||||
$data['node_revision']['table']['base']['help'] = t('Content revision is a history of changes to content.');
|
||||
$data['node_revision']['table']['base']['defaults']['title'] = 'title';
|
||||
|
||||
// For other base tables, explain how we join.
|
||||
$data['node_revision']['table']['join'] = array(
|
||||
'node' => array(
|
||||
'left_field' => 'vid',
|
||||
'field' => 'vid',
|
||||
),
|
||||
);
|
||||
|
||||
$data['node_revision']['nid'] = array(
|
||||
'title' => t('Nid'),
|
||||
'help' => t('The revision NID of the content revision.'),
|
||||
'field' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_nid',
|
||||
'numeric' => TRUE,
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'relationship' => array(
|
||||
'id' => 'standard',
|
||||
'base' => 'node',
|
||||
'base field' => 'nid',
|
||||
'title' => t('Content'),
|
||||
'label' => t('Get the actual content from a content revision.'),
|
||||
),
|
||||
);
|
||||
$data['node_revision']['nid']['argument'] = [
|
||||
'id' => 'node_nid',
|
||||
'numeric' => TRUE,
|
||||
];
|
||||
// @todo the NID field needs different behaviour on revision/non-revision
|
||||
// tables. It would be neat if this could be encoded in the base field
|
||||
// definition.
|
||||
$data['node_revision']['nid']['relationship']['id'] = 'standard';
|
||||
$data['node_revision']['nid']['relationship']['base'] = 'node';
|
||||
$data['node_revision']['nid']['relationship']['base field'] = 'nid';
|
||||
$data['node_revision']['nid']['relationship']['title'] = t('Content');
|
||||
$data['node_revision']['nid']['relationship']['label'] = t('Get the actual content from a content revision.');
|
||||
|
||||
$data['node_revision']['vid'] = array(
|
||||
'title' => t('Vid'),
|
||||
'help' => t('The revision ID of the content revision.'),
|
||||
'field' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'node_vid',
|
||||
'numeric' => TRUE,
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'numeric',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'relationship' => array(
|
||||
'id' => 'standard',
|
||||
'base' => 'node',
|
||||
|
@ -486,119 +279,29 @@ class NodeViewsData implements EntityViewsDataInterface {
|
|||
'title' => t('Content'),
|
||||
'label' => t('Get the actual content from a content revision.'),
|
||||
),
|
||||
);
|
||||
) + $data['node_revision']['vid'];
|
||||
|
||||
if (\Drupal::moduleHandler()->moduleExists('language')) {
|
||||
$data['node_revision']['langcode'] = array(
|
||||
'title' => t('Original language'),
|
||||
'help' => t('The language the original content is in.'),
|
||||
'field' => array(
|
||||
'id' => 'node_language',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'language',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'language',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
}
|
||||
$data['node_revision']['langcode']['help'] = t('The language the original content is in.');
|
||||
$data['node_revision']['langcode']['field']['id'] = 'node_language';
|
||||
|
||||
$data['node_revision']['revision_log'] = array(
|
||||
'title' => t('Log message'),
|
||||
'help' => t('The log message entered when the revision was created.'),
|
||||
'field' => array(
|
||||
'id' => 'xss',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
);
|
||||
$data['node_revision']['revision_log']['field']['id'] = 'xss';
|
||||
|
||||
$data['node_revision']['revision_uid'] = array(
|
||||
'title' => t('User'),
|
||||
'help' => t('Relate a content revision to the user who created the revision.'),
|
||||
'relationship' => array(
|
||||
'id' => 'standard',
|
||||
'base' => 'users',
|
||||
'base field' => 'uid',
|
||||
'label' => t('revision user'),
|
||||
),
|
||||
);
|
||||
$data['node_revision']['revision_uid']['help'] = t('Relate a content revision to the user who created the revision.');
|
||||
$data['node_revision']['revision_uid']['relationship']['label'] = t('revision user');
|
||||
|
||||
$data['node_field_revision']['table']['entity type'] = 'node';
|
||||
// Define the base group of this table. Fields that don't have a group defined
|
||||
// will go into this field by default.
|
||||
$data['node_field_revision']['table']['group'] = t('Content revision');
|
||||
$data['node_field_revision']['table']['wizard_id'] = 'node_field_revision';
|
||||
|
||||
// For other base tables, explain how we join.
|
||||
$data['node_field_revision']['table']['join'] = array(
|
||||
'node' => array(
|
||||
'left_field' => 'vid',
|
||||
'field' => 'vid',
|
||||
),
|
||||
'node_revision' => array(
|
||||
'left_field' => 'vid',
|
||||
'field' => 'vid',
|
||||
),
|
||||
);
|
||||
$data['node_field_revision']['table']['join']['node']['left_field'] = 'vid';
|
||||
$data['node_field_revision']['table']['join']['node']['field'] = 'vid';
|
||||
|
||||
$data['node_field_revision']['status'] = array(
|
||||
'title' => t('Published'),
|
||||
'help' => t('Whether or not the content is published.'),
|
||||
'field' => array(
|
||||
'id' => 'boolean',
|
||||
'output formats' => array(
|
||||
'published-notpublished' => array(t('Published'), t('Not published')),
|
||||
),
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'boolean',
|
||||
'label' => t('Published'),
|
||||
'type' => 'yes-no',
|
||||
// Use status = 1 instead of status <> 0 in WHERE statement.
|
||||
'use_equal' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
);
|
||||
$data['node_field_revision']['status']['field']['output formats'] = [
|
||||
'published-notpublished' => [t('Published'), t('Not published')],
|
||||
];
|
||||
$data['node_field_revision']['status']['filter']['label'] = t('Published');
|
||||
$data['node_field_revision']['status']['filter']['type'] = 'yes-no';
|
||||
$data['node_field_revision']['status']['filter']['use_equal'] = TRUE;
|
||||
|
||||
$data['node_field_revision']['title'] = array(
|
||||
'title' => t('Title'),
|
||||
'help' => t('The content title.'),
|
||||
'field' => array(
|
||||
'field' => 'title',
|
||||
'id' => 'node_revision',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'standard',
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
'argument' => array(
|
||||
'id' => 'string',
|
||||
),
|
||||
);
|
||||
|
||||
$data['node_field_revision']['changed'] = array(
|
||||
'title' => t('Updated date'),
|
||||
'help' => t('The date the content was last updated.'),
|
||||
'field' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
'sort' => array(
|
||||
'id' => 'date'
|
||||
),
|
||||
'filter' => array(
|
||||
'id' => 'date',
|
||||
),
|
||||
);
|
||||
$data['node_field_revision']['title']['field']['id'] = 'node_revision';
|
||||
|
||||
$data['node_revision']['link_to_revision'] = array(
|
||||
'field' => array(
|
||||
|
@ -727,6 +430,4 @@ class NodeViewsData implements EntityViewsDataInterface {
|
|||
return $data;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -310,7 +310,8 @@ use Drupal\Core\Render\Element;
|
|||
* config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
|
||||
* You can extend one of these classes to provide custom behavior.
|
||||
* - views_data: A class implementing \Drupal\views\EntityViewsDataInterface
|
||||
* to provide views data for the entity type.
|
||||
* to provide views data for the entity type. You can autogenerate most of
|
||||
* the views data by extending \Drupal\views\EntityViewsData.
|
||||
* - For content entities, the annotation will refer to a number of database
|
||||
* tables and their fields. These annotation properties, such as 'base_table',
|
||||
* 'data_table', 'entity_keys', etc., are documented on
|
||||
|
|
|
@ -29,7 +29,8 @@ use Drupal\user\UserInterface;
|
|||
* "default" = "Drupal\entity_test\EntityTestForm",
|
||||
* "delete" = "Drupal\entity_test\EntityTestDeleteForm"
|
||||
* },
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler"
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler",
|
||||
* "views_data" = "Drupal\views\EntityViewsData"
|
||||
* },
|
||||
* base_table = "entity_test",
|
||||
* fieldable = TRUE,
|
||||
|
|
|
@ -24,7 +24,8 @@ use Drupal\entity_test\Entity\EntityTest;
|
|||
* "default" = "Drupal\entity_test\EntityTestForm",
|
||||
* "delete" = "Drupal\entity_test\EntityTestDeleteForm"
|
||||
* },
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler"
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler",
|
||||
* "views_data" = "Drupal\views\EntityViewsData"
|
||||
* },
|
||||
* base_table = "entity_test_mul",
|
||||
* data_table = "entity_test_mul_property_data",
|
||||
|
|
|
@ -23,7 +23,8 @@ use Drupal\entity_test\Entity\EntityTestRev;
|
|||
* "default" = "Drupal\entity_test\EntityTestForm",
|
||||
* "delete" = "Drupal\entity_test\EntityTestDeleteForm"
|
||||
* },
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler"
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler",
|
||||
* "views_data" = "Drupal\views\EntityViewsData"
|
||||
* },
|
||||
* base_table = "entity_test_mulrev",
|
||||
* data_table = "entity_test_mulrev_property_data",
|
||||
|
|
|
@ -23,7 +23,8 @@ use Drupal\entity_test\Entity\EntityTest;
|
|||
* "default" = "Drupal\entity_test\EntityTestForm",
|
||||
* "delete" = "Drupal\entity_test\EntityTestDeleteForm"
|
||||
* },
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler"
|
||||
* "translation" = "Drupal\content_translation\ContentTranslationHandler",
|
||||
* "views_data" = "Drupal\views\EntityViewsData"
|
||||
* },
|
||||
* base_table = "entity_test_rev",
|
||||
* revision_table = "entity_test_rev_revision",
|
||||
|
|
|
@ -0,0 +1,446 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\EntityViewsData.
|
||||
*/
|
||||
|
||||
namespace Drupal\views;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityType;
|
||||
use Drupal\Core\Entity\EntityHandlerInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
|
||||
use Drupal\Core\Entity\Sql\TableMappingInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides generic views integration for entities.
|
||||
*/
|
||||
class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Entity type for this views controller instance.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The storage used for this entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The translation manager.
|
||||
*
|
||||
* @var \Drupal\Core\StringTranslation\TranslationInterface
|
||||
*/
|
||||
protected $translationManager;
|
||||
|
||||
/**
|
||||
* The field storage definitions for all base fields of the entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]
|
||||
*/
|
||||
protected $fieldStorageDefinitions;
|
||||
|
||||
/**
|
||||
* Constructs an EntityViewsData object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type to provide views integration for.
|
||||
* @param \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $storage_controller
|
||||
* The storage controller used for this entity type.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager
|
||||
* The translation manager.
|
||||
*/
|
||||
function __construct(EntityTypeInterface $entity_type, SqlEntityStorageInterface $storage_controller, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, TranslationInterface $translation_manager) {
|
||||
$this->entityType = $entity_type;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->storage = $storage_controller;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->setStringTranslation($translation_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('entity.manager')->getStorage($entity_type->id()),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('string_translation'),
|
||||
$container->get('typed_data_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field storage definitions.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
|
||||
*/
|
||||
protected function getFieldStorageDefinitions() {
|
||||
if (!isset($this->fieldStorageDefinitions)) {
|
||||
$this->fieldStorageDefinitions = $this->entityManager->getFieldStorageDefinitions($this->entityType->id());
|
||||
}
|
||||
return $this->fieldStorageDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getViewsData() {
|
||||
$data = [];
|
||||
|
||||
// @todo In theory we should use the data table as base table, as this would
|
||||
// save one pointless join (and one more for every relationship).
|
||||
// @see https://drupal.org/node/2337509
|
||||
$base_table = $this->entityType->getBaseTable();
|
||||
$base_field = $this->entityType->getKey('id');
|
||||
$data_table = $this->entityType->getDataTable();
|
||||
$revision_table = $this->entityType->getRevisionTable();
|
||||
$revision_data_table = $this->entityType->getRevisionDataTable();
|
||||
$revision_field = $this->entityType->getKey('revision');
|
||||
|
||||
// Setup base information of the views data.
|
||||
$data[$base_table]['table']['entity type'] = $this->entityType->id();
|
||||
$data[$base_table]['table']['group'] = $this->entityType->getLabel();
|
||||
$data[$base_table]['table']['base'] = [
|
||||
'field' => $base_field,
|
||||
'title' => $this->entityType->getLabel(),
|
||||
];
|
||||
|
||||
if ($label_key = $this->entityType->getKey('label')) {
|
||||
if ($data_table) {
|
||||
$data[$base_table]['table']['base']['defaults'] = array(
|
||||
'field' => $label_key,
|
||||
'table' => $data_table,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$data[$base_table]['table']['base']['defaults'] = array(
|
||||
'field' => $label_key,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup relations to the revisions/property data.
|
||||
if ($data_table) {
|
||||
$data[$data_table]['table']['join'][$base_table] = [
|
||||
'left_field' => $base_field,
|
||||
'field' => $base_field,
|
||||
'type' => 'INNER'
|
||||
];
|
||||
$data[$data_table]['table']['entity type'] = $this->entityType->id();
|
||||
$data[$data_table]['table']['group'] = $this->entityType->getLabel();
|
||||
}
|
||||
if ($revision_table) {
|
||||
$data[$revision_table]['table']['entity type'] = $this->entityType->id();
|
||||
$data[$revision_table]['table']['group'] = $this->t('@entity_type revision', ['@entity_type' => $this->entityType->getLabel()]);
|
||||
$data[$revision_table]['table']['base'] = array(
|
||||
'field' => $revision_field,
|
||||
'title' => $this->t('@entity_type revisions', array('@entity_type' => $this->entityType->getLabel())),
|
||||
);
|
||||
// Join the revision table to the base table.
|
||||
$data[$revision_table]['table']['join'][$base_table] = array(
|
||||
'left_field' => $revision_field,
|
||||
'field' => $revision_field,
|
||||
'type' => 'INNER',
|
||||
);
|
||||
|
||||
if ($revision_data_table) {
|
||||
$data[$revision_data_table]['table']['entity type'] = $this->entityType->id();
|
||||
$data[$revision_data_table]['table']['group'] = $this->t('@entity_type revision', ['@entity_type' => $this->entityType->getLabel()]);
|
||||
|
||||
$data[$revision_data_table]['table']['join'][$revision_table] = array(
|
||||
'left_field' => $revision_field,
|
||||
'field' => $revision_field,
|
||||
'type' => 'INNER',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Load all typed data definitions of all fields. This should cover each of
|
||||
// the entity base, revision, data tables.
|
||||
$field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id());
|
||||
if ($table_mapping = $this->storage->getTableMapping()) {
|
||||
// Iterate over each table we have so far and collect field data for each.
|
||||
// Based on whether the field is in the field_definitions provided by the
|
||||
// entity manager.
|
||||
// @todo We should better just rely on information coming from the entity
|
||||
// storage.
|
||||
// @todo https://drupal.org/node/2337511
|
||||
foreach ($table_mapping->getTableNames() as $table) {
|
||||
foreach ($table_mapping->getFieldNames($table) as $field_name) {
|
||||
$this->mapFieldDefinition($table, $field_name, $field_definitions[$field_name], $table_mapping, $data[$table]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the views data for a single field onto the views data.
|
||||
*
|
||||
* @param string $table
|
||||
* The table of the field to handle.
|
||||
* @param string $field_name
|
||||
* The name of the field to handle.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition defined in Entity::baseFieldDefinitions()
|
||||
* @param \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping
|
||||
* The table mapping information
|
||||
* @param array $table_data
|
||||
* A reference to a specific entity table (for example data_table) inside
|
||||
* the views data.
|
||||
*/
|
||||
protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterface $field_definition, TableMappingInterface $table_mapping, &$table_data) {
|
||||
// Create a dummy instance to retrieve property definitions.
|
||||
$field_column_mapping = $table_mapping->getColumnNames($field_name);
|
||||
$field_schema = $this->getFieldStorageDefinitions()[$field_name]->getSchema();
|
||||
|
||||
$field_definition_type = $field_definition->getType();
|
||||
// Add all properties to views table data.
|
||||
$first = TRUE;
|
||||
foreach ($field_column_mapping as $field_column_name => $schema_field_name) {
|
||||
$schema = $field_schema['columns'][$field_column_name];
|
||||
// We want to both have an entry in the views data for the actual field,
|
||||
// but also each additional schema field, for example the file
|
||||
// description.
|
||||
// @todo Introduce a concept of the "main" schema field for a field item.
|
||||
// This would be the FID for a file reference for example.
|
||||
// @see https://www.drupal.org/node/2337517
|
||||
if ($first) {
|
||||
$first = FALSE;
|
||||
$table_data[$field_name] = $this->mapSingleFieldViewsData($table, $field_definition_type, $schema_field_name, $field_definition, TRUE);
|
||||
}
|
||||
else {
|
||||
$table_data["$field_name.$field_column_name"] = $this->mapSingleFieldViewsData($table, $schema['type'], $schema_field_name, $field_definition, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the views data for a given data type and schema field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table of the field to handle.
|
||||
* @param string $data_type
|
||||
* The data type to generate views data for, for example "int". The data
|
||||
* type comes directly from the schema definition of each field item.
|
||||
* @param string $schema_field_name
|
||||
* The schema field name.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param bool $first
|
||||
* Is it the first column of the schema.
|
||||
*
|
||||
* @return array
|
||||
* The modified views data field definition.
|
||||
*/
|
||||
protected function mapSingleFieldViewsData($table, $data_type, $schema_field_name, FieldDefinitionInterface $field_definition, $first) {
|
||||
$views_field = array();
|
||||
|
||||
// Provide a nicer, less verbose label for the first field.
|
||||
if ($first) {
|
||||
$views_field['title'] = $field_definition->getLabel();
|
||||
}
|
||||
else {
|
||||
$views_field['title'] = $field_definition->getLabel() . " ($schema_field_name)";
|
||||
}
|
||||
|
||||
if ($description = $field_definition->getDescription()) {
|
||||
$views_field['help'] = $description;
|
||||
}
|
||||
|
||||
// @todo Allow field types to customize this.
|
||||
// @see https://www.drupal.org/node/2337515
|
||||
switch ($data_type) {
|
||||
case 'int':
|
||||
case 'integer':
|
||||
case 'smallint':
|
||||
case 'tinyint':
|
||||
case 'mediumint':
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'decimal':
|
||||
$views_field['field']['id'] = 'numeric';
|
||||
$views_field['argument']['id'] = 'numeric';
|
||||
$views_field['filter']['id'] = 'numeric';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
case 'char':
|
||||
case 'string':
|
||||
case 'varchar':
|
||||
case 'tinytext':
|
||||
case 'text':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
$views_field['field']['id'] = 'standard';
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
case 'boolean':
|
||||
$views_field['field']['id'] = 'boolean';
|
||||
$views_field['argument']['id'] = 'numeric';
|
||||
$views_field['filter']['id'] = 'boolean';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
case 'uuid':
|
||||
$views_field['field']['id'] = 'standard';
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
case 'language':
|
||||
$views_field['field']['id'] = 'language';
|
||||
$views_field['argument']['id'] = 'language';
|
||||
$views_field['filter']['id'] = 'language';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
case 'created':
|
||||
case 'changed':
|
||||
$views_field['field']['id'] = 'date';
|
||||
$views_field['argument']['id'] = 'date';
|
||||
$views_field['filter']['id'] = 'date';
|
||||
$views_field['sort']['id'] = 'date';
|
||||
break;
|
||||
case 'entity_reference':
|
||||
// @todo Should the actual field handler respect that this is just renders a number
|
||||
// @todo Create an optional entity field handler, that can render the
|
||||
// entity.
|
||||
// @see https://www.drupal.org/node/2322949
|
||||
$views_field['field']['id'] = 'standard';
|
||||
$views_field['argument']['id'] = 'standard';
|
||||
$views_field['filter']['id'] = 'standard';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
case 'uri':
|
||||
$views_field['field']['id'] = 'standard';
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
break;
|
||||
default:
|
||||
$views_field['field']['id'] = 'standard';
|
||||
$views_field['argument']['id'] = 'standard';
|
||||
$views_field['filter']['id'] = 'standard';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
}
|
||||
|
||||
$process_method = 'processViewsDataFor' . Container::camelize($data_type);
|
||||
if (method_exists($this, $process_method)) {
|
||||
$this->{$process_method}($table, $field_definition, $views_field);
|
||||
}
|
||||
|
||||
return $views_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the views data for a language field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table the language field is added to.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $views_field
|
||||
* The views field data.
|
||||
*/
|
||||
protected function processViewsDataForLanguage($table, FieldDefinitionInterface $field_definition, array &$views_field) {
|
||||
// Apply special titles for the langcode field.
|
||||
if ($field_definition->getName() == 'langcode') {
|
||||
if ($table == $this->entityType->getDataTable() || $table == $this->entityType->getBaseTable()) {
|
||||
$views_field['title'] = $this->t('Translation language');
|
||||
}
|
||||
if ($table == $this->entityType->getRevisionDataTable() || $table == $this->entityType->getRevisionTable()) {
|
||||
$views_field['title'] = $this->t('Original language');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the views data for an entity reference field.
|
||||
*
|
||||
* @param string $table
|
||||
* The table the language field is added to.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The field definition.
|
||||
* @param array $views_field
|
||||
* The views field data.
|
||||
*/
|
||||
protected function processViewsDataForEntityReference($table, FieldDefinitionInterface $field_definition, array &$views_field) {
|
||||
if ($entity_type_id = $field_definition->getItemDefinition()->getSetting('target_type')) {
|
||||
$entity_type = $this->entityManager->getDefinition($entity_type_id);
|
||||
if ($entity_type instanceof ContentEntityType) {
|
||||
$views_field['relationship'] = [
|
||||
'base' => $this->getViewsTableForEntityType($entity_type),
|
||||
'base field' => $entity_type->getKey('id'),
|
||||
'label' => $entity_type->getLabel(),
|
||||
'title' => $entity_type->getLabel(),
|
||||
'id' => 'standard',
|
||||
];
|
||||
$views_field['field']['id'] = 'numeric';
|
||||
$views_field['argument']['id'] = 'numeric';
|
||||
$views_field['filter']['id'] = 'numeric';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
}
|
||||
else {
|
||||
$views_field['field']['id'] = 'standard';
|
||||
$views_field['argument']['id'] = 'string';
|
||||
$views_field['filter']['id'] = 'string';
|
||||
$views_field['sort']['id'] = 'standard';
|
||||
}
|
||||
}
|
||||
|
||||
if ($field_definition->getName() == $this->entityType->getKey('bundle')) {
|
||||
// @todo Use the other bundle handlers, once
|
||||
// https://www.drupal.org/node/2322949 is in.
|
||||
$views_field['filter']['id'] = 'bundle';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table of an entity type to be used as base table in views.
|
||||
*
|
||||
* @todo Given that the base_table is pretty much useless as you often have to
|
||||
* join to the data table anyway, it could make a lot of sense to start with
|
||||
* the data table right from the beginning.
|
||||
* @see https://drupal.org/node/2337509
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return string
|
||||
* The name of the base table in views.
|
||||
*/
|
||||
protected function getViewsTableForEntityType(EntityTypeInterface $entity_type) {
|
||||
return $entity_type->getBaseTable();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,659 @@
|
|||
<?php
|
||||
use Drupal\Core\Entity\EntityType;
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views\Tests\EntityViewsDataTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\views\Tests {
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityType;
|
||||
use Drupal\Core\Entity\ContentEntityType;
|
||||
use Drupal\Core\Entity\EntityType;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\LanguageItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\UuidItem;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\entity_test\Entity\EntityTestMul;
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\views\EntityViewsData;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\views\EntityViewsData
|
||||
* @group Views
|
||||
*/
|
||||
class EntityViewsDataTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Entity info to use in this test.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $baseEntityType;
|
||||
|
||||
/**
|
||||
* The mocked entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $entityStorage;
|
||||
|
||||
/**
|
||||
* The mocked entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The mocked module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The mocked translation manager.
|
||||
*
|
||||
* @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $translationManager;
|
||||
|
||||
/**
|
||||
* The tested entity views controller.
|
||||
*
|
||||
* @var \Drupal\views\Tests\TestEntityViewsData
|
||||
*/
|
||||
protected $viewsData;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->entityStorage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
|
||||
$this->baseEntityType = new TestEntityType([
|
||||
'base_table' => 'entity_test',
|
||||
'id' => 'entity_test',
|
||||
'label' => 'Entity test',
|
||||
'entity_keys' => ['id' => 'id'],
|
||||
]);
|
||||
|
||||
$this->translationManager = $this->getStringTranslationStub();
|
||||
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||
|
||||
$this->viewsData = new TestEntityViewsData($this->baseEntityType, $this->entityStorage, $this->entityManager, $this->moduleHandler, $this->translationManager);
|
||||
|
||||
$field_type_manager = $this->getMockBuilder('Drupal\Core\Field\FieldTypePluginManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$field_type_manager->expects($this->any())
|
||||
->method('getDefaultSettings')
|
||||
->willReturn([]);
|
||||
$field_type_manager->expects($this->any())
|
||||
->method('getDefaultInstanceSettings')
|
||||
->willReturn([]);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('plugin.manager.field.field_type', $field_type_manager);
|
||||
$container->set('entity.manager', $this->entityManager);
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to setup base fields.
|
||||
*
|
||||
* @param \Drupal\Core\Field\BaseFieldDefinition[] $base_fields
|
||||
* The base fields which are adapted.
|
||||
*
|
||||
* @return \Drupal\Core\Field\BaseFieldDefinition[]
|
||||
* The setup base fields.
|
||||
*/
|
||||
protected function setupBaseFields(array $base_fields) {
|
||||
foreach ($base_fields as $name => $base_field) {
|
||||
$base_field->setName($name);
|
||||
}
|
||||
return $base_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests base tables.
|
||||
*/
|
||||
public function testBaseTables() {
|
||||
$data = $this->viewsData->getViewsData();
|
||||
|
||||
$this->assertEquals('entity_test', $data['entity_test']['table']['entity type']);
|
||||
$this->assertEquals('Entity test', $data['entity_test']['table']['group']);
|
||||
|
||||
$this->assertEquals('id', $data['entity_test']['table']['base']['field']);
|
||||
$this->assertEquals('Entity test', $data['entity_test']['table']['base']['title']);
|
||||
|
||||
$this->assertFalse(isset($data['entity_test']['table']['defaults']));
|
||||
|
||||
$this->assertFalse(isset($data['entity_test_mul_property_data']));
|
||||
$this->assertFalse(isset($data['revision_table']));
|
||||
$this->assertFalse(isset($data['revision_data_table']));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests data_table support.
|
||||
*/
|
||||
public function testDataTable() {
|
||||
$entity_type = $this->baseEntityType->set('data_table', 'entity_test_mul_property_data')
|
||||
->set('id', 'entity_test_mul')
|
||||
->setKey('label', 'label');
|
||||
|
||||
$this->viewsData->setEntityType($entity_type);
|
||||
|
||||
// Tests the join definition between the base and the data table.
|
||||
$data = $this->viewsData->getViewsData();
|
||||
$field_views_data = $data['entity_test_mul_property_data'];
|
||||
|
||||
$this->assertEquals('entity_test_mul', $data['entity_test_mul_property_data']['table']['entity type']);
|
||||
$this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['group']);
|
||||
$this->assertEquals(['field' => 'label', 'table' => 'entity_test_mul_property_data'], $data['entity_test']['table']['base']['defaults']);
|
||||
|
||||
// Ensure the join information is set up properly.
|
||||
$this->assertCount(1, $field_views_data['table']['join']);
|
||||
$this->assertEquals(['entity_test' => ['left_field' => 'id', 'field' => 'id', 'type' => 'INNER']], $field_views_data['table']['join']);
|
||||
$this->assertFalse(isset($data['revision_table']));
|
||||
$this->assertFalse(isset($data['revision_data_table']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests revision table support.
|
||||
*/
|
||||
public function testRevisionTable() {
|
||||
$entity_type = $this->baseEntityType
|
||||
->set('revision_table', 'entity_test_mulrev_revision')
|
||||
->set('revision_data_table', 'entity_test_mulrev_property_revision')
|
||||
->set('id', 'entity_test_mulrev')
|
||||
->setKey('revision', 'revision_id')
|
||||
;
|
||||
$this->viewsData->setEntityType($entity_type);
|
||||
|
||||
$data = $this->viewsData->getViewsData();
|
||||
|
||||
$this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
|
||||
$this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
|
||||
$this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
|
||||
|
||||
// Ensure the join information is set up properly.
|
||||
// Tests the join definition between the base and the revision table.
|
||||
$revision_data = $data['entity_test_mulrev_revision'];
|
||||
$this->assertCount(1, $revision_data['table']['join']);
|
||||
$this->assertEquals(['entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']);
|
||||
$revision_data = $data['entity_test_mulrev_property_revision'];
|
||||
$this->assertCount(1, $revision_data['table']['join']);
|
||||
$this->assertEquals(['entity_test_mulrev_revision' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']);
|
||||
$this->assertFalse(isset($data['data_table']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to mock all store definitions.
|
||||
*/
|
||||
protected function setupFieldStorageDefinition() {
|
||||
$id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$id_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(IntegerItem::schema($id_field_storage_definition));
|
||||
$uuid_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$uuid_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(UuidItem::schema($uuid_field_storage_definition));
|
||||
$type_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$type_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(StringItem::schema($type_field_storage_definition));
|
||||
$langcode_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$langcode_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(LanguageItem::schema($langcode_field_storage_definition));
|
||||
$name_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$name_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(StringItem::schema($name_field_storage_definition));
|
||||
|
||||
// Setup the user_id entity reference field.
|
||||
$this->entityManager->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->willReturnMap([
|
||||
['user', TRUE, static::userEntityInfo()],
|
||||
]
|
||||
);
|
||||
$user_id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$user_id_field_storage_definition->expects($this->any())
|
||||
->method('getSetting')
|
||||
->with('target_type')
|
||||
->willReturn('user');
|
||||
$user_id_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(EntityReferenceItem::schema($user_id_field_storage_definition));
|
||||
|
||||
$revision_id_field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$revision_id_field_storage_definition->expects($this->any())
|
||||
->method('getSchema')
|
||||
->willReturn(IntegerItem::schema($revision_id_field_storage_definition));
|
||||
|
||||
$this->entityManager->expects($this->any())
|
||||
->method('getFieldStorageDefinitions')
|
||||
->willReturn([
|
||||
'id' => $id_field_storage_definition,
|
||||
'uuid' => $uuid_field_storage_definition,
|
||||
'type' => $type_field_storage_definition,
|
||||
'langcode' => $langcode_field_storage_definition,
|
||||
'name' => $name_field_storage_definition,
|
||||
'user_id' => $user_id_field_storage_definition,
|
||||
'revision_id' => $revision_id_field_storage_definition,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests fields on the base table.
|
||||
*/
|
||||
public function testBaseTableFields() {
|
||||
$base_field_definitions = $this->setupBaseFields(EntityTest::baseFieldDefinitions($this->baseEntityType));
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('getBaseFieldDefinitions')
|
||||
->with('entity_test')
|
||||
->willReturn($base_field_definitions);
|
||||
|
||||
// Setup the table mapping.
|
||||
$table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getTableNames')
|
||||
->willReturn(['entity_test']);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getColumnNames')
|
||||
->willReturnMap([
|
||||
['id', ['value' => 'id']],
|
||||
['uuid', ['value' => 'uuid']],
|
||||
['type', ['value' => 'type']],
|
||||
['langcode', ['value' => 'langcode']],
|
||||
['name', ['value' => 'name']],
|
||||
['user_id', ['target_id' => 'user_id']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldNames')
|
||||
->willReturnMap([
|
||||
['entity_test', ['id', 'uuid', 'type', 'langcode', 'name', 'user_id']]
|
||||
]);
|
||||
|
||||
$this->entityStorage->expects($this->once())
|
||||
->method('getTableMapping')
|
||||
->willReturn($table_mapping);
|
||||
|
||||
$this->setupFieldStorageDefinition();
|
||||
|
||||
$this->viewsData->setSchemaFields(['entity_test' => ['id', 'uuid', 'type', 'langcode', 'name', 'user_id']]);
|
||||
$data = $this->viewsData->getViewsData();
|
||||
|
||||
$this->assertNumericField($data['entity_test']['id']);
|
||||
$this->assertUuidField($data['entity_test']['uuid']);
|
||||
$this->assertStringField($data['entity_test']['type']);
|
||||
|
||||
$this->assertLanguageField($data['entity_test']['langcode']);
|
||||
$this->assertEquals('Translation language', $data['entity_test']['langcode']['title']);
|
||||
|
||||
$this->assertStringField($data['entity_test']['name']);
|
||||
|
||||
$this->assertEntityReferenceField($data['entity_test']['user_id']);
|
||||
$relationship = $data['entity_test']['user_id']['relationship'];
|
||||
$this->assertEquals('users', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests fields on the data table.
|
||||
*/
|
||||
public function testDataTableFields() {
|
||||
$entity_type = $this->baseEntityType
|
||||
->set('data_table', 'entity_test_mul_property_data')
|
||||
->set('base_table', 'entity_test_mul')
|
||||
->set('id', 'entity_test_mul')
|
||||
->setKey('bundle', 'type')
|
||||
;
|
||||
$base_field_definitions = $this->setupBaseFields(EntityTestMul::baseFieldDefinitions($this->baseEntityType));
|
||||
$base_field_definitions['type'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel('entity test type')
|
||||
->setSettings(array('target_type' => 'entity_test_bundle'))
|
||||
->setTranslatable(TRUE);
|
||||
$base_field_definitions = $this->setupBaseFields($base_field_definitions);
|
||||
$entity_test_type = new ConfigEntityType(['id' => 'entity_test_bundle']);
|
||||
$user_entity_type = new ContentEntityType(['id' => 'user', 'base_table' => 'users', 'entity_keys' => ['id' => 'uid']]);
|
||||
$this->entityManager->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->willReturnMap([
|
||||
['entity_test_bundle', TRUE, $entity_test_type],
|
||||
['user', TRUE, $user_entity_type],
|
||||
]);
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('getBaseFieldDefinitions')
|
||||
->with('entity_test_mul')
|
||||
->willReturn($base_field_definitions);
|
||||
|
||||
$this->viewsData->setSchemaFields([
|
||||
'entity_test_mul' => ['id', 'uuid', 'type', 'langcode'],
|
||||
'entity_test_mul_property_data' => ['id', 'langcode', 'name', 'user_id'],
|
||||
]);
|
||||
|
||||
;
|
||||
$this->viewsData->setEntityType($entity_type);
|
||||
|
||||
// Setup the table mapping.
|
||||
$table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getTableNames')
|
||||
->willReturn(['entity_test_mul', 'entity_test_mul_property_data']);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getColumnNames')
|
||||
->willReturnMap([
|
||||
['id', ['value' => 'id']],
|
||||
['uuid', ['value' => 'uuid']],
|
||||
['type', ['value' => 'type']],
|
||||
['langcode', ['value' => 'langcode']],
|
||||
['name', ['value' => 'name']],
|
||||
['user_id', ['target_id' => 'user_id']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldNames')
|
||||
->willReturnMap([
|
||||
['entity_test_mul', ['id', 'uuid', 'type', 'langcode']],
|
||||
['entity_test_mul_property_data', ['id', 'langcode', 'name', 'user_id']],
|
||||
]);
|
||||
|
||||
$this->entityStorage->expects($this->once())
|
||||
->method('getTableMapping')
|
||||
->willReturn($table_mapping);
|
||||
|
||||
$this->setupFieldStorageDefinition();
|
||||
|
||||
$data = $this->viewsData->getViewsData();
|
||||
|
||||
// Check the base fields.
|
||||
$this->assertNumericField($data['entity_test_mul']['id']);
|
||||
$this->assertUuidField($data['entity_test_mul']['uuid']);
|
||||
|
||||
$this->assertBundleField($data['entity_test_mul']['type']);
|
||||
$this->assertFalse(isset($data['entity_test_mul']['type']['relationship']));
|
||||
|
||||
$this->assertLanguageField($data['entity_test_mul']['langcode']);
|
||||
// Also ensure that field_data only fields don't appear on the base table.
|
||||
$this->assertFalse(isset($data['entity_test_mul']['name']));
|
||||
$this->assertFalse(isset($data['entity_test_mul']['user_id']));
|
||||
|
||||
// Check the data fields.
|
||||
$this->assertNumericField($data['entity_test_mul_property_data']['id']);
|
||||
|
||||
$this->assertLanguageField($data['entity_test_mul_property_data']['langcode']);
|
||||
$this->assertEquals('Translation language', $data['entity_test_mul_property_data']['langcode']['title']);
|
||||
|
||||
$this->assertStringField($data['entity_test_mul_property_data']['name']);
|
||||
|
||||
$this->assertEntityReferenceField($data['entity_test_mul_property_data']['user_id']);
|
||||
$relationship = $data['entity_test_mul_property_data']['user_id']['relationship'];
|
||||
$this->assertEquals('users', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests fields on the revision table.
|
||||
*/
|
||||
public function testRevisionTableFields() {
|
||||
$entity_type = $this->baseEntityType
|
||||
->set('base_table', 'entity_test_mulrev')
|
||||
->set('revision_table', 'entity_test_mulrev_revision')
|
||||
->set('data_table', 'entity_test_mulrev_property_data')
|
||||
->set('revision_data_table', 'entity_test_mulrev_property_revision')
|
||||
->set('id', 'entity_test_mulrev');
|
||||
$base_field_definitions = $this->setupBaseFields(EntityTestMulRev::baseFieldDefinitions($this->baseEntityType));
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('getBaseFieldDefinitions')
|
||||
->with('entity_test_mulrev')
|
||||
->willReturn($base_field_definitions);
|
||||
|
||||
$this->viewsData->setSchemaFields([
|
||||
'entity_test_mulrev' => ['id', 'revision_id', 'uuid', 'type'],
|
||||
'entity_test_mulrev_revision' => ['id', 'revision_id', 'langcode'],
|
||||
'entity_test_mulrev_property_data' => ['id', 'revision_id', 'langcode', 'name', 'user_id'],
|
||||
'entity_test_mulrev_property_revision' => ['id', 'revision_id', 'langcode', 'name', 'user_id'],
|
||||
]);
|
||||
|
||||
;
|
||||
$this->viewsData->setEntityType($entity_type);
|
||||
|
||||
// Setup the table mapping.
|
||||
$table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getTableNames')
|
||||
->willReturn(['entity_test_mulrev', 'entity_test_mulrev_revision', 'entity_test_mulrev_property_data', 'entity_test_mulrev_property_revision']);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getColumnNames')
|
||||
->willReturnMap([
|
||||
['id', ['value' => 'id']],
|
||||
['uuid', ['value' => 'uuid']],
|
||||
['type', ['value' => 'type']],
|
||||
['langcode', ['value' => 'langcode']],
|
||||
['name', ['value' => 'name']],
|
||||
['user_id', ['target_id' => 'user_id']],
|
||||
['revision_id', ['value' => 'id']],
|
||||
]);
|
||||
$table_mapping->expects($this->any())
|
||||
->method('getFieldNames')
|
||||
->willReturnMap([
|
||||
['entity_test_mulrev', ['id', 'revision_id', 'uuid', 'type']],
|
||||
['entity_test_mulrev_revision', ['id', 'revision_id', 'langcode']],
|
||||
['entity_test_mulrev_property_data', ['id', 'revision_id', 'langcode', 'name', 'user_id']],
|
||||
['entity_test_mulrev_property_revision', ['id', 'revision_id', 'langcode', 'name', 'user_id']],
|
||||
]);
|
||||
|
||||
$this->entityStorage->expects($this->once())
|
||||
->method('getTableMapping')
|
||||
->willReturn($table_mapping);
|
||||
|
||||
$this->setupFieldStorageDefinition();
|
||||
|
||||
$data = $this->viewsData->getViewsData();
|
||||
|
||||
// Check the base fields.
|
||||
$this->assertNumericField($data['entity_test_mulrev']['id']);
|
||||
$this->assertNumericField($data['entity_test_mulrev']['revision_id']);
|
||||
$this->assertUuidField($data['entity_test_mulrev']['uuid']);
|
||||
$this->assertStringField($data['entity_test_mulrev']['type']);
|
||||
|
||||
// Also ensure that field_data only fields don't appear on the base table.
|
||||
$this->assertFalse(isset($data['entity_test_mulrev']['name']));
|
||||
$this->assertFalse(isset($data['entity_test_mulrev']['langcode']));
|
||||
$this->assertFalse(isset($data['entity_test_mulrev']['user_id']));
|
||||
|
||||
// Check the revision fields.
|
||||
$this->assertNumericField($data['entity_test_mulrev_revision']['id']);
|
||||
$this->assertNumericField($data['entity_test_mulrev_revision']['revision_id']);
|
||||
|
||||
$this->assertLanguageField($data['entity_test_mulrev_revision']['langcode']);
|
||||
$this->assertEquals('Original language', $data['entity_test_mulrev_revision']['langcode']['title']);
|
||||
|
||||
// Also ensure that field_data only fields don't appear on the revision table.
|
||||
$this->assertFalse(isset($data['entity_test_mulrev_revision']['name']));
|
||||
$this->assertFalse(isset($data['entity_test_mulrev_revision']['user_id']));
|
||||
|
||||
// Check the data fields.
|
||||
$this->assertNumericField($data['entity_test_mulrev_property_data']['id']);
|
||||
$this->assertLanguageField($data['entity_test_mulrev_property_data']['langcode']);
|
||||
$this->assertStringField($data['entity_test_mulrev_property_data']['name']);
|
||||
|
||||
$this->assertEntityReferenceField($data['entity_test_mulrev_property_data']['user_id']);
|
||||
$relationship = $data['entity_test_mulrev_property_data']['user_id']['relationship'];
|
||||
$this->assertEquals('users', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
|
||||
// Check the property data fields.
|
||||
$this->assertNumericField($data['entity_test_mulrev_property_revision']['id']);
|
||||
|
||||
$this->assertLanguageField($data['entity_test_mulrev_property_revision']['langcode']);
|
||||
$this->assertEquals('Original language', $data['entity_test_mulrev_property_revision']['langcode']['title']);
|
||||
|
||||
$this->assertStringField($data['entity_test_mulrev_property_revision']['name']);
|
||||
|
||||
$this->assertEntityReferenceField($data['entity_test_mulrev_property_revision']['user_id']);
|
||||
$relationship = $data['entity_test_mulrev_property_revision']['user_id']['relationship'];
|
||||
$this->assertEquals('users', $relationship['base']);
|
||||
$this->assertEquals('uid', $relationship['base field']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests views data for a string field.
|
||||
*
|
||||
* @param $data
|
||||
* The views data to check.
|
||||
*/
|
||||
protected function assertStringField($data) {
|
||||
$this->assertEquals('standard', $data['field']['id']);
|
||||
$this->assertEquals('string', $data['filter']['id']);
|
||||
$this->assertEquals('string', $data['argument']['id']);
|
||||
$this->assertEquals('standard', $data['sort']['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests views data for a UUID field.
|
||||
*
|
||||
* @param array $data
|
||||
* The views data to check.
|
||||
*/
|
||||
protected function assertUuidField($data) {
|
||||
// @todo Can we provide additional support for UUIDs in views?
|
||||
$this->assertEquals('standard', $data['field']['id']);
|
||||
$this->assertEquals('string', $data['filter']['id']);
|
||||
$this->assertEquals('string', $data['argument']['id']);
|
||||
$this->assertEquals('standard', $data['sort']['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests views data for a numeric field.
|
||||
*
|
||||
* @param array $data
|
||||
* The views data to check.
|
||||
*/
|
||||
protected function assertNumericField($data) {
|
||||
$this->assertEquals('numeric', $data['field']['id']);
|
||||
$this->assertEquals('numeric', $data['filter']['id']);
|
||||
$this->assertEquals('numeric', $data['argument']['id']);
|
||||
$this->assertEquals('standard', $data['sort']['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests views data for a language field.
|
||||
*
|
||||
* @param array $data
|
||||
* The views data to check.
|
||||
*/
|
||||
protected function assertLanguageField($data) {
|
||||
$this->assertEquals('language', $data['field']['id']);
|
||||
$this->assertEquals('language', $data['filter']['id']);
|
||||
$this->assertEquals('language', $data['argument']['id']);
|
||||
$this->assertEquals('standard', $data['sort']['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests views data for a entity reference field.
|
||||
*/
|
||||
protected function assertEntityReferenceField($data) {
|
||||
$this->assertEquals('numeric', $data['field']['id']);
|
||||
$this->assertEquals('numeric', $data['filter']['id']);
|
||||
$this->assertEquals('numeric', $data['argument']['id']);
|
||||
$this->assertEquals('standard', $data['sort']['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests views data for a bundle field.
|
||||
*/
|
||||
protected function assertBundleField($data) {
|
||||
$this->assertEquals('standard', $data['field']['id']);
|
||||
$this->assertEquals('bundle', $data['filter']['id']);
|
||||
$this->assertEquals('string', $data['argument']['id']);
|
||||
$this->assertEquals('standard', $data['sort']['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns entity info for the user entity.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function userEntityInfo() {
|
||||
return new ContentEntityType([
|
||||
'id' => 'user',
|
||||
'class' => 'Drupal\user\Entity\User',
|
||||
'label' => 'User',
|
||||
'base_table' => 'users',
|
||||
'entity_keys' => [
|
||||
'id' => 'uid',
|
||||
'uuid' => 'uuid',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestEntityViewsData extends EntityViewsData {
|
||||
|
||||
protected $schemaFields = [];
|
||||
|
||||
public function setSchemaFields($fields) {
|
||||
$this->schemaFields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function drupalSchemaFieldsSql($table) {
|
||||
return isset($this->schemaFields[$table]) ? $this->schemaFields[$table] : [];
|
||||
}
|
||||
|
||||
public function setEntityType(EntityTypeInterface $entity_type) {
|
||||
$this->entityType = $entity_type;
|
||||
}
|
||||
}
|
||||
|
||||
class TestEntityType extends EntityType {
|
||||
|
||||
/**
|
||||
* Sets a specific entity key.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the entity key.
|
||||
* @param string $value
|
||||
* The new value of the key.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setKey($key, $value) {
|
||||
$this->entity_keys[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
use Drupal\Component\Utility\String;
|
||||
|
||||
if (!function_exists('t')) {
|
||||
function t($string, array $args = []) {
|
||||
return String::format($string, $args);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,9 +26,10 @@ use Drupal\Core\Language\LanguageInterface;
|
|||
* by implementing hook_views_data_alter(). To provide views data for an
|
||||
* entity, create a class implementing
|
||||
* \Drupal\views\EntityViewsDataInterface and reference this in the
|
||||
* "views_data" annotation in the entity class. See the
|
||||
* @link entity_api Entity API topic @endlink for more information about
|
||||
* entities.
|
||||
* "views_data" annotation in the entity class. You can autogenerate big parts
|
||||
* of the ingration if you extend the \Drupal\views\EntityViewsData base
|
||||
* class. See the @link entity_api Entity API topic @endlink for more
|
||||
* information about entities.
|
||||
* - Implement hooks: A few operations in Views can be influenced by hooks.
|
||||
* See the @link Views hooks topic @endlink for a list.
|
||||
* - Theming: See the @link views_templates Views templates topic @endlink
|
||||
|
|
Loading…
Reference in New Issue