本文首發(fā)于 https://jaychen.cc
作者 JayChen
這是一篇基礎(chǔ)教程淋淀,對標(biāo) Laravel 文檔中的數(shù)據(jù)遷移和數(shù)據(jù)填充袒炉。
migration
Laravel 中提供了數(shù)據(jù)庫遷移的方式來管理數(shù)據(jù)庫冶共,想象一個(gè)場景:在一個(gè)多人開發(fā)的項(xiàng)目中,你的同事修改了某個(gè)數(shù)據(jù)庫結(jié)構(gòu)并修改了代碼抡锈,通過 git 你可以即時(shí)的同步同事修改的代碼渡紫,但是數(shù)據(jù)庫結(jié)構(gòu),你只能通過手工的方式來復(fù)制同事修改的 SQL 語句凤粗,執(zhí)行以保證數(shù)據(jù)庫的結(jié)構(gòu)一致酥泛。那么,Laravel 中的數(shù)據(jù)庫遷移概念嫌拣,就是用于解決團(tuán)隊(duì)中保證數(shù)據(jù)庫結(jié)構(gòu)一致的方案柔袁。
migration 使用非常簡單,編寫一定的 php 代碼并執(zhí)行亭罪,那么 Laravel 就會(huì)自動(dòng)的更新數(shù)據(jù)庫瘦馍。假設(shè)你的同事要修改數(shù)據(jù)庫某個(gè)字段,那么只要編寫 php 代碼应役,接著你通過 git 更新了代碼情组,執(zhí)行 migrate 操作之后燥筷,你的數(shù)據(jù)庫結(jié)構(gòu)就和他的同步了。下面我們就來看具體的使用方法院崇。
migrate
Laravel 把編寫數(shù)據(jù)庫改動(dòng)的 php 代碼稱為遷移肆氓,可以通過 php artisan make:migration filename
的方式來創(chuàng)建遷移文件。假設(shè)你需要?jiǎng)?chuàng)建一張新的 user 表底瓣,那么你可以通過執(zhí)行 php artisan make:migration create_user_table --create=user
來創(chuàng)建一個(gè)遷移文件谢揪,執(zhí)行命令會(huì)在 database/migrations/
目錄下建立一個(gè) 文件創(chuàng)建時(shí)間_filename
的 php 文件,那么這個(gè)文件就是我們接下來用來編寫數(shù)據(jù)庫結(jié)構(gòu)變化的文件了捐凭。這里要提一點(diǎn)拨扶,雖然說創(chuàng)建遷移文件的名稱可以隨意,但是為了管理方便茁肠,最好文件名可以體現(xiàn)要執(zhí)行的數(shù)據(jù)庫操作患民,比如這里我們要?jiǎng)?chuàng)建一張 user 表,所以文件名稱為 create_user_table
垦梆。
php artisan make:migration filename
有兩個(gè)可選參數(shù)
-
--create=tablename
表明該遷移是用來創(chuàng)建表匹颤。 -
--table=tablename
表明該遷移是用來對 tablename 這張表進(jìn)行操作。
我們創(chuàng)建出來的遷移文件 create_user_table
會(huì)包含兩個(gè)方法托猩。
public function up()
{
Schema::create('user', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('user');
}
這兩個(gè)方法是互逆的操作印蓖,比如我們可以再 up
方法中編寫我們要?jiǎng)?chuàng)建的 user 表的相關(guān)信息,而 down
方法中則是刪除 user 表的操作京腥。這樣赦肃,我們就可以做到回滾操作,當(dāng)我們創(chuàng)建 user 表之后發(fā)現(xiàn)某個(gè)字段名寫錯(cuò)了绞旅,就可以通過 down
來刪除 user 表摆尝,進(jìn)而重新建立 user 表。
假設(shè) user 表有 id,username,email
三個(gè)字段因悲,那么可以再 up 方法中寫
public function up()
{
Schema::create('user', function (Blueprint $table) {
$table->increments('id')->index()->comment('用戶id');
$table->string('name')->default('')->comment('用戶名');
$table->string('email')->nullable()->comment('用戶郵箱');
$table->timestamps();
});
}
一般,我們的邏輯會(huì)在閉包函數(shù)中寫勺爱。上面的代碼晃琳,即時(shí)不能完全明白,也可以大概猜出以下幾點(diǎn):
- 我們操作的表是 user 表琐鲁。
- user 表中定義了 id 字段卫旱,因?yàn)檎{(diào)用了
increments
方法,所以 id 為auto_increment
围段,調(diào)用了index
方法說明給 id 添加了索引顾翼,最后comment
等同于注釋。 - 有了 id 的經(jīng)驗(yàn)奈泪,那么 name 字段也很好理解了适贸,
string
方法說明 name 是varchar/char
類型的灸芳,default
定義了 name 字段的默認(rèn)值。 - email 字段 調(diào)用了
nullable
方法說明運(yùn)行 email 字段為空拜姿。 - 定義字段結(jié)構(gòu)的時(shí)候可以使用鏈?zhǔn)秸{(diào)用的方式烙样。
Laravel 中的方法是滿足你對 sql 語句的所有操作,如果你需要定義一個(gè)類型為 text 的字段蕊肥,那么可以調(diào)用 text()
方法谒获,更多的方法說明可以參見文檔 Laravel 數(shù)據(jù)庫結(jié)構(gòu)構(gòu)造器。
我們已經(jīng)編寫好了 user 表的結(jié)構(gòu)壁却,接下來執(zhí)行 php artisan migrate
批狱,Laravel 會(huì)根據(jù) create
方法自動(dòng)為我們創(chuàng)建 user 表。至此展东,我們已經(jīng)成功的通過 Larvel 的遷移功能來實(shí)現(xiàn)創(chuàng)建表赔硫。
Rollback
使用 Laravel 的遷移功能可以有后悔藥吃。
執(zhí)行 php artisan migrate
創(chuàng)建 user 表之后琅锻,覺得不行卦停,不要 user 這張表,于是你打算刪除這張表恼蓬。那么這時(shí)候我們就要使用剛剛說到的 down
方法了惊完。
public function down()
{
Schema::dropIfExists('user');
}
這里 Laarvel 已經(jīng)為我們寫好邏輯了,dropIfExists
函數(shù)就是用來刪除表处硬,我們只需要執(zhí)行 php artisan migrate :rollback
就可以回滾到執(zhí)行 php artisan migrate
之前的狀態(tài)小槐。
重命名表
除了創(chuàng)建表,也可以用遷移記錄表的其他任何操作荷辕,包括修改表屬性凿跳,修改字段等等操作。這里再舉個(gè)例子說明如何用遷移來對表進(jìn)行重命名疮方。
- 假設(shè)有表 user控嗜,我們需要對它重命名為 users。首先要執(zhí)行
php artisan make:migration rename_user_to_users --table user
來創(chuàng)建遷移文件骡显。 - 在
up
方法中寫我們要重命名表的邏輯疆栏。
public function up()
{
Schema::table('user', function (Blueprint $table) {
Schema::rename('user','users');
});
}
- 為了可以 rollback 可以順利執(zhí)行,我們還需要在
down
方法中編寫撤銷重命名操作的邏輯惫谤。
public function up()
{
Schema::table('user', function (Blueprint $table) {
//
Schema::rename('users','user');
});
}
- 最后執(zhí)行
php artisan migrate
就就可以完成對 user 表的重命名操作壁顶。如果需要回滾,只要執(zhí)行php artisan migrate:rollback
溜歪。
你會(huì)發(fā)現(xiàn)若专,如果執(zhí)行一次遷移之后,如果執(zhí)行第二次遷移是不會(huì)重復(fù)執(zhí)行的蝴猪,這是因?yàn)?Laravel 會(huì)在數(shù)據(jù)庫中建立一張 migrations
的表來記錄哪些已經(jīng)進(jìn)行過遷移调衰。
基本的 migration 介紹就到這里膊爪,以上的內(nèi)容可以應(yīng)對大部分的需求,如果需要更詳細(xì)的介紹窖式,可能需要閱讀 Laravel 那不知所云的文檔了蚁飒。:)
Seeder
Laravel 中除了 migration 之外,還有一個(gè) seeder 的東西萝喘,這個(gè)東西用于做數(shù)據(jù)填充淮逻。假設(shè)項(xiàng)目開發(fā)中需要有一些測試數(shù)據(jù),那么同樣可以通過編寫 php 代碼來填充測試數(shù)據(jù)阁簸,那么通過 git 同步代碼爬早,所有的人都可以擁有一份同樣的測試數(shù)據(jù)。
同樣启妹,數(shù)據(jù)填充在 Laravel 中被稱為 Seeder筛严,如果需要對某張表填充數(shù)據(jù),需要先建立一個(gè) seeder饶米。通過執(zhí)行 php artisan make:seeder UserTableSeeder
來生成一個(gè) seeder 類桨啃。這里我們希望填充數(shù)據(jù)的表示 test 表,所以名字為 UserTableSeeder
檬输。當(dāng)然這個(gè)名字不是強(qiáng)制性的照瘾,只是為了做到見名知意。
創(chuàng)建 UserTableSeeder 之后會(huì)在 database/seeders
目錄下生成一個(gè) UserTableSeeder
類丧慈,這個(gè)類只有一個(gè) run 方法析命。你可以在 run
方法中寫插入數(shù)據(jù)庫的代碼。假設(shè)我們使用 DB facade 來向 test 表插入數(shù)據(jù)逃默。
class UserTableSeeder extends Seeder
{
public function run()
{
DB::table('users')->insert($insertData);
}
}
編寫完代碼之后鹃愤,執(zhí)行 php artsian db:seeder --class= UserTableSeeder
來進(jìn)行數(shù)據(jù)填充。執(zhí)行完畢之后查看數(shù)據(jù)庫已經(jīng)有數(shù)據(jù)了完域。
如果我們有多個(gè)表要進(jìn)行數(shù)據(jù)填充软吐,那么不可能在編寫完 php 代碼之后,逐個(gè)的執(zhí)行 php artisan db:seeder --class=xxxx
來進(jìn)行填充吟税。有一個(gè)簡便的方法关噪。在 DatabaseSeeder
的 run
方法中添加一行 $this->call(UserTableSeeder::class);
,然后執(zhí)行 php artisan db:seeder
乌妙,那么 Laravel 就會(huì)執(zhí)行 DatabaseSeeder
中的 run
方法,然后逐個(gè)執(zhí)行遷移建钥。
和 migration 不同藤韵,如果多次執(zhí)行 php artisan db:seeder
就會(huì)進(jìn)行多次數(shù)據(jù)填充。
加入你想一次性插入大量的測試數(shù)據(jù) 熊经,那么在 run
方法中使用 DB facade 來逐個(gè)插入顯然不是一個(gè)好的方法泽艘。Laravel 中提供了一種模型工廠的方式來創(chuàng)建創(chuàng)建大量的數(shù)據(jù)欲险。
模型工廠
模型工廠,意味著本質(zhì)其實(shí)是一個(gè)工廠模式匹涮。那么天试,在使用模型工廠創(chuàng)建數(shù)據(jù)需要做兩件事情
- 創(chuàng)建工廠,定義好工廠要返回的數(shù)據(jù)然低。
- 調(diào)用工廠獲取數(shù)據(jù)喜每。
Laravel 中通過執(zhí)行 php artisan make:factory UserFactory --model=User
來為 User Model 創(chuàng)建一個(gè)工廠類,該文件會(huì)放在 database/factory
目錄下雳攘。打開該文件可以看到如下代碼:
$factory->define(App\User::class, function (Faker $faker) {
return [
//
];
});
這里带兜, return 的值就是我們第 2 步調(diào)用工廠獲取到的數(shù)據(jù)。生成數(shù)據(jù)的邏輯也只需要寫在閉包函數(shù)中就可以吨灭。這里需要提一下 Faker 這個(gè)類刚照。這是一個(gè)第三方庫,Laravel 集成了這個(gè)第三方庫喧兄。這個(gè)庫的作用很好玩:用于生成假數(shù)據(jù)无畔。假設(shè) User 表需要插入 100 個(gè)用戶,那么就需要 100 個(gè) username吠冤,那么你就不必自己寫邏輯生成大量的 test01浑彰,test02 這樣子幼稚的假數(shù)據(jù),直接使用 Faker 類咨演,會(huì)替你生成大量逼真的 username闸昨。(我也不知道這個(gè)算不算無聊了 :)。薄风。饵较。)。
現(xiàn)在假設(shè) User 表有 id, email, username 三個(gè)字段遭赂,那么我要生成 100 個(gè)用戶循诉,首先在工廠類中實(shí)現(xiàn)邏輯。
$factory->define(App\Models\User::class, function (Faker $faker) {
return [
// 直接調(diào)用 faker API 生成假數(shù)據(jù)撇他,更多 faker 相關(guān)查看 文檔茄猫。
'username' => $faker->name,
'email' => $faker->unique()->safeEmail,
];
});
現(xiàn)在,我們已經(jīng)定義好了工廠困肩,現(xiàn)在我們就要在 UserSeeder@run
函數(shù)中使用模型工廠來生成測試數(shù)據(jù)划纽。
class UserTableSeeder extends Seeder
{
public function run()
{
factory(App\User::class)->times(10)->make()->each(function($user,$index){
$user->save();
});
}
}
run
函數(shù)中這一波行云流水的鏈?zhǔn)秸{(diào)用在我剛剛開始接觸 Laravel 的時(shí)候也是一臉黑線,不過習(xí)慣之后感覺這代碼可讀性確實(shí)很強(qiáng)
-
factory(App\User::class)
指明返回哪個(gè)工廠锌畸,參數(shù)App\User::class
就是工廠的唯一標(biāo)識(shí)勇劣。這里我們在定義工廠的時(shí)候define
的第一個(gè)參數(shù)已經(jīng)指明了。 -
->times(10)
指明需要工廠模式生成 10 個(gè) User 數(shù)據(jù)。即會(huì)調(diào)用 10 次define
函數(shù)的第二個(gè)參數(shù)比默。 -
->make()
把生成的 10 個(gè) User 數(shù)據(jù)封裝成 Laravel 中的集合對象幻捏。 -
->each()
是 Laravel 集合中的函數(shù),each
函數(shù)會(huì)針對集合中的每個(gè)元素進(jìn)行操作命咐。這里直接把數(shù)據(jù)保存到數(shù)據(jù)庫篡九。
好了,數(shù)據(jù)遷移和數(shù)據(jù)填充的基本操作也就這些了醋奠。更多復(fù)雜的用法榛臼。。钝域。讽坏。也不一定能用上。