Migration giống như version control cho db. Facade Schema cung cấp hỗ trợ cho create, manipulate db. Migration sử dụng facade này để create, modify db.
Khởi tạo migrations:
Lệnh make:migration để khởi tạo db migration. Migration mới sẽ nằm trong thư mục database/migrations. Mỗi file sẽ bao gồm timestamp cho phép Laravel xác định thứ tự:
php artisan make:migration create_flights_tableLaravel sử dụng tên migration để thử đoán tên của table và liệu migration có cần tạo table mới không. Nếu Laravel có thể xác định được tên table, Laravel sẽ điền trước table vào file migrate được khởi tạo. Nếu không, bạn sẽ tự điền vào file.
Squash migration:
Trong khi build ứng dụng bạn có thể tích trữ nhiều migration. Việc này khiến thư mục database/migrations trở nên đầy. Bạn sẽ cần squash migration vào 1 file SQL. Sử dụng lệnh schema:dump.
php artisan schema:dump
# dump và cắt tỉa những migration tồn tại:
php artisan schema:dump --pruneKhi bạn chạy lệnh này, Laravel sẽ viết 1 file schema vào database/schema. Tên file sẽ tương ứng với db connection. Khi bạn thử migrate db và không có migration nào khác được thực thi, Laravel đầu tiên sẽ thực thi SQL trong schema. Sau đó sẽ thực thi những migration còn lại mà không thuộc schema dump.
Nếu ứng dụng test sử dụng 1 db connection khác local development, bạn nên chắc chắn dump 1 schema file sử dụng db connection này, nhờ vậy test của bạn mới build được db. Bạn có thể làm điều này sau khi đã dump db connection mà bạn đang sử dụng ở local dev:
php artisan schema:dump
php artisan schema:dump --database=testing --pruneBạn nên commit schema file lên source control để dev khác trong team có thể nhanh chóng tạo cấu trúc db ban đầu.
Cấu trúc migration:
Migration class có 2 method up và down. Method up sử dụng để thêm mới table, column, index db, trong khi method down sẽ đảo ngược hành động được thực thi bởi up. Với 2 method này bạn có thể sử dụng schema builder để tạo/sửa đổi table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::drop('flights');
}
};Cấu hình migrate connection:
Nếu migration đang tương tác với 1 db connection khác connection mặc định, sử dụng thuộc tính $connection:
/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';Chạy migrate:
php artisan migrateĐể xem migration nào sẽ chạy, sử dụng migrate:status.
Để xem lệnh SQL nào sẽ được thực thi bởi migration mà không thực sự chạy chúng, sử dụng --pretend:
php artisan migrate --pretendForce migrate trên môi trường production:
Một số migration có thể làm mất dữ liệu, cần confirm trước khi thực hiện bằng --force:
php artisan migrate --forceRoll back migrate:
Lệnh rollback sẽ quay trở lại “batch” cuối cùng, có thể bao gồm nhiều migration files:
php artisan migrate:rollbackBạn có thể rollback về trước 1 số migration sử dụng step:
php artisan migrate:rollback --step=5Rollback về 1 số batch:
php artisan migrate:rollback --batch=3Xem trước lệnh: --pretend:
php artisan migrate:rollback --pretendRollback toàn bộ migration:
php artisan migrate:resetRoll back toàn bộ và migrate:
php artisan migrate:refresh
# Refresh the database and run all database seeds...
php artisan migrate:refresh --seedRoll back và re-migrate 1 số nhất định:
php artisan migrate:refresh --step=5Table:
Tạo table:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});Check table/column tồn tại:
if (Schema::hasTable('users')) {
// The "users" table exists...
}
if (Schema::hasColumn('users', 'email')) {
// The "users" table exists and has an "email" column...
}DB connection và table options: thực thi 1 schema trên connection không phải là mặc định:
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});Tạo table với tùy chọn:
Schema::create('users', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
// add comment:
$table->comment('Business calculations');
// ...
});Update table:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});Đổi tên/drop table:
use Illuminate\Support\Facades\Schema;
Schema::rename($from, $to);
Schema::drop('users');
Schema::dropIfExists('users');Columns:
Tạo columns:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});Các column type có sẵn:
Tham khảo docs: https://laravel.com/docs/10.x/migrations#available-column-types
Column modify:
Ví dụ để set column “nullable”, sử dụng method nullable:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});Check docs: https://laravel.com/docs/10.x/migrations#column-modifiers
Default expressions:
Method default chấp nhận 1 giá trị hoặc 1 instance Illuminate\Database\Query\Expression. Sử dụng instance Expression sẽ ngăn Laravel bọc giá trị trong dấu nháy và cho phép bạn sử dụng những function của db. Một tình huống cụ thể hữu ích là khi bạn cần gán giá trị mặc định cho JSON columns:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
};Thứ tự column:
Sử dụng method after để add column vào sau 1 column đã có trong schema:
$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});Thay đổi column:
Method change cho phép bạn thay đổi type, thuộc tính của 1 column đã tồn tại. Ví dụ, bạn muốn tắng size của 1 string column:
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});Khi thay đổi column, bạn phải include rõ ràng những thay đổi bạn muốn giữ cho column – bất kỳ thuộc tính nào thiếu sẽ bị xóa bỏ. Ví dụ, để giữ lại unsigned, default, comment, bạn cần gọi tường minh mỗi modifier:
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});Thay đổi tên column:
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});Xóa column:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});Xóa nhiều column:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});Tạo index:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});Tạo index sau khi đã định nghĩa column:
$table->unique('email');Tạo index nhiều column:
$table->index(['account_id', 'created_at']);Các kiểu index:
primary: có thể nhận 1 column hoặc array nhiều column.unique: add unique.index: add index.fullText: add full text index.spatialIndex: add spatial index.
Index length & MySQL / MariaDB:
Mặc định Laravel set utf8mb4, nếu bạn chạy MySQL cũ hơn 5.7.7 hoặc MariaDB cũ hơn 10.2.2, bạn cần cấu hình string length mặc định được sinh ra bởi migrate. Gọi method Schema::defaultStringLength trong boot ở App\Providers\AppServiceProvider:
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Schema::defaultStringLength(191);
}Gỡ index:
dropPrimarydropUniquedropIndexdropFullTextdropSpatialIndex
Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // Drops index 'geo_state_index'
});Khóa ngoại:
Ví dụ user_id của table posts tham chiếu đến id của users:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});Hoặc cách viết khác:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});Method foreignId tạo 1 column tương đương UNSIGNED BIGINT, method constrained sử dụng quy ước để xác định table và column được tham chiếu. Nếu tên table không khớp quy ước, bạn có thể cung cấp bằng tay:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained(
table: 'users', indexName: 'posts_user_id'
);
});Thêm action “on delete” và “on update”:
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');Xóa foreign key:
$table->dropForeign('posts_user_id_foreign');