getPendingUpdateFunctions(), TRUE)) { // The 'name' field is non-NULL - if we get a NULL value that indicates a // failure to join on taxonomy_term_field_data. $is_broken = \Drupal::entityQuery('taxonomy_term') ->condition('name', NULL, 'IS NULL') ->range(0, 1) ->accessCheck(FALSE) ->execute(); if ($is_broken) { $requirements[$update_name] = [ 'title' => t('Taxonomy term data'), 'value' => t('Integrity issues detected'), 'description' => t('The make_taxonomy_term_revisionable database update cannot be run until the data has been fixed. See the change record for more information.', [ ':change_record' => 'https://www.drupal.org/node/3117753', ]), 'severity' => REQUIREMENT_ERROR, ]; } } } return $requirements; } /** * Convert the custom taxonomy term hierarchy storage to a default storage. */ function taxonomy_update_8501() { $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); /** @var \Drupal\Core\Field\BaseFieldDefinition $field_storage_definition */ $field_storage_definition = $definition_update_manager->getFieldStorageDefinition('parent', 'taxonomy_term'); $field_storage_definition->setCustomStorage(FALSE); $definition_update_manager->updateFieldStorageDefinition($field_storage_definition); } /** * Copy hierarchy from {taxonomy_term_hierarchy} to {taxonomy_term__parent}. */ function taxonomy_update_8502(&$sandbox) { $database = \Drupal::database(); if (!isset($sandbox['current'])) { // Set batch ops sandbox. $sandbox['current'] = 0; $sandbox['tid'] = -1; $sandbox['delta'] = 0; $sandbox['limit'] = Settings::get('entity_update_batch_size', 50); // Count records using a join, as there might be orphans in the hierarchy // table. See https://www.drupal.org/project/drupal/issues/2997982. $select = $database->select('taxonomy_term_hierarchy', 'h'); $select->join('taxonomy_term_data', 'd', 'h.tid = d.tid'); $sandbox['max'] = $select ->countQuery() ->execute() ->fetchField(); } // Save the hierarchy. $select = $database->select('taxonomy_term_hierarchy', 'h'); $select->join('taxonomy_term_data', 'd', 'h.tid = d.tid'); $hierarchy = $select ->fields('h', ['tid', 'parent']) ->fields('d', ['vid', 'langcode']) ->range($sandbox['current'], $sandbox['limit']) ->orderBy('tid', 'ASC') ->orderBy('parent', 'ASC') ->execute() ->fetchAll(); // Restore data. $insert = $database->insert('taxonomy_term__parent') ->fields(['bundle', 'entity_id', 'revision_id', 'langcode', 'delta', 'parent_target_id']); foreach ($hierarchy as $row) { if ($row->tid !== $sandbox['tid']) { $sandbox['delta'] = 0; $sandbox['tid'] = $row->tid; } $insert->values([ 'bundle' => $row->vid, 'entity_id' => $row->tid, 'revision_id' => $row->tid, 'langcode' => $row->langcode, 'delta' => $sandbox['delta'], 'parent_target_id' => $row->parent, ]); $sandbox['delta']++; $sandbox['current']++; } $insert->execute(); $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']); if ($sandbox['#finished'] >= 1) { // Update the entity type because the 'taxonomy_term_hierarchy' table is no // longer part of its shared tables schema. $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $definition_update_manager->updateEntityType($definition_update_manager->getEntityType('taxonomy_term')); // \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::onEntityTypeUpdate() // only deletes *known* entity tables (i.e. the base, data and revision // tables), so we have to drop it manually. $database->schema()->dropTable('taxonomy_term_hierarchy'); return t('Taxonomy term hierarchy has been converted to default entity reference storage.'); } } /** * Update views to use {taxonomy_term__parent} in relationships. */ function taxonomy_update_8503() { $config_factory = \Drupal::configFactory(); foreach ($config_factory->listAll('views.view.') as $id) { $view = $config_factory->getEditable($id); foreach (array_keys($view->get('display')) as $display_id) { $changed = FALSE; foreach (['relationships', 'filters', 'arguments'] as $handler_type) { $base_path = "display.$display_id.display_options.$handler_type"; $handlers = $view->get($base_path); if (!$handlers) { continue; } foreach ($handlers as $handler_key => $handler_config) { $table_path = "$base_path.$handler_key.table"; $field_path = "$base_path.$handler_key.field"; $table = $view->get($table_path); $field = $view->get($field_path); if (($table && ($table === 'taxonomy_term_hierarchy')) && ($field && ($field === 'parent'))) { $view->set($table_path, 'taxonomy_term__parent'); $view->set($field_path, 'parent_target_id'); $changed = TRUE; } } } if ($changed) { $view->save(TRUE); } } } } /** * Add the publishing status fields to taxonomy terms. */ function taxonomy_update_8601() { $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $entity_type = $definition_update_manager->getEntityType('taxonomy_term'); // Bail out early if a field named 'status' is already installed. if ($definition_update_manager->getFieldStorageDefinition('status', 'taxonomy_term')) { $message = \Drupal::state()->get('taxonomy_update_8601_skip_message', t('The publishing status field has not been added to taxonomy terms. See this page for more information on how to install it.', [ ':link' => 'https://www.drupal.org/node/2985366', ])); return $message; } // Add the 'published' entity key to the taxonomy_term entity type. $entity_keys = $entity_type->getKeys(); $entity_keys['published'] = 'status'; $entity_type->set('entity_keys', $entity_keys); $definition_update_manager->updateEntityType($entity_type); // Add the status field. $status = BaseFieldDefinition::create('boolean') ->setLabel(t('Publishing status')) ->setDescription(t('A boolean indicating the published state.')) ->setRevisionable(TRUE) ->setTranslatable(TRUE) ->setDefaultValue(TRUE); $has_content_translation_status_field = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term'); if ($has_content_translation_status_field) { $status->setInitialValueFromField('content_translation_status', TRUE); } else { $status->setInitialValue(TRUE); } $definition_update_manager->installFieldStorageDefinition('status', 'taxonomy_term', 'taxonomy_term', $status); // Uninstall the 'content_translation_status' field if needed. if ($has_content_translation_status_field) { $content_translation_status = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term'); $definition_update_manager->uninstallFieldStorageDefinition($content_translation_status); } return t('The publishing status field has been added to taxonomy terms.'); } /** * Add an index on the 'taxonomy_term__parent' field table. */ function taxonomy_update_8701() { $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $storage_definition = $entity_definition_update_manager->getFieldStorageDefinition('parent', 'taxonomy_term'); $entity_definition_update_manager->updateFieldStorageDefinition($storage_definition); } /** * Fix the parent field langcode data. */ function taxonomy_update_8702(&$sandbox) { $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $field_storage_definition = $definition_update_manager->getFieldStorageDefinition('parent', 'taxonomy_term'); $entity_type = $definition_update_manager->getEntityType('taxonomy_term'); // Only perform the update if: // - The field is not translatable. It's possible that custom or contrib code // has overridden this. // - The field is not revisionable. If it is then // taxonomy_post_update_make_taxonomy_term_revisionable() has already run // and this used to fix the parent field langcode data. // - Terms are using a SQL-based storage class. if (!$field_storage_definition->isTranslatable() && !$entity_type->isRevisionable() && is_subclass_of($entity_type->getStorageClass(), SqlEntityStorageInterface::class) ) { // taxonomy_update_8502() populated the langcode field of // 'taxonomy_term__parent' using the term's langcode. However, the field is // not translatable and, therefore, should use the term's default language. $database = \Drupal::database(); $select = $database->select('taxonomy_term__parent', 'tp'); $select->join('taxonomy_term_field_data', 'tdf', 'tp.entity_id = tdf.tid AND tdf.langcode <> tp.langcode'); $select->fields('tp', ['entity_id']) ->fields('tdf', ['tid', 'langcode']) ->condition('tdf.default_langcode', 1); if (!isset($sandbox['max'])) { $count_query = clone $select; $sandbox['max'] = $count_query->countQuery()->execute()->fetchField(); $sandbox['current'] = 0; } $result = $select->execute(); $processed = 0; while ($row = $result->fetchAssoc()) { $database->update('taxonomy_term__parent') ->condition('entity_id', $row['tid']) ->fields(['langcode' => $row['langcode']]) ->execute(); $sandbox['current']++; $processed++; if ($processed >= Settings::get('entity_update_batch_size', 50)) { break; } } } $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']); }