"Ready-to-eat" Codeigniter 3 migrations

Create database migrations in Codeigniter 3 easily using a command line interface.

View source code on Github

Refinery is a console-based package of Migrations Class for the Codeigniter 3. It uses the Describe package for retrieving the database tables for creating database migrations.

Installation

From an existing Codeigniter 3 project, the Refinery package can be installed through Composer:

$ composer require rougin/refinery --dev
// ciacme/composer.json

{
  // ...

  "require-dev":
  {
    "mikey179/vfsstream": "1.6.*",
    "phpunit/phpunit": "4.* || 5.* || 9.*",
    "rougin/refinery": "~0.4"
  }
}

Then configure the project's database connectivity settings:

// ciacme/application/config/database.php

// ...

$db['default'] = array(
    'dsn'   => '',
    'hostname' => 'localhost',
    'username' => '',
    'password' => '',
    'database' => '',
    'dbdriver' => 'mysqli',

    // ...
);

[!NOTE] Although using database connection is not required in using Refinery, this is only applicable when creating migration files based on an existing database. Please see Creating from database below for its usage.

Basic Usage

Creating migration files

To create a new database migration, kindly run the create command:

$ vendor/bin/refinery create create_users_table
[PASS] "20241019044009_create_users_table.php" successfully created!
// ciacme/application/migrations/20241019044009_create_users_table.php

use Rougin\Refinery\Migration;

class Migration_create_users_table extends Migration
{
    /**
     * @return void
     */
    public function up()
    {
        $data = array('id' => array());
        $data['id']['type'] = 'integer';
        $data['id']['auto_increment'] = true;
        $data['id']['constraint'] = 10;
        $this->dbforge->add_field($data);
        $this->dbforge->add_key('id', true);

        $this->dbforge->create_table('users');
    }

    /**
     * @return void
     */
    public function down()
    {
        $this->dbforge->drop_table('users');
    }
}

[!NOTE]

When creating database migrations, Refinery will try to guess the expected output of up and down methods of a migration file based on its name (e.g., add_name_in_users_table):

$ vendor/bin/refinery create add_name_in_users_table
"20241019044035_add_name_in_users_table.php" has been created.
// ciacme/application/migrations/20241019044035_add_name_in_users_table.php

use Rougin\Refinery\Migration;

class Migration_add_name_in_users_table extends Migration
{
    /**
     * @return void
     */
    public function up()
    {
        $data = array('name' => array());
        $data['name']['type'] = 'varchar';
        $data['name']['auto_increment'] = false;
        $data['name']['constraint'] = 100;
        $data['name']['default'] = null;
        $data['name']['null'] = true;
        $data['name']['unsigned'] = false;
        $this->dbforge->add_column('users', $data);
    }

    /**
     * @return void
     */
    public function down()
    {
        $this->dbforge->drop_column('users', 'name');
    }
}

Please see the accepted keywords below when creating database migration files:

KeywordDescriptionExample
addAdds new column to a tableadd_name_in_users_table
createCreates new table with id as the primary keycreate_users_table
deleteDeletes a column from a tabledelete_name_in_users_table
modifyUpdates a column of a tablemodify_name_in_users_table

Running the migrations

Kindly use the migrate command to use the files for database migrations:

$ vendor/bin/refinery migrate
[INFO] Migrating "create_users_table"...
[PASS] "create_users_table" migrated!
[INFO] Migrating "add_name_in_users_table"...
[PASS] "add_name_in_users_table" migrated!

When running this command, the target timestamp (--target) will always be the latest file in the migrations directory if not specified (e.g., add_name_in_users_table). Use the --target option to migrate to a specific version:

$ vendor/bin/refinery migrate --target=20241019044009
[INFO] Migrating "create_users_table"...
[PASS] "create_users_table" migrated!

To rollback a database, kindly use the rollback command:

$ vendor/bin/refinery rollback
[INFO] Rolling back "add_name_in_users_table"...
[PASS] "add_name_in_users_table" rolled back!

[!NOTE] Without a --target option, the rollback will only revert to its previous version (e.g., create_users_table).

