diff --git a/core/modules/block_content/block_content.install b/core/modules/block_content/block_content.install index dd4521690f..72b3724db1 100644 --- a/core/modules/block_content/block_content.install +++ b/core/modules/block_content/block_content.install @@ -152,3 +152,34 @@ function block_content_update_8600() { \Drupal::entityDefinitionUpdateManager() ->installFieldStorageDefinition('reusable', 'block_content', 'block_content', $reusable); } + +/** + * Update 'block_content' view to filter on new 'reusable' field. + */ +function block_content_update_8601() { + $config_factory = \Drupal::configFactory(); + $view = $config_factory->getEditable('views.view.block_content'); + $base_table = 'block_content_field_data'; + // Make sure the view's 'base_table' is correct. The default view could have + // been deleted and the view ID used for a different view. + if ($view->get('base_table') !== $base_table) { + return; + } + foreach ($view->get('display') as $display_name => $display) { + // Update the default display and displays that have overridden filters. + if (!isset($display['display_options']['filters']['reusable']) && + ($display_name === 'default' || isset($display['display_options']['filters']))) { + // Save off the base part of the config path we are updating. + $base = "display.$display_name.display_options.filters.reusable"; + $view->set("$base.id", 'reusable'); + $view->set("$base.plugin_id", 'boolean'); + $view->set("$base.table", $base_table); + $view->set("$base.field", "reusable"); + $view->set("$base.value", "1"); + $view->set("$base.entity_type", "block_content"); + $view->set("$base.entity_field", "reusable"); + } + } + $view->save(); +} + diff --git a/core/modules/block_content/block_content.routing.yml b/core/modules/block_content/block_content.routing.yml index 35724a68b8..29e0dad377 100644 --- a/core/modules/block_content/block_content.routing.yml +++ b/core/modules/block_content/block_content.routing.yml @@ -27,6 +27,7 @@ entity.block_content.canonical: requirements: _entity_access: 'block_content.update' block_content: \d+ + _is_reusable_block_content: 'true' entity.block_content.edit_form: path: '/block/{block_content}' @@ -37,6 +38,7 @@ entity.block_content.edit_form: requirements: _entity_access: 'block_content.update' block_content: \d+ + _is_reusable_block_content: 'true' entity.block_content.delete_form: path: '/block/{block_content}/delete' @@ -48,6 +50,7 @@ entity.block_content.delete_form: requirements: _entity_access: 'block_content.delete' block_content: \d+ + _is_reusable_block_content: 'true' block_content.type_add: path: '/admin/structure/block/block-content/types/add' diff --git a/core/modules/block_content/block_content.services.yml b/core/modules/block_content/block_content.services.yml index 9c6dceb82e..25c4f2edc3 100644 --- a/core/modules/block_content/block_content.services.yml +++ b/core/modules/block_content/block_content.services.yml @@ -4,3 +4,7 @@ services: arguments: ['@cache.bootstrap', '@lock', '@entity_type.manager'] tags: - { name: needs_destruction } + access_check.entity.block_content: + class: Drupal\block_content\Access\ReusableAccessCheck + tags: + - { name: access_check, applies_to: _is_reusable_block_content } diff --git a/core/modules/block_content/config/optional/views.view.block_content.yml b/core/modules/block_content/config/optional/views.view.block_content.yml index 1be5a0417c..2c008864f3 100644 --- a/core/modules/block_content/config/optional/views.view.block_content.yml +++ b/core/modules/block_content/config/optional/views.view.block_content.yml @@ -431,6 +431,44 @@ display: entity_type: block_content entity_field: type plugin_id: bundle + reusable: + id: reusable + table: block_content_field_data + field: reusable + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: block_content + entity_field: reusable + plugin_id: boolean sorts: { } title: 'Custom block library' header: { } diff --git a/core/modules/block_content/src/Access/ReusableAccessCheck.php b/core/modules/block_content/src/Access/ReusableAccessCheck.php new file mode 100644 index 0000000000..3558023786 --- /dev/null +++ b/core/modules/block_content/src/Access/ReusableAccessCheck.php @@ -0,0 +1,28 @@ +isReusable()); + return $access->addCacheableDependency($block_content); + } + +} diff --git a/core/modules/layout_builder/layout_builder.install b/core/modules/layout_builder/layout_builder.install index 0e55ccbedd..6d7f19245b 100644 --- a/core/modules/layout_builder/layout_builder.install +++ b/core/modules/layout_builder/layout_builder.install @@ -6,6 +6,8 @@ */ use Drupal\Core\Cache\Cache; +use Drupal\Core\Database\Database; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; use Drupal\layout_builder\Section; @@ -59,14 +61,59 @@ function layout_builder_schema() { 'not null' => TRUE, 'default' => '', ], -/* 'module' => [ - 'description' => 'The name of the module that is using the entity.', + // @todo will the parent always be an entity. + 'parent_type' => [ + 'description' => 'The name of the object type in which the entity is used.', 'type' => 'varchar_ascii', - 'length' => DRUPAL_EXTENSION_NAME_MAX_LENGTH, + 'length' => 64, 'not null' => TRUE, 'default' => '', - ],*/ - // @todo will the user always be an entity. File usage uses object + ], + 'parent_id' => [ + 'description' => 'The primary key of the entity using the entity.', + 'type' => 'varchar_ascii', + 'length' => EntityTypeInterface::ID_MAX_LENGTH, + 'not null' => TRUE, + 'default' => 0, + ], + 'count' => [ + 'description' => 'The number of times this entity is used by this parent.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ], + ], + 'primary key' => ['entity_id', 'entity_type', 'parent_id'], + 'indexes' => [ + 'type_id' => ['parent_type', 'parent_id'], + 'entity_id_count' => ['entity_id', 'count'], + ], + ]; + return $schema; +} + +/** + * Create the 'entity_usage' table. + */ +function layout_builder_update_8001() { + $entity_usage_schema = [ + 'description' => 'Track where a entity is used.', + 'fields' => [ + 'entity_id' => [ + 'description' => 'Entity ID.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + ], + 'entity_type' => [ + 'description' => 'The name of the object type in which the file is used.', + 'type' => 'varchar_ascii', + 'length' => 64, + 'not null' => TRUE, + 'default' => '', + ], + // @todo will the parent always be an entity. 'parent_type' => [ 'description' => 'The name of the object type in which the entity is used.', 'type' => 'varchar_ascii', @@ -75,9 +122,9 @@ function layout_builder_schema() { 'default' => '', ], 'parent_id' => [ - 'description' => 'The primary key of the entity using the file.', + 'description' => 'The primary key of the entity using the entity.', 'type' => 'varchar_ascii', - 'length' => 64, + 'length' => EntityTypeInterface::ID_MAX_LENGTH, 'not null' => TRUE, 'default' => 0, ], @@ -93,9 +140,8 @@ function layout_builder_schema() { 'indexes' => [ 'type_id' => ['parent_type', 'parent_id'], 'entity_id_count' => ['entity_id', 'count'], - /*'entity_ids_module' => ['entity_id', 'module'],*/ ], ]; - return $schema; + Database::getConnection()->schema()->createTable('entity_usage', $entity_usage_schema); }