diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php new file mode 100644 index 0000000000000000000000000000000000000000..c97430117e22f33f6929098ba94c6cf03c8f481c --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php @@ -0,0 +1,91 @@ +setLabel('Computed Field Test') + ->setComputed(TRUE) + ->setClass(ComputedTestFieldItemList::class); + + $fields['computed_reference_field'] = BaseFieldDefinition::create('entity_reference') + ->setLabel('Computed Reference Field Test') + ->setComputed(TRUE) + ->setSetting('target_type', 'entity_test') + ->setClass(ComputedReferenceTestFieldItemList::class); + + $fields['computed_test_cacheable_string_field'] = BaseFieldDefinition::create('computed_test_cacheable_string_item') + ->setLabel(new TranslatableMarkup('Computed Cacheable String Field Test')) + ->setComputed(TRUE) + ->setClass(ComputedTestCacheableStringItemList::class) + ->setReadOnly(FALSE) + ->setInternal(FALSE); + + return $fields; + } + + /** + * {@inheritdoc} + */ + public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) { + $fields = parent::bundleFieldDefinitions($entity_type, $bundle, $base_field_definitions); + + $computed_field_bundles = [ + 'entity_test_comp_bund_fld_bund', + 'entity_test_comp_bund_fld_bund_2', + ]; + + if (in_array($bundle, $computed_field_bundles, TRUE)) { + // @todo Use the proper FieldStorageDefinition class instead + // https://www.drupal.org/node/2280639. + $storageDefinition = FieldStorageDefinition::create('string') + ->setName('computed_bundle_field') + ->setTargetEntityTypeId($entity_type->id()) + ->setComputed(TRUE) + ->setClass(ComputedTestBundleFieldItemList::class); + $fields['computed_bundle_field'] = FieldDefinition::createFromFieldStorageDefinition($storageDefinition) + ->setLabel(t('A computed Bundle Field Test')) + ->setComputed(TRUE) + ->setClass(ComputedTestBundleFieldItemList::class); + } + + return $fields; + } + +} diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestViewsData.php b/core/modules/system/tests/modules/entity_test/src/EntityTestViewsData.php index 27a1186ada6f4f1da6b05a7550e337909b4e6bcd..54a234e34b1799a2939e492be2b5b8f45a290d50 100644 --- a/core/modules/system/tests/modules/entity_test/src/EntityTestViewsData.php +++ b/core/modules/system/tests/modules/entity_test/src/EntityTestViewsData.php @@ -26,6 +26,16 @@ public function getViewsData() { ], ]; } + if ($this->entityType->id() === 'entity_test_comp_bund_fld') { + $views_data['entity_test_comp_bund_fld']['computed_bundle_field'] = [ + 'title' => $this->t('Computed Bundle Field'), + 'field' => [ + 'id' => 'field', + 'default_formatter' => 'string', + 'field_name' => 'computed_bundle_field', + ], + ]; + } if ($this->entityType->id() != 'entity_test') { return $views_data; diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/ComputedTestBundleFieldItemList.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/ComputedTestBundleFieldItemList.php new file mode 100644 index 0000000000000000000000000000000000000000..c69e36855888782d818819878ca6e7605dd02dfc --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/ComputedTestBundleFieldItemList.php @@ -0,0 +1,24 @@ +get('entity_test_comp_bund_fld_item_list_value', []) as $delta => $item) { + $this->list[$delta] = $this->createItem($delta, $item); + } + } + +} diff --git a/core/modules/views/src/Plugin/views/field/EntityField.php b/core/modules/views/src/Plugin/views/field/EntityField.php index fccd8ff532bf3f4b3ce41c0ec339e912781ad289..d0664bcd63225ce5064fcd33634c2e0db26606d4 100644 --- a/core/modules/views/src/Plugin/views/field/EntityField.php +++ b/core/modules/views/src/Plugin/views/field/EntityField.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityRepositoryInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; @@ -126,6 +127,13 @@ class EntityField extends FieldPluginBase implements CacheableDependencyInterfac */ protected $entityFieldRenderer; + /** + * The entity type bundle info service. + * + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface + */ + protected $entityTypeBundleInfo; + /** * The fields that we are actually grouping on. */ @@ -154,8 +162,10 @@ class EntityField extends FieldPluginBase implements CacheableDependencyInterfac * The entity repository. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The entity field manager. + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info + * The entity type bundle info service. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, FormatterPluginManager $formatter_plugin_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, LanguageManagerInterface $language_manager, RendererInterface $renderer, EntityRepositoryInterface $entity_repository, EntityFieldManagerInterface $entity_field_manager) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, FormatterPluginManager $formatter_plugin_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, LanguageManagerInterface $language_manager, RendererInterface $renderer, EntityRepositoryInterface $entity_repository, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->entityTypeManager = $entity_type_manager; @@ -166,6 +176,12 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition $this->entityRepository = $entity_repository; $this->entityFieldManager = $entity_field_manager; + if (!$entity_type_bundle_info) { + @trigger_error('Calling EntityField::__construct() without the $entity_type_bundle_info argument is deprecated in drupal:10.0.0 and the $entity_type_bundle_info argument will be required in drupal:11.0.0. See https://www.drupal.org/node/2981047', E_USER_DEPRECATED); + $entity_type_bundle_info = \Drupal::service('entity_type.bundle.info'); + } + $this->entityTypeBundleInfo = $entity_type_bundle_info; + // @todo Unify 'entity field'/'field_name' instead of converting back and // forth. https://www.drupal.org/node/2410779 if (isset($this->definition['entity field'])) { @@ -188,7 +204,8 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('language_manager'), $container->get('renderer'), $container->get('entity.repository'), - $container->get('entity_field.manager') + $container->get('entity_field.manager'), + $container->get('entity_type.bundle.info') ); } @@ -363,6 +380,19 @@ protected function getFieldStorageDefinition() { if (isset($this->definition['field_name']) && isset($base_fields[$this->definition['field_name']])) { return $base_fields[$this->definition['field_name']]->getFieldStorageDefinition(); } + + // If there is still no field storage definition found, we are dealing with + // a bundle field. Get the storage from the field definition on the first + // bundle we find which has this field. + $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id); + foreach ($bundles as $bundle_id => $bundle) { + $bundle_fields = $this->entityFieldManager->getFieldDefinitions($entity_type_id, $bundle_id); + if (isset($this->definition['field_name']) && isset($bundle_fields[$this->definition['field_name']])) { + return $bundle_fields[$this->definition['field_name']]->getFieldStorageDefinition(); + } + } + + return NULL; } /** diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.computed_bundle_field_view.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.computed_bundle_field_view.yml new file mode 100644 index 0000000000000000000000000000000000000000..9e1130df3d52089140d8048a8478d772227eaa5b --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.computed_bundle_field_view.yml @@ -0,0 +1,234 @@ +langcode: en +status: true +dependencies: + module: + - entity_test +id: computed_bundle_field_view +label: 'Computed Bundled Field View' +module: views +description: '' +tag: '' +base_table: entity_test_comp_bund_fld +base_field: id +display: + default: + display_plugin: default + id: default + display_title: Default + position: 0 + display_options: + access: + type: none + options: { } + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + uses_fields: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + fields: + computed_string_field: + id: computed_string_field + table: entity_test_comp_bund_fld + field: computed_string_field + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: entity_test_computed_field + plugin_id: field + computed_bundle_field: + id: computed_bundle_field + table: entity_test_comp_bund_fld + field: computed_bundle_field + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: entity_test_comp_bund_fld + plugin_id: field + filters: { } + sorts: { } + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + tags: { } + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: foo + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + tags: { } diff --git a/core/modules/views/tests/src/Kernel/Handler/ComputedBundleFieldTest.php b/core/modules/views/tests/src/Kernel/Handler/ComputedBundleFieldTest.php new file mode 100644 index 0000000000000000000000000000000000000000..cb1fd31d008e5000459eed90d779170737ddc0c0 --- /dev/null +++ b/core/modules/views/tests/src/Kernel/Handler/ComputedBundleFieldTest.php @@ -0,0 +1,94 @@ +installEntitySchema('entity_test_comp_bund_fld'); + + // Create a default bundle that has a computed field. + entity_test_create_bundle('entity_test_comp_bund_fld_bund', NULL, 'entity_test_comp_bund_fld'); + + // Create a second bundle that also has a computed field. + entity_test_create_bundle('entity_test_comp_bund_fld_bund_2', NULL, 'entity_test_comp_bund_fld'); + + // Create a bundle that does not have the computed field. + entity_test_create_bundle('entity_test_bundle_no_comp_field', NULL, 'entity_test_comp_bund_fld'); + + ViewTestData::createTestViews(static::class, ['views_test_config']); + + // Create an entity using the default bundle with a computed field. + $entity_with_comp_field = EntityTestComputedBundleField::create([ + 'type' => 'entity_test_comp_bund_fld_bund', + 'name' => 'Entity with bundle field', + ]); + $entity_with_comp_field->save(); + + // Create an entity using the second bundle with a computed field. + $entity_with_comp_field_2 = EntityTestComputedBundleField::create([ + 'type' => 'entity_test_comp_bund_fld_bund_2', + 'name' => 'Entity 2 with bundle field', + ]); + $entity_with_comp_field_2->save(); + + // Create an entity using the third bundle without a computed field. + $entity_no_computed_field = EntityTestComputedBundleField::create([ + 'type' => 'entity_test_bundle_no_comp_field', + 'name' => 'Entity without bundle field', + ]); + $entity_no_computed_field->save(); + } + + /** + * Tests the computed field handler. + */ + public function testComputedFieldHandler() { + \Drupal::state()->set('entity_test_computed_field_item_list_value', ['computed string']); + \Drupal::state()->set('entity_test_comp_bund_fld_item_list_value', ['some other string that is also computed']); + + $view = Views::getView('computed_bundle_field_view'); + $this->executeView($view); + $this->assertCount(3, $view->result, 'The number of returned rows match.'); + + // Entities 1 and 2 should have the computed bundle field. But entity 3 + // should not. + $this->assertStringContainsString('some other string that is also computed', $view->field['computed_bundle_field']->render($view->result[0])); + $this->assertStringContainsString('some other string that is also computed', $view->field['computed_bundle_field']->render($view->result[1])); + $this->assertStringNotContainsString('some other string that is also computed', $view->field['computed_bundle_field']->render($view->result[2])); + + $view->destroy(); + } + +} diff --git a/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php b/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php index c60e91447f0fc1ae6a14fc5a4c0306ce5f13fefd..879c6d4bc26748290d4dda33e727e75027afa787 100644 --- a/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/field/FieldTest.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityRepositoryInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Tests\UnitTestCase; @@ -67,6 +68,13 @@ class FieldTest extends UnitTestCase { */ protected $fieldTypePluginManager; + /** + * The mocked entity type bundle info service. + * + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityTypeBundleInfo; + /** * The renderer. * @@ -113,6 +121,9 @@ protected function setUp(): void { $this->container = new ContainerBuilder(); $this->container->set('plugin.manager.field.field_type', $this->fieldTypePluginManager); + + $this->entityTypeBundleInfo = $this->createMock(EntityTypeBundleInfoInterface::class); + $this->container->set('entity_type.bundle.info', $this->entityTypeBundleInfo); \Drupal::setContainer($this->container); } @@ -126,7 +137,7 @@ public function testConstruct() { // provides it. 'entity field' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $this->assertEquals('title', $handler->definition['field_name']); } @@ -139,7 +150,7 @@ public function testDefineOptionsWithNoOptions() { 'entity_type' => 'test_entity', 'field_name' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); // Setup the entity field manager to allow fetching the storage definitions. $title_storage = $this->getBaseFieldStorage(); @@ -168,7 +179,7 @@ public function testDefineOptionsWithDefaultFormatterOnFieldDefinition() { 'default_formatter' => 'test_example', 'default_formatter_settings' => ['link_to_entity' => TRUE], ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); // Setup the entity field manager to allow fetching the storage definitions. $title_storage = $this->getBaseFieldStorage(); @@ -195,7 +206,7 @@ public function testDefineOptionsWithDefaultFormatterOnFieldType() { 'field_name' => 'title', 'default_formatter_settings' => ['link_to_entity' => TRUE], ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); // Setup the entity field manager to allow fetching the storage definitions. $title_storage = $this->getBaseFieldStorage(); @@ -221,7 +232,7 @@ public function testCalculateDependenciesWithBaseField() { 'entity_type' => 'test_entity', 'field_name' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $title_storage = $this->getBaseFieldStorage(); $this->entityFieldManager->expects($this->atLeastOnce()) @@ -243,7 +254,7 @@ public function testCalculateDependenciesWithConfiguredField() { 'entity_type' => 'test_entity', 'field_name' => 'body', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $body_storage = $this->getConfigFieldStorage(); $this->entityFieldManager->expects($this->atLeastOnce()) @@ -269,7 +280,7 @@ public function testAccess() { 'entity_type' => 'test_entity', 'field_name' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $handler->setViewsData($this->viewsData); @@ -320,7 +331,7 @@ public function testClickSortWithOutConfiguredColumn($order) { 'entity_type' => 'test_entity', 'field_name' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $this->entityFieldManager->expects($this->never()) @@ -342,7 +353,7 @@ public function testClickSortWithBaseField($order) { 'entity_type' => 'test_entity', 'field_name' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $field_storage = $this->getBaseFieldStorage(); @@ -402,7 +413,7 @@ public function testClickSortWithConfiguredField($order) { 'entity_type' => 'test_entity', 'field_name' => 'body', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $field_storage = $this->getConfigFieldStorage(); @@ -457,7 +468,7 @@ public function testQueryWithGroupByForBaseField() { 'entity_type' => 'test_entity', 'field_name' => 'title', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $handler->view->field = [$handler]; @@ -519,7 +530,7 @@ public function testQueryWithGroupByForConfigField() { 'entity_type' => 'test_entity', 'field_name' => 'body', ]; - $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new EntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $handler->view->field = [$handler]; @@ -583,7 +594,7 @@ public function testPrepareItemsByDelta(array $options, array $expected_values) 'entity_type' => 'test_entity', 'field_name' => 'integer', ]; - $handler = new FieldTestEntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager); + $handler = new FieldTestEntityField([], 'field', $definition, $this->entityTypeManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager, $this->renderer, $this->entityRepository, $this->entityFieldManager, $this->entityTypeBundleInfo); $handler->view = $this->executable; $handler->view->field = [$handler]; diff --git a/core/modules/views/views.api.php b/core/modules/views/views.api.php index 49eb06513edb29c1facfd6fa6e90fd828a2c4f06..503ef9064d5ce68f6f0cb8cf029f999f0a60f4c3 100644 --- a/core/modules/views/views.api.php +++ b/core/modules/views/views.api.php @@ -420,6 +420,25 @@ function hook_views_data() { ], ]; + // Computed field example. Computed fields are not associated with actual data + // tables and fields, and therefore have no schema. Instead, they are computed + // when the value is read from the entity. Here's the definition of a computed + // field that exists for a particular entity type. The value of the field will + // be calculated by a defined class. If the defined class for the computed + // fields differs between multiple bundles of the same entity type, then each + // of those fields should be added separately. + // @see \Drupal\Core\TypedData\DataDefinitionInterface::setComputed(). + // @see \Drupal\Core\TypedData\DataDefinitionInterface::setClass(). + $data['example_table']['computed_bundle_field'] = [ + 'title' => t('Computed Bundle Field'), + 'help' => t('The computed bundle field'), + 'field' => [ + 'id' => 'field', + 'default_formatter' => 'string', + 'field_name' => 'computed_bundle_field', + ], + ]; + // Area example. Areas are not generally associated with actual data // tables and fields. This example is from views_views_data(), which defines // the "Global" table (not really a table, but a group of Fields, Filters,