Belajar Yii - Migrations & Database
Episode 6 of 27

Belajar Yii - Migrations & Database

Mengelola skema database sebagai kode yang bisa di-versioning lewat migration Yii: membuat dan mengubah tabel dengan createTable dan addColumn, pola up()/down() yang reversibel, menjalankan migrasi di berbagai environment, serta praktik seeding data awal untuk pengembangan dan production.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

Di episode 5 kalian sudah memakai posts dan comments sebagai tabel — tapi dari mana tabel itu lahir? Di banyak project, jawabannya "dibuat manual di phpMyAdmin", dan di situlah awal masalah: tidak ada jejak, tidak bisa di-replay, tidak konsisten antar developer.

Migrations menyelesaikan masalah ini dengan memperlakukan skema database seperti source code: setiap perubahan skema adalah file ber-version yang bisa di-commit, di-review, dan dijalankan ulang di environment mana pun. Di episode ini kita belajar membuat dan mengubah tabel lewat migration, menjalankannya dengan yii migrate, dan menyiapkan data awal untuk pengembangan.

Mengapa Skema Harus Menjadi Kode

Bayangkan tiga developer bekerja di fitur yang sama. Developer A menambah kolom slug di tabel posts manual. Developer B memakai posts tapi tanpa kolom itu. Developer C bingung mengapa migration production gagal. Inilah biang kerok kekacauan — dan migrations adalah solusinya:

  • Versionable: setiap perubahan punya file sendiri yang bisa di-review di pull request.
  • Replayable: yii migrate bisa dijalankan berulang dari nol di environment baru.
  • Reversible: kebanyakan perubahan bisa di-rollback lewat yii migrate/down.
  • Auditable: tabel migration mencatat migrasi mana yang sudah dijalankan.

Analoginya: migrations adalah git untuk skema database. Kalian tidak lagi bertanya "tabel ini dari mana?", melainkan membuka history migrasi dan melihat jawabannya.

Membuat Migration Pertama

Membuat file migration
php yii migrate/create create_posts_table

Perintah ini membuat file migrations/mYYYYMMDDHHMMSS_create_posts_table.php. Pola nama create_..._table dikenali Yii: migration akan otomatis memanggil dropTable pada method down() — pola yang menghemat pekerjaan.

migrations/m..._create_posts_table.php
<?php
 
use yii\db\Migration;
 
class m20260816120000_create_posts_table extends Migration
{
    public function safeUp(): void
    {
        $this->createTable('posts', [
            'id' => $this->primaryKey(),
            'title' => $this->string(255)->notNull(),
            'slug' => $this->string(255)->notNull()->unique(),
            'body' => $this->text(),
            'status' => $this->string(16)->notNull()->defaultValue('draft'),
            'user_id' => $this->integer()->notNull(),
            'created_at' => $this->timestamp()->defaultExpression('CURRENT_TIMESTAMP'),
            'updated_at' => $this->timestamp()->defaultExpression('CURRENT_TIMESTAMP'),
        ]);
 
        $this->addForeignKey(
            'fk-posts-user_id',
            'posts',
            'user_id',
            'users',
            'id',
            'CASCADE',
            'CASCADE'
        );
    }
 
    public function safeDown(): void
    {
        $this->dropTable('posts');
    }
}

Perhatikan gaya penulisan: safeUp()/safeDown() membungkus semua operasi dalam transaksi — jika satu statement gagal, seluruhnya di-rollback. Ini wajib dipakai, bukan up()/down() biasa. Daftar method yang sering dipakai:

MethodFungsi
createTable / dropTableMembuat / menghapus tabel
addColumn / dropColumnMenambah / menghapus kolom
alterColumnMengubah tipe atau constraint kolom
createIndex / dropIndexIndeks biasa dan unik
addForeignKey / dropForeignKeyForeign key
insert / updateData awal / perbaikan data

Menjalankan Migrasi

Perintah migrasi inti
php yii migrate/up        # jalankan migrasi yang belum dijalankan
php yii migrate/down 1    # rollback 1 langkah terakhir
php yii migrate/redo      # rollback lalu jalankan ulang migrasi terakhir
php yii migrate/up 5      # jalankan sampai migrasi ke-5 dari yang tersisa
php yii migrate/history   # lihat riwayat

Jalankan migrasi pertama kalian:

Jalankan migrasi
php yii migrate/up --interactive=0

