Change record status: 
Project: 
Introduced in branch: 
11.5.x
Introduced in version: 
11.5.0
Description: 

This introduces the Database Schema Definition to replace the current way of defining a table's structure via a nested array, with a structure of value objects defined in the Drupal\Core\Database\SchemaDefinition namespace.

This structure is immutable and database abstract.

In the future, the db-specific field types in the existing array-based schema definition will no longer be defined here and database drivers will be able to implement db-specific features such as GIN and GIST indexes. It will also allow for better introspection of database schema, and validation of properties.

Schema definition changes

Before

    $schema = [
      'description' => 'The base table for configuration data.',
      'fields' => [
        'collection' => [
          'description' => 'Primary Key: Config object collection.',
          'type' => 'varchar_ascii',
          'length' => 255,
          'not null' => TRUE,
          'default' => '',
        ],
        'name' => [
          'description' => 'Primary Key: Config object name.',
          'type' => 'varchar_ascii',
          'length' => 255,
          'not null' => TRUE,
          'default' => '',
        ],
        'data' => [
          'description' => 'A serialized configuration object data.',
          'type' => 'blob',
          'not null' => FALSE,
          'size' => 'big',
        ],
      ],
      'primary key' => ['collection', 'name'],
    ];

After

Note the usage of named parameters. In the future, these could allow more flexibility when it comes to adding, changing, deprecating, and removing function arguments.

    new Table(
      name: 'config',
      description: 'The base table for configuration data.',
      columns: [
        new Column(
          name: 'collection',
          description: 'Primary Key: Config object collection.',
          type: ColumnType::VarcharAscii,
          length: 255,
          notNull: TRUE,
          default: new StringValue(''),
        ),
        new Column(
          name: 'name',
          description: 'Primary Key: Config object name.',
          type: ColumnType::VarcharAscii,
          length: 255,
          notNull: TRUE,
          default: new StringValue(''),
        ),
        new Column(
          name: 'data',
          description: 'A serialized configuration object data.',
          type: ColumnType::Blob,
          notNull: FALSE,
          size: ColumnSize::Big,
        ),
      ],
      primaryKey: new PrimaryKey(['collection', 'name']),
    );

hook_schema() changes

Refer to database.api.php for a full example.

Before

/**
 * Implements hook_schema().
 */
function system_schema(): array {
  $schema['my_table'] = [
    ...
  ];

  return $schema;
}

After


/**
 * Implements hook_schema().
 */
function system_schema(): Schema {
    $tables[] = new Table(
      name: 'my_table',
      ...
    );

    return new Schema(
      type: SchemaDefinitionType::Module,
      name: 'system',
      tables: $tables,
    );
}

Storage handlers

Before

  /**
   * Check if the table exists and create it if not.
   */
  protected function ensureTableExists() {
    try {
      $database_schema = $this->connection->schema();
      $schema_definition = $this->schemaDefinition();
      $database_schema->createTable(static::TABLE_NAME, $schema_definition);
    }
    // If another process has already created the batch table, attempting to
    // recreate it will throw an exception. In this case just catch the
    // exception and do nothing.
    catch (DatabaseException) {
    }
    catch (\Exception) {
      return FALSE;
    }
    return TRUE;
  }

  public function schemaDefinition() {
    return [
      ...
    ];
  }

After

  /**
   * Check if the table exists and create it if not.
   */
  protected function ensureTableExists() {
    try {
      $this->connection->schema()->createSchemaFromDefinition($this->schemaDefinition());
    }
    // If another process has already created the batch table, attempting to
    // recreate it will throw an exception. In this case just catch the
    // exception and do nothing.
    catch (DatabaseException) {
    }
    catch (\Exception) {
      return FALSE;
    }
    return TRUE;
  }

  public function schemaDefinition(): Schema {
    $tables[] = new Table(
      name: 'my_storage_table',
      ...
    );

    return new Schema(
      type: SchemaDefinitionType::Storage,
      name: 'my_storage',
      tables: $tables,
    );
  }
Impacts: 
Module developers