taxonomy.install

Same filename and directory in other branches
  1. 7.x modules/taxonomy/taxonomy.install
  2. 9 core/modules/taxonomy/taxonomy.install
  3. 10 core/modules/taxonomy/taxonomy.install
  4. 11.x core/modules/taxonomy/taxonomy.install

Install, update and uninstall functions for the taxonomy module.

File

core/modules/taxonomy/taxonomy.install

View source
<?php


/**
 * @file
 * Install, update and uninstall functions for the taxonomy module.
 */
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Site\Settings;

/**
 * Implements hook_requirements().
 */
function taxonomy_requirements($phase) {
    $requirements = [];
    if ($phase === 'update') {
        // Check for invalid data before making terms revisionable.
        
        /** @var \Drupal\Core\Update\UpdateRegistry $registry */
        $registry = \Drupal::service('update.post_update_registry');
        $update_name = 'taxonomy_post_update_make_taxonomy_term_revisionable';
        if (in_array($update_name, $registry->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 <a href=":change_record">change record</a> 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 <strong>not</strong> been added to taxonomy terms. See <a href=":link">this page</a> 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'];
}

Functions

Title Deprecated Summary
taxonomy_requirements Implements hook_requirements().
taxonomy_update_8501 Convert the custom taxonomy term hierarchy storage to a default storage.
taxonomy_update_8502 Copy hierarchy from {taxonomy_term_hierarchy} to {taxonomy_term__parent}.
taxonomy_update_8503 Update views to use {taxonomy_term__parent} in relationships.
taxonomy_update_8601 Add the publishing status fields to taxonomy terms.
taxonomy_update_8701 Add an index on the 'taxonomy_term__parent' field table.
taxonomy_update_8702 Fix the parent field langcode data.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.