layout_builder.post_update.php
Same filename in other branches
Post update functions for Layout Builder.
File
-
core/
modules/ layout_builder/ layout_builder.post_update.php
View source
<?php
/**
* @file
* Post update functions for Layout Builder.
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
use Drupal\layout_builder\TempStoreIdentifierInterface;
use Drupal\user\Entity\Role;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
/**
* Rebuild plugin dependencies for all entity view displays.
*/
function layout_builder_post_update_rebuild_plugin_dependencies(&$sandbox = NULL) {
$storage = \Drupal::entityTypeManager()->getStorage('entity_view_display');
if (!isset($sandbox['ids'])) {
$sandbox['ids'] = $storage->getQuery()
->accessCheck(FALSE)
->execute();
$sandbox['count'] = count($sandbox['ids']);
}
for ($i = 0; $i < 10 && count($sandbox['ids']); $i++) {
$id = array_shift($sandbox['ids']);
if ($display = $storage->load($id)) {
$display->save();
}
}
$sandbox['#finished'] = empty($sandbox['ids']) ? 1 : ($sandbox['count'] - count($sandbox['ids'])) / $sandbox['count'];
}
/**
* Ensure all extra fields are properly stored on entity view displays.
*
* Previously
* \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::setComponent()
* was not correctly setting the configuration for extra fields. This function
* calls setComponent() for all extra field components to ensure the updated
* logic is invoked on all extra fields to correct the settings.
*/
function layout_builder_post_update_add_extra_fields(&$sandbox = NULL) {
$entity_field_manager = \Drupal::service('entity_field.manager');
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_view_display', function (LayoutEntityDisplayInterface $display) use ($entity_field_manager) {
if (!$display->isLayoutBuilderEnabled()) {
return FALSE;
}
$extra_fields = $entity_field_manager->getExtraFields($display->getTargetEntityTypeId(), $display->getTargetBundle());
$components = $display->getComponents();
// Sort the components to avoid them being reordered by setComponent().
uasort($components, 'Drupal\\Component\\Utility\\SortArray::sortByWeightElement');
$result = FALSE;
foreach ($components as $name => $component) {
if (isset($extra_fields['display'][$name])) {
$display->setComponent($name, $component);
$result = TRUE;
}
}
return $result;
});
}
/**
* Clear caches due to changes to section storage annotation changes.
*/
function layout_builder_post_update_section_storage_context_definitions() {
// Empty post-update hook.
}
/**
* Clear caches due to changes to annotation changes to the Overrides plugin.
*/
function layout_builder_post_update_overrides_view_mode_annotation() {
// Empty post-update hook.
}
/**
* Clear caches due to routing changes for the new discard changes form.
*/
function layout_builder_post_update_cancel_link_to_discard_changes_form() {
// Empty post-update hook.
}
/**
* Clear caches due to the removal of the layout_is_rebuilding query string.
*/
function layout_builder_post_update_remove_layout_is_rebuilding() {
// Empty post-update hook.
}
/**
* Clear caches due to routing changes to move the Layout Builder UI to forms.
*/
function layout_builder_post_update_routing_entity_form() {
// Empty post-update hook.
}
/**
* Clear caches to discover new blank layout plugin.
*/
function layout_builder_post_update_discover_blank_layout_plugin() {
// Empty post-update hook.
}
/**
* Clear caches due to routing changes to changing the URLs for defaults.
*/
function layout_builder_post_update_routing_defaults() {
// Empty post-update hook.
}
/**
* Clear caches due to new link added to Layout Builder's contextual links.
*/
function layout_builder_post_update_discover_new_contextual_links() {
// Empty post-update hook.
}
/**
* Fix Layout Builder tempstore keys of existing entries.
*/
function layout_builder_post_update_fix_tempstore_keys() {
/** @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager */
$section_storage_manager = \Drupal::service('plugin.manager.layout_builder.section_storage');
/** @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_factory */
$key_value_factory = \Drupal::service('keyvalue.expirable');
// Loop through each section storage type.
foreach (array_keys($section_storage_manager->getDefinitions()) as $section_storage_type) {
$key_value = $key_value_factory->get("tempstore.shared.layout_builder.section_storage.{$section_storage_type}");
foreach ($key_value->getAll() as $key => $value) {
$contexts = $section_storage_manager->loadEmpty($section_storage_type)
->deriveContextsFromRoute($key, [], '', []);
if ($section_storage = $section_storage_manager->load($section_storage_type, $contexts)) {
// Some overrides were stored with an incorrect view mode value. Update
// the view mode on the temporary section storage, if necessary.
if ($section_storage_type === 'overrides') {
$view_mode = $value->data['section_storage']
->getContextValue('view_mode');
$new_view_mode = $section_storage->getContextValue('view_mode');
if ($view_mode !== $new_view_mode) {
$value->data['section_storage']
->setContextValue('view_mode', $new_view_mode);
$key_value->set($key, $value);
}
}
// The previous tempstore key names were exact matches with the section
// storage ID. Attempt to load the corresponding section storage and
// rename the tempstore entry if the section storage provides a more
// granular tempstore key.
if ($section_storage instanceof TempStoreIdentifierInterface) {
$new_key = $section_storage->getTempstoreKey();
if ($key !== $new_key) {
if ($key_value->has($new_key)) {
$key_value->delete($new_key);
}
$key_value->rename($key, $new_key);
}
}
}
}
}
}
/**
* Clear caches due to config schema additions.
*/
function layout_builder_post_update_section_third_party_settings_schema() {
// Empty post-update hook.
}
/**
* Clear caches due to dependency changes in the layout_builder render element.
*/
function layout_builder_post_update_layout_builder_dependency_change() {
// Empty post-update hook.
}
/**
* Add new custom block permission to all roles with 'configure any layout'.
*/
function layout_builder_post_update_update_permissions() {
foreach (Role::loadMultiple() as $role) {
if ($role->hasPermission('configure any layout')) {
$role->grantPermission('create and edit custom blocks')
->save();
}
}
}
/**
* Clear caches due to addition of service decorator for entity form controller.
*/
function layout_builder_post_update_override_entity_form_controller() {
// Empty post-update hook.
}
/**
* Set the layout builder field as non-translatable where possible.
*/
function layout_builder_post_update_make_layout_untranslatable() {
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
$field_manager = \Drupal::service('entity_field.manager');
$field_map = $field_manager->getFieldMap();
foreach ($field_map as $entity_type_id => $field_infos) {
if (isset($field_infos[OverridesSectionStorage::FIELD_NAME]['bundles'])) {
$non_translatable_bundle_count = 0;
foreach ($field_infos[OverridesSectionStorage::FIELD_NAME]['bundles'] as $bundle) {
// The field map can contain stale information. If the field does not
// exist, ignore it. The field map will be rebuilt when the cache is
// cleared at the end of the update process.
if (!($field_config = FieldConfig::loadByName($entity_type_id, $bundle, OverridesSectionStorage::FIELD_NAME))) {
continue;
}
if (!$field_config->isTranslatable()) {
$non_translatable_bundle_count++;
// The layout field is already configured to be non-translatable so it
// does not need to be updated.
continue;
}
if (_layout_builder_bundle_has_no_translations($entity_type_id, $bundle) || _layout_builder_bundle_has_no_layouts($entity_type_id, $bundle)) {
// Either none of the entities have layouts or none of them have
// translations. In either case it is safe to set the field to be
// non-translatable.
$field_config->setTranslatable(FALSE);
$field_config->save();
$non_translatable_bundle_count++;
}
}
// Set the field storage to untranslatable if the field config for each
// bundle is now untranslatable. This removes layout fields for the
// entity type from the Content Translation configuration form.
if (count($field_infos[OverridesSectionStorage::FIELD_NAME]['bundles']) === $non_translatable_bundle_count) {
$field_storage = FieldStorageConfig::loadByName($entity_type_id, OverridesSectionStorage::FIELD_NAME);
$field_storage->setTranslatable(FALSE);
$field_storage->save();
}
}
}
}
/**
* Determines if there are zero layout overrides for the bundle.
*
* @param string $entity_type_id
* The entity type ID.
* @param string $bundle
* The bundle name.
*
* @return bool
* TRUE if there are zero layout overrides for the bundle, otherwise FALSE.
*/
function _layout_builder_bundle_has_no_layouts($entity_type_id, $bundle) {
$entity_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $entity_update_manager->getEntityType($entity_type_id);
$bundle_key = $entity_type->getKey('bundle');
$query = \Drupal::entityTypeManager()->getStorage($entity_type_id)
->getQuery();
if ($bundle_key) {
$query->condition($bundle_key, $bundle);
}
if ($entity_type->isRevisionable()) {
$query->allRevisions();
}
$query->exists(OverridesSectionStorage::FIELD_NAME)
->accessCheck(FALSE)
->range(0, 1);
$results = $query->execute();
return empty($results);
}
/**
* Determines if there are zero translations for the bundle.
*
* @param string $entity_type_id
* The entity type ID.
* @param string $bundle
* The bundle name.
*
* @return bool
* TRUE if there are zero translations for the bundle, otherwise FALSE.
*/
function _layout_builder_bundle_has_no_translations($entity_type_id, $bundle) {
$entity_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $entity_update_manager->getEntityType($entity_type_id);
if (!$entity_type->isTranslatable()) {
return TRUE;
}
$query = \Drupal::entityTypeManager()->getStorage($entity_type_id)
->getQuery();
$bundle_key = $entity_type->getKey('bundle');
if ($entity_type->hasKey('default_langcode')) {
if ($bundle_key) {
$query->condition($bundle_key, $bundle);
}
if ($entity_type->isRevisionable()) {
$query->allRevisions();
}
$query->condition($entity_type->getKey('default_langcode'), 0)
->accessCheck(FALSE)
->range(0, 1);
$results = $query->execute();
return empty($results);
}
// A translatable entity type should always have a default_langcode key. If it
// doesn't we have no way to determine if there are translations.
return FALSE;
}
Functions
Title | Deprecated | Summary |
---|---|---|
layout_builder_post_update_add_extra_fields | Ensure all extra fields are properly stored on entity view displays. | |
layout_builder_post_update_cancel_link_to_discard_changes_form | Clear caches due to routing changes for the new discard changes form. | |
layout_builder_post_update_discover_blank_layout_plugin | Clear caches to discover new blank layout plugin. | |
layout_builder_post_update_discover_new_contextual_links | Clear caches due to new link added to Layout Builder's contextual links. | |
layout_builder_post_update_fix_tempstore_keys | Fix Layout Builder tempstore keys of existing entries. | |
layout_builder_post_update_layout_builder_dependency_change | Clear caches due to dependency changes in the layout_builder render element. | |
layout_builder_post_update_make_layout_untranslatable | Set the layout builder field as non-translatable where possible. | |
layout_builder_post_update_overrides_view_mode_annotation | Clear caches due to changes to annotation changes to the Overrides plugin. | |
layout_builder_post_update_override_entity_form_controller | Clear caches due to addition of service decorator for entity form controller. | |
layout_builder_post_update_rebuild_plugin_dependencies | Rebuild plugin dependencies for all entity view displays. | |
layout_builder_post_update_remove_layout_is_rebuilding | Clear caches due to the removal of the layout_is_rebuilding query string. | |
layout_builder_post_update_routing_defaults | Clear caches due to routing changes to changing the URLs for defaults. | |
layout_builder_post_update_routing_entity_form | Clear caches due to routing changes to move the Layout Builder UI to forms. | |
layout_builder_post_update_section_storage_context_definitions | Clear caches due to changes to section storage annotation changes. | |
layout_builder_post_update_section_third_party_settings_schema | Clear caches due to config schema additions. | |
layout_builder_post_update_update_permissions | Add new custom block permission to all roles with 'configure any layout'. | |
_layout_builder_bundle_has_no_layouts | Determines if there are zero layout overrides for the bundle. | |
_layout_builder_bundle_has_no_translations | Determines if there are zero translations for the bundle. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.