function SqlContentEntityStorageSchema::updateSharedTableSchema

Same name in other branches
  1. 9 core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::updateSharedTableSchema()
  2. 8.9.x core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::updateSharedTableSchema()
  3. 10 core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::updateSharedTableSchema()

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 1815

Class

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

Namespace

Drupal\Core\Entity\Sql

Code

protected function updateSharedTableSchema(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) {
    if (!$this->storage
        ->countFieldData($original, TRUE)) {
        try {
            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();
            }
            // Since there is no data we may be switching from a dedicated table
            // to a schema 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()) {
                if (isset($transaction)) {
                    $transaction->rollBack();
                }
            }
            else {
                // Recreate original schema.
                $this->createSharedTableSchema($original);
            }
            throw $e;
        }
    }
    else {
        if (empty($storage_definition->getSetting('column_changes_handled')) && $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.');
        }
        $updated_field_name = $storage_definition->getName();
        $table_mapping = $this->getTableMapping($this->entityType, [
            $storage_definition,
        ]);
        $column_names = $table_mapping->getColumnNames($updated_field_name);
        $schema_handler = $this->database
            ->schema();
        // Iterate over the mapped table to find the ones that host the deleted
        // field schema.
        $original_schema = $this->loadFieldSchemaData($original);
        $schema = [];
        foreach ($table_mapping->getTableNames() as $table_name) {
            foreach ($table_mapping->getFieldNames($table_name) as $field_name) {
                if ($field_name == $updated_field_name) {
                    $schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names);
                    // Handle NOT NULL constraints.
                    foreach ($schema[$table_name]['fields'] as $column_name => $specifier) {
                        $not_null = !empty($specifier['not null']);
                        $original_not_null = !empty($original_schema[$table_name]['fields'][$column_name]['not null']);
                        if ($not_null !== $original_not_null) {
                            if ($not_null && $this->hasNullFieldPropertyData($table_name, $column_name)) {
                                throw new EntityStorageException("The {$column_name} column cannot have NOT NULL constraints as it holds NULL values.");
                            }
                            $column_schema = $original_schema[$table_name]['fields'][$column_name];
                            $column_schema['not null'] = $not_null;
                            $schema_handler->changeField($table_name, $column_name, $column_name, $column_schema);
                        }
                    }
                    // Drop original indexes and unique keys.
                    if (!empty($original_schema[$table_name]['indexes'])) {
                        foreach ($original_schema[$table_name]['indexes'] as $name => $specifier) {
                            $schema_handler->dropIndex($table_name, $name);
                        }
                    }
                    if (!empty($original_schema[$table_name]['unique keys'])) {
                        foreach ($original_schema[$table_name]['unique keys'] as $name => $specifier) {
                            $schema_handler->dropUniqueKey($table_name, $name);
                        }
                    }
                    // Create new indexes and unique keys.
                    if (!empty($schema[$table_name]['indexes'])) {
                        foreach ($schema[$table_name]['indexes'] as $name => $specifier) {
                            // Check if the index exists because it might already have been
                            // created as part of the earlier entity type update event.
                            $this->addIndex($table_name, $name, $specifier, $schema[$table_name]);
                        }
                    }
                    if (!empty($schema[$table_name]['unique keys'])) {
                        foreach ($schema[$table_name]['unique keys'] as $name => $specifier) {
                            $schema_handler->addUniqueKey($table_name, $name, $specifier);
                        }
                    }
                    // After deleting the field schema skip to the next table.
                    break;
                }
            }
        }
        $this->saveFieldSchemaData($storage_definition, $schema);
    }
}

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