To reset back the database schema to version 0, the reset command can be used:

$ vendor/bin/refinery migrate
[INFO] Migrating "add_name_in_users_table"...
[PASS] "add_name_in_users_table" migrated!

$ vendor/bin/refinery reset
[INFO] Rolling back "add_name_in_users_table"...
[PASS] "add_name_in_users_table" rolled back!
[INFO] Rolling back "create_users_table"...
[PASS] "create_users_table" rolled back!

Creating from database

Refinery also allows to create a database migration based on the existing database table. Prior in creating its database migration, kindly ensure that the specified table already exists in the database schema:

CREATE TABLE IF NOT EXISTS `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

After checking the database table exists, run the same create command with the --from-database option:

$ vendor/bin/refinery create create_users_table --from-database
"20241019044729_create_users_table.php" has been created.
// ciacme/application/migrations/20241019044729_create_users_table.php

use Rougin\Refinery\Migration;

class Migration_create_users_table extends Migration
{
    /**
     * @return void
     */
    public function up()
    {
        $data = array('id' => array());
        $data['id']['type'] = 'integer';
        $data['id']['auto_increment'] = true;
        $data['id']['constraint'] = 10;
        $this->dbforge->add_field($data);
        $this->dbforge->add_key('id', true);

        $data = array('name' => array());
        $data['name']['type'] = 'varchar';
        $data['name']['auto_increment'] = false;
        $data['name']['constraint'] = 100;
        $data['name']['default'] = null;
        $data['name']['null'] = true;
        $data['name']['unsigned'] = false;
        $this->dbforge->add_field($data);

        $this->dbforge->create_table('users');
    }

    /**
     * @return void
     */
    public function down()
    {
        $this->dbforge->drop_table('users');
    }
}

[!NOTE] The --from-database option only exists when creating files under the create_*_table prefix.

Creating sequential migrations

By default, Refinery uses a timestamp prefix as its numbering style when creating migration files. To change it to a sequential numbering, kindly update the value of migration_type in the config/migration.php to sequential:

// ciacme/application/config/migration.php

/*
|--------------------------------------------------------------------------
| Migration Type
|--------------------------------------------------------------------------
|
| Migration file names may be based on a sequential identifier or on
| a timestamp. Options are:
|
|   'sequential' = Sequential migration naming (001_add_blog.php)
|   'timestamp'  = Timestamp migration naming (20121031104401_add_blog.php)
|                  Use timestamp format YYYYMMDDHHIISS.
|
| Note: If this configuration value is missing the Migration library
|       defaults to 'sequential' for backward compatibility with CI2.
|
*/
$config['migration_type'] = 'sequential';

Then run the create command to generate a migration file in sequential migration:

$ vendor/bin/refinery create create_users_table
[PASS] "001_create_users_table.php" successfully created!

Alternatively, the --sequential option can also be added in the create command to update the said configuration:

$ vendor/bin/refinery create add_name_in_users_table --sequential
[PASS] "002_add_name_in_users_table.php" successfully created!

[!NOTE] When using the --sequential option, the migration_type in the config/migration.php is also set as sequential.

Using refinery.yml

Refinery currently works out of the box after the configuration based on Installation. However, using a refinery.yml can be used for complex setups like specifying the new application path:

# refinery.yml

app_path: %%CURRENT_DIRECTORY%%

To create a refinery.yml, simply run the initialize command:

$ vendor/bin/refinery initialize
[PASS] "refinery.yml" added successfully!

[!NOTE] %%CURRENT_DIRECTORY%% is a placeholder variable which is the current directory of refinery.yml.

app_path

This property specifies the application directory. It may updated to any directory (e.g., ciacme/application, ciacme/config, etc.) as long it can detect the config/config.php file from the defined directory:

# refinery.yml

app_path: %%CURRENT_DIRECTORY%%/Sample

# ...

[!NOTE] Refinery will try to check the path specified in app_path if it is a valid Codeigniter 3 project. Then it will perform another check if the application directory exists or if the config directory can be accessed directly from the directory defined in app_path.