123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- <?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;
- }
|