2015/10/07

CodeIgniter Migration

一般的程式設計師設計資料庫常常會使用 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_typesequential,看個人習慣,這個設定是指 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 而已,這樣會出事。

沒有留言: