You are here

protected function SqlContentEntityStorageSchema::updateDedicatedTableSchema in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::updateDedicatedTableSchema()

Updates the schema for a field stored in a shared table.

Parameters

\Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition: The storage definition of the field being updated.

\Drupal\Core\Field\FieldStorageDefinitionInterface $original: The original storage definition; i.e., the definition before the update.

Throws

\Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException Thrown when the update to the field is forbidden.

\Exception Rethrown exception if the table recreation fails.

File

core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php, line 1724

Class

SqlContentEntityStorageSchema
Defines a schema handler that supports revisionable, translatable entities.

Namespace

Drupal\Core\Entity\Sql

Code

protected function updateDedicatedTableSchema(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) {
  if (!$this->storage
    ->countFieldData($original, TRUE)) {

    // There is no data. Re-create the tables completely.
    if ($this->database
      ->supportsTransactionalDDL()) {

      // If the database supports transactional DDL, we can go ahead and rely
      // on it. If not, we will have to rollback manually if something fails.
      $transaction = $this->database
        ->startTransaction();
    }
    try {

      // Since there is no data we may be switching from a shared table schema
      // to a dedicated table schema, hence we should use the proper API.
      $this
        ->performFieldSchemaOperation('delete', $original);
      $this
        ->performFieldSchemaOperation('create', $storage_definition);
    } catch (\Exception $e) {
      if ($this->database
        ->supportsTransactionalDDL()) {
        $transaction
          ->rollBack();
      }
      else {

        // Recreate tables.
        $this
          ->performFieldSchemaOperation('create', $original);
      }
      throw $e;
    }
  }
  else {
    if ($this
      ->hasColumnChanges($storage_definition, $original)) {
      throw new FieldStorageDefinitionUpdateForbiddenException('The SQL storage cannot change the schema for an existing field (' . $storage_definition
        ->getName() . ' in ' . $storage_definition
        ->getTargetEntityTypeId() . ' entity) with data.');
    }

    // There is data, so there are no column changes. Drop all the prior
    // indexes and create all the new ones, except for all the priors that
    // exist unchanged.
    $table_mapping = $this
      ->getTableMapping($this->entityType, [
      $storage_definition,
    ]);
    $table = $table_mapping
      ->getDedicatedDataTableName($original);
    $revision_table = $table_mapping
      ->getDedicatedRevisionTableName($original);

    // Get the field schemas.
    $schema = $storage_definition
      ->getSchema();
    $original_schema = $original
      ->getSchema();

    // Gets the SQL schema for a dedicated tables.
    $actual_schema = $this
      ->getDedicatedTableSchema($storage_definition);
    foreach ($original_schema['indexes'] as $name => $columns) {
      if (!isset($schema['indexes'][$name]) || $columns != $schema['indexes'][$name]) {
        $real_name = $this
          ->getFieldIndexName($storage_definition, $name);
        $this->database
          ->schema()
          ->dropIndex($table, $real_name);
        $this->database
          ->schema()
          ->dropIndex($revision_table, $real_name);
      }
    }
    $table = $table_mapping
      ->getDedicatedDataTableName($storage_definition);
    $revision_table = $table_mapping
      ->getDedicatedRevisionTableName($storage_definition);
    foreach ($schema['indexes'] as $name => $columns) {
      if (!isset($original_schema['indexes'][$name]) || $columns != $original_schema['indexes'][$name]) {
        $real_name = $this
          ->getFieldIndexName($storage_definition, $name);
        $real_columns = [];
        foreach ($columns as $column_name) {

          // Indexes can be specified as either a column name or an array with
          // column name and length. Allow for either case.
          if (is_array($column_name)) {
            $real_columns[] = [
              $table_mapping
                ->getFieldColumnName($storage_definition, $column_name[0]),
              $column_name[1],
            ];
          }
          else {
            $real_columns[] = $table_mapping
              ->getFieldColumnName($storage_definition, $column_name);
          }
        }

        // Check if the index exists because it might already have been
        // created as part of the earlier entity type update event.
        $this
          ->addIndex($table, $real_name, $real_columns, $actual_schema[$table]);
        $this
          ->addIndex($revision_table, $real_name, $real_columns, $actual_schema[$revision_table]);
      }
    }
    $this
      ->saveFieldSchemaData($storage_definition, $this
      ->getDedicatedTableSchema($storage_definition));
  }
}