--interactive=0 mematikan prompt konfirmasi — penting untuk otomasi (episode 22). Tabel migration di database akan mencatat file yang sudah dijalankan, sehingga yii migrate/up hanya menjalankan yang baru.

Warning

Satu aturan emas: jangan pernah mengubah migration yang sudah dijalankan di production. Migration adalah riwayat — mengeditnya akan membuat down/redo tidak konsisten dan state production menyimpang dari kode. Jika butuh perubahan, buat migration baru. Ini juga alasan mengapa safeDown() penting ditulis dengan benar sejak awal.

Mengubah Skema dengan Migration Baru

Menambah kolom bukan berarti mengubah migration lama — buat migration baru:

Migration baru untuk kolom baru
php yii migrate/create add_read_count_to_posts_table
migrations/m..._add_read_count_to_posts_table.php
<?php
 
use yii\db\Migration;
 
class m20260816123000_add_read_count_to_posts_table extends Migration
{
    public function safeUp(): void
    {
        $this->addColumn('posts', 'read_count', $this->integer()->notNull()->defaultValue(0));
        $this->createIndex('idx-posts-read_count', 'posts', 'read_count');
    }
 
    public function safeDown(): void
    {
        $this->dropColumn('posts', 'read_count');
    }
}

Pola ini — migration sekecil mungkin dengan satu tujuan — membuat riwayat skema mudah dibaca dan mudah di-review.

Seeding Data

Migrations juga bisa mengisi data, tapi sebaiknya dipisahkan: migrasi untuk skema, dan data awal untuk kebutuhan pengembangan. Ada dua pendekatan umum.

Pertama, insert di dalam migration ketika data itu memang prasyarat sistem (misal role admin):

Menyisipkan data wajib di migration
public function safeUp(): void
{
    $this->insert('users', [
        'username' => 'admin',
        'password_hash' => Yii::$app->security->generatePasswordHash('rahasia-sementara'),
    ]);
}

Kedua, seeder terpisah untuk data dummy pengembangan — misalnya console command:

commands/SeedController.php
<?php
 
namespace app\commands;
 
use app\models\Post;
use yii\console\Controller;
 
class SeedController extends Controller
{
    public function actionPosts(int $count = 10): int
    {
        for ($i = 1; $i <= $count; $i++) {
            $post = new Post([
                'title' => "Post percobaan #$i",
                'slug' => "post-percobaan-$i",
                'body' => str_repeat('Konten contoh untuk praktik migrations. ', 10),
                'status' => 'published',
            ]);
            $post->save();
        }
        $this->stdout("OK: $count posts dibuat\n");
        return self::EXIT_CODE_NORMAL;
    }
}

Jalankan dengan php yii seed/posts 25 — data dummy tersedia tanpa mencemari migration. Di episode 16 kita lihat pendekatan yang lebih rapi dengan fixtures untuk keperluan testing.

Konfigurasi Multi-Database

Migration default memakai koneksi db. Untuk project yang punya database terpisah (misal db dan db_admin), daftarkan keduanya di config/console.php:

config/console.php - multiple database
'db' => [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=app_main',
    'username' => 'root',
    'password' => '',
],
'db_admin' => [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=app_admin',
    'username' => 'root',
    'password' => '',
],
'migrationNamespaces' => [
    'app\migrations',
    'app\migrations\admin',
],

migrationNamespaces memungkinkan migration ditempatkan di namespace berbeda (misal folder migrations/admin/ khusus database admin). Konsol menjalankannya dengan --db=db_admin:

Migrasi ke database tertentu
php yii migrate/up --db=db_admin

Penutup

Inti yang harus dibawa pulang:

  • Migration = skema sebagai kode: versionable, replayable, reversible, auditable.
  • Selalu pakai safeUp()/safeDown() agar perubahan dibungkus transaksi.
  • Setiap perubahan skema adalah migration baru — jangan edit migration lama.
  • Pisahkan data wajib (di migration) dan data dummy (di seeder).
  • Multi-database dikelola lewat --db dan migrationNamespaces.

Di episode 7 selanjutnya, kita membangun lapisan interaksi: forms, validation & widgetsActiveForm yang menghubungkan form HTML dengan model dan rules-nya, penanganan error yang konsisten, serta widget GridView dan DetailView yang mengubah query menjadi tabel dan detail halaman dengan sangat sedikit kode. Sampai jumpa di episode 7!

Belajar Yii - Migrations & Database | Belajar Yii