Thanks to visit codestin.com
Credit goes to bowphp.com

Skip to main content
Version: 5.x

Database Migrations

Introduction​

About migrations

Migrations are a way to version your database, which often evolves alongside changes to your application.

Migrations are stored in the migrations folder.

Adding a migration​

To add a migration, use php bow with the add:migration command followed by the name of the migration (e.g. create_todos_table). Bow will create a file of the same name prefixed with a creation date.

php bow add:migration create_todos_table

The --table and --create options can also be used to specify the table name and indicate whether the migration will create a new table:

# Create a new table
php bow add:migration create_todos_table --create=todos

# Modify an existing table
php bow add:migration add_status_to_todos_table --table=todos

Migration structure​

A migration class contains two methods: up and rollback. The up method is used to add new tables, columns, or indexes to your database, while the rollback method should reverse the operations performed by the up method.

use Bow\Database\Migration\Migration;
use Bow\Database\Migration\Table;

class Version20190929153939CreateTodosTable extends Migration
{
/**
* Run the migration
*/
public function up(): void
{
$this->create("todos", function (Table $table) {
$table->addIncrement('id');
$table->addString('title');
$table->addInteger('status', ['default' => 1]);
$table->addTimestamps();
});
}

/**
* Reverse the migration
*/
public function rollback(): void
{
$this->dropIfExists("todos");
}
}

Running migrations​

To run all your pending migrations:

php bow migration:migrate

# Shortcut
php bow migrate

Rolling back migrations​

To roll back the last migration operation:

php bow migration:rollback

To roll back all migrations:

php bow migration:reset

Table management​

Creating a table​

$this->create("users", function (Table $table) {
$table->addIncrement('id');
$table->addString('name');
$table->addString('email', ['unique' => true]);
$table->addTimestamps();
});

Creating a table if it does not exist​

$this->createIfNotExists("users", function (Table $table) {
$table->addIncrement('id');
$table->addString('name');
$table->addTimestamps();
});

Modifying a table​

$this->alter('users', function (Table $table) {
$table->addString('phone', ['nullable' => true]);
});

Renaming a table​

$this->renameTable('old_table', 'new_table');

// Rename if it exists
$this->renameTableIfExists('old_table', 'new_table');

Dropping a table​

$this->drop('users');

// Drop if it exists
$this->dropIfExists('users');

Custom connection​

$this->connection('mysql_secondary')->create("logs", function (Table $table) {
$table->addIncrement('id');
$table->addText('message');
$table->addTimestamps();
});

Table options​

$this->create("users", function (Table $table) {
$table->withEngine('InnoDB');
$table->withCharset('utf8mb4');
$table->withCollation('utf8mb4_unicode_ci');

$table->addIncrement('id');
$table->addString('name');
});

Raw SQL​

// Run raw SQL inside the migration
$this->sql('ALTER TABLE users ADD INDEX idx_email (email)');

// Alternative
$this->addSql('CREATE INDEX idx_name ON users (name)');

Column types​

Numeric columns​

MethodDescription
addIncrement('id')Auto-incremented INTEGER (primary key)
addBigIncrement('id')Auto-incremented BIGINT (primary key)
addMediumIncrement('id')Auto-incremented MEDIUMINT (primary key)
addSmallIntegerIncrement('id')Auto-incremented SMALLINT (primary key)
addInteger('column', $attr)INTEGER
addIntegerPrimary('column')INTEGER (primary key)
addBigInteger('column', $attr)BIGINT
addMediumInteger('column', $attr)MEDIUMINT
addSmallInteger('column', $attr)SMALLINT
addTinyInteger('column', $attr)TINYINT
addFloat('column', $attr)FLOAT
addFloatPrimary('column')FLOAT (primary key)
addDouble('column', $attr)DOUBLE
addDoublePrimary('column')DOUBLE (primary key)
addBoolean('column')BOOLEAN

Text columns​

MethodDescription
addString('column', $attr)VARCHAR (255 by default)
addChar('column', $attr)CHAR
addText('column', $attr)TEXT
addLongtext('column', $attr)LONGTEXT
addJson('column', $attr)JSON

Date/time columns​

MethodDescription
addDatetime('column', $attr)DATETIME
addDate('column', $attr)DATE
addTime('column', $attr)TIME
addTimestamp('column', $attr)TIMESTAMP
addYear('column', $attr)YEAR
addTimestamps()Adds created_at and updated_at
addSoftDelete()Adds deleted_at for soft delete

Special columns​

MethodDescription
addUuid('column', $attr)UUID
addUuidPrimary('column', $attr)UUID (primary key)
addBinary('column', $attr)BINARY
addBlob('column', $attr)BLOB
addTinyBlob('column', $attr)TINYBLOB
addMediumBlob('column', $attr)MEDIUMBLOB
addLongBlob('column', $attr)LONGBLOB
addIpAddress('column', $attr)IP address
addMacAddress('column', $attr)MAC address
addEnum('column', $attr)ENUM
addCheck('column', $attr)CHECK constraint

Column attributes​

All add* methods accept an array of attributes:

$table->addString('email', [
'size' => 100, // Column size
'nullable' => true, // Can be NULL
'default' => 'N/A', // Default value
'unique' => true, // UNIQUE constraint
'index' => true, // Add an INDEX
'unsigned' => true, // Unsigned (for numbers)
'primary' => true, // Primary key
'increment' => true, // Auto-increment
]);

The addColumn method​

All helper methods use addColumn internally:

$table->addColumn('price', 'decimal', [
'size' => '10,2',
'unsigned' => true,
'default' => 0.00
]);

Raw SQL in a column​

$table->addRaw('FULLTEXT INDEX idx_content (title, body)');

Modifying columns​

Renaming a column​

$this->alter('users', function (Table $table) {
$table->renameColumn('name', 'full_name');
});

Changing a column's type​

Each add* method in the table above has a change* counterpart that modifies the type or attributes of an existing column (changeString, changeInteger, changeFloat, changeBoolean, changeEnum, changeJson, etc.):

$this->alter('users', function (Table $table) {
$table->changeString('name', ['size' => 500]);
$table->changeInteger('status', ['default' => 0]);
});

For cases not covered by the helpers, the generic changeColumn($name, $type, $attr) method is available.

Dropping a column​

$this->alter('users', function (Table $table) {
$table->dropColumn('temporary_field');
});

Constraints​

Foreign keys​

$this->create("posts", function (Table $table) {
$table->addIncrement('id');
$table->addInteger('user_id', ['unsigned' => true]);
$table->addString('title');
$table->addTimestamps();

// Define the foreign key
$table->addForeign('user_id', [
'references' => 'id',
'on' => 'users',
'onDelete' => 'CASCADE',
'onUpdate' => 'CASCADE'
]);
});

Indexes​

$this->alter('users', function (Table $table) {
$table->addIndex('email');
});

UNIQUE constraint​

$this->alter('users', function (Table $table) {
$table->addUnique('email');
});

Dropping a constraint (rollback)​

To undo constraints β€” useful in the rollback() method:

$this->alter('posts', function (Table $table) {
$table->dropForeign('user_id'); // or an array of columns
$table->dropIndex('idx_title');
$table->dropUnique('email');
$table->dropPrimary();
});
MethodDescription
dropForeign($name)Drops a foreign key (string or array)
dropIndex($name)Drops an index
dropUnique($name)Drops a UNIQUE constraint
dropPrimary()Drops the primary key

Complete example​

use Bow\Database\Migration\Migration;
use Bow\Database\Migration\Table;

class Version20240101120000CreateBlogTables extends Migration
{
public function up(): void
{
// Categories table
$this->create("categories", function (Table $table) {
$table->addIncrement('id');
$table->addString('name');
$table->addString('slug', ['unique' => true]);
$table->addTimestamps();
});

// Posts table
$this->create("posts", function (Table $table) {
$table->withEngine('InnoDB');
$table->withCharset('utf8mb4');

$table->addIncrement('id');
$table->addInteger('category_id', ['unsigned' => true]);
$table->addInteger('author_id', ['unsigned' => true]);
$table->addString('title');
$table->addString('slug', ['unique' => true]);
$table->addText('content');
$table->addEnum('status', ['size' => ['draft', 'published', 'archived']]);
$table->addBoolean('featured', ['default' => false]);
$table->addTimestamps();
$table->addSoftDelete();

$table->addForeign('category_id', [
'references' => 'id',
'on' => 'categories',
'onDelete' => 'CASCADE'
]);

$table->addForeign('author_id', [
'references' => 'id',
'on' => 'users',
'onDelete' => 'CASCADE'
]);

$table->addIndex('status');
});
}

public function rollback(): void
{
$this->dropIfExists("posts");
$this->dropIfExists("categories");
}
}

Is something missing?

If you run into problems with the documentation or have suggestions to improve the documentation or the project in general, please open an issue for us, or send a tweet mentioning the Twitter account @bowframework or directly on github.