一般的程式設計師設計資料庫常常會使用 PHPMyAdmin 或者是一些軟體直接在 DB 上做表單的建立或管理,一個人的專案可能還 ok,但如果遇到 co-work,或者是測試機與正式機不同機器,很難避免粗心漏掉內容的問題,最好的解決方案就是用程式產生相關的內容,PHP 兩個熱門的框架 Laravel 以及 CodeIgniter 都有提供 Database Migration 的功能,今天來初探 CodeIgniter 的 Migration 部分。
CodeIgniter 所有 Migration 的內容只要看過上面兩個連結就可以做完,讓我們來 step by step 案例。
前置作業
application/config/migration.php
這個檔案是設定 migration config 的位置,有幾個重點要設定
$config['migration_enabled'] = true;
將 miagration_enabled
的部分開啟。
$config['migration_type'] = 'sequential';
修改 migration_type
為 sequential
,看個人習慣,這個設定是指 migration 的檔案取名方式,如果是 timestamp
檔名取法則用日期當做順序,例: 20121031104401_add_blog.php
,而 sequential
的話就是按照檔名排序,例:001_add_blog.php
,其他設定如 miagration 資料夾位置,這邊我用 default,所以我們建立一個目錄 application/migrations/
。
實做
application/migrations/001_create_users_table.php
class Migration_Create_users_table extends CI_Migration
{
public function up()
{
$this->dbforge->add_field([
'id' => [
'type' => 'int',
'unsigned' => true,
'auto_increment' => true,
],
'username' => [
'type' => 'varchar',
'constraint' => 50,
],
'password' => [
'type' => 'varchar',
'constraint' => 50,
],
'gender' => [
'type' => 'tinyint',
'constraint' => 1
],
'created_at' => [
'type' => 'datetime'
],
'updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW()'
]);
$this->dbforge->add_key('id', true);
$this->dbforge->create_table('users');
}
public function down()
{
$this->dbforge->drop_table('users');
}
}
class name 一定要是 Migration_
加上字首大寫並且去掉序列的檔名,不然不會動,up
是建立的部分,down
則是給 rollback 用的,所以我們這邊的 up
是 create 某個 table 的話,down
就是 drop 某個 table,以此類推,add_key
的部分有加 true
會是 primary key,沒有的話就是一般的 index,基本上欄位的設定就是把 sql 的欄位建立方式填進去並且給值,constraint
不給的話預設會是最大,如果在 MySQL 裡面試是非題的話就是用 true
false
給值,像是 null => false
則預設不能 null,如果沒下的話預設值看 MySQL 怎麼設定。
application/controllers/Migrate.php
class Migrate extends CI_Controller
{
public function start()
{
$this->load->library('migration');
if ($this->migration->latest() === false) {
echo $this->migration->error_string();
} else {
echo 'migrated'.PHP_EOL;
}
}
}
我們建立一個 controller 來執行 migration,網路上有很多方法可以讓這個 controller 只能透過 cli 執行,但我實際跑過,如果你是下 $this->migration->latest()
的話,從 browser 重複執行並不會影響建構好的 table,所以我是沒有打算放,而且客戶常常都只有給 FTP 哪有辦法走 cli 模式。
建立完畢後我在本機的 cli 跑 php index.php migrate start
得到:
"chan" Sid: S-1-5-21-759891990-2490853520-3465201229-1000
migrated
打開資料庫看得到了 migrations
以及 users
table,這樣就是順利完成了,接下來我們來模擬幾個場景。
application/migrations/002_add_ip_to_users_table.php
class Migration_Add_ip_to_users_table extends CI_Migration
{
public function up()
{
$field = [
'ip' => [
'type' => 'varchar',
'constraint' => 100,
'null' => false,
]
];
$this->dbforge->add_column('users', $field, 'password');
}
public function down()
{
$this->dbforge->drop_column('users', 'ip');
}
}
這個場景就是在 users
裡面增加一個欄位,add_column
的第三個欄位等於 MySQL 的 after
。
application/migrations/003_drop_gender_from_users_table
class Migration_Drop_gender_from_users_table extends CI_Migration
{
public function up()
{
$this->dbforge->drop_column('users', 'gender');
}
}
從 users
table 移掉 gender
這個 column。
004_modify_password_from_users_table.php
class Migration_Modify_password_from_users_table extends CI_Migration
{
public function up()
{
$field = [
'password' => [
'name' => 'password',
'type' => 'varchar',
'constraint' => 100,
]
];
$this->dbforge->modify_column('users', $field);
}
}
將 password
的長度增加到 100,在 MySQL 如果要改一個欄位的內容 alter
的語法你必須把其他欄位設定都在打一次,所以不要只有打 'constraint' => 100
而已,這樣會出事。