Migrations
When you are maintaining a software with database, it's obvious that you may need database changes.
You may create new tables
You may add new columns to existing tables
You may create new Objects
You may create new Object Specs for existing Objects
You may update Objects
You may update Object Specs
Migrations are placed in Migration folder for each Module. If you need Migrations for your App, than you can use Migrations in app/Migration folder.
There are two types of Migrations
Install
Install migrations run when the system is installed to a new database. Which means that, you can assume that, target database is empty when you add a new migration.
[!TIP] As an example: If you want to change name of a table, you can directly rename it if it already exists in Install script. Since Installation only runs for empty databases, it will not have a table with the previous name.
You can use the following command to run migrations:
bin/butterfly installGenerator
Install script aims to install an application from scratch. You may want to generate or update Install script with the following command:
bin/butterfly object:migration:createThis command will update app/Migration/Install.php with the migrations of all Data Types in the active database.
You can also filter table names
bin/butterfly object:migration:create --tables=users,faqswill generate migration for Data Type: users and faqs tables.
You may also use wildcards for table names
bin/butterfly object:migration:create --tables=user%will generate a single migration file with tables starting with user*.
Upgrade
Upgrade migrations should run after each deployment. Upgrade migrations make it easy to maintain structure of your Database. Besides creating new Tables, Objects, Indexes, you can also delete or update existing ones using Upgrades.
You can use the following command to run migrations:
bin/butterfly upgradeFor migrations not to run more than once, you can use version numbers. Butterfly uses semantic versioning to version the Modules. Version numbers are written in module.yaml files. For more information about Modules you can check Modules documentation
Example:
namespace App\Migration;
use Butterfly\Framework\Migration\Base;
class Upgrade extends Base
{
public function run()
{
if($this->currentVersionIsOlderThan('1.0.1'))
{
// Put some Migration Script code here
}
}
}Indexes
You can add Unique or Normal index to the Objects you have created.
Index
$response = db()->schema('my_new_table')->object(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->string('name');
$object->dropdown('user_id', 'User')
->parameters('users', 'name', 'id', '-')
->searchable()
->listColumn()
->readonly()
->index() // This will add index to column user_id
->required()
;
return $object;
});Unique Index
$response = db()->schema('my_new_table')->object(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->string('name');
$object->string('remote_user_id')->unique(); // This will add unique index to remote_user_id column
return $object;
});Multiple Columns
$response = db()->schema('my_new_table')->object(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->string('title');
$object->string('sub_title');
$object->unique(['title', 'sub_title']); // This will add unique index to title and sub_title columns together.
$object->index(['title', 'sub_title']); // This will add normal index to title and sub_title columns together.
return $object;
});App Specific Migrations
You can also use Migrations in app Folder. app is considered as a Module inside of the System. Which means that, you can update your modules version from app/module.yaml and you can write down Migration scripts in app/Migration/Install.php and app/Migration/Upgrade.php files.
Migration Scripts
Objects
Create or Update
Object Migrations works with upsert strategy. Which means that, when you write down a migration, if the target Object already exist, it will update the existing Object. If it doesn't exist, it will insert new Object.
[!WARNING] If you create a migration for an existing object and you don't define all of the existing Specs, it
won'tdelete existing Object Specs.
[!WARNING] Objects check existence with
table_name. If you want to rename an existing Object, then you can check Renaming Object Table Names section.
Example:
$response = db()->schema('my_new_table')->object(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->setDescription('Sample Description for Object');
$object->hasItem();
$object->hasTrash();
$object->hasOrder();
$object->setDatabaseAlias('test');
$object->setAutoIncrementColumnName('entity_id');
$object->setLinkFormat('%name%');
$object->string('name');
$object->integer('votes');
$object->integer('vote_count')->defaultValue(100);
$object->dropdown('user_id', 'User')
->parameters('users', 'name', 'id', '-')
->searchable()
->listColumn()
->readonly()
->required()
;
$object->datetimeMysql('created_at')->defaultValue(db()->raw('CURRENT_TIMESTAMP()'));
return $object;
});Defining Object Spec Position (Placement)
When creating additional Object Specs, you can choose the relative position of the newly created Object Spec.
Example:
db()->schema('my_new_table')->objectSpecs(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->integer('votes')->placeAfter('test');
$object->integer('vote_count')->defaultValue(100)->placeBefore('test_2');
return $object;
});will place votes Object Spec, after test column and will place vote_count Object Spec, before test_2 column.
[!WARNING] By default, new Object Specs are placed Left Side Bottom. If target Column Name is not found, Default rules are applied.
Creating Admin Menus for Objects
You can create admin menus while creating an Object using Migrations.
With Parent Menu
Example:
$response = db()->schema('my_new_table')->object(function(\Butterfly\Framework\Data\ButterflyObject $object) {
// This will create System Settings > Sub System Settings > My New Table
$object->setAdminParentMenu('System Settings', 'Sub System Settings');
// You can update Menu Title. If you don't call this function it will default to Object Name
$object->setAdminMenuTitle('My Menu Title');
return $object;
});Without Parent Menu
If you want to create a Main Menu to link to Object Listing Page, you can use the following example:
Example:
$response = db()->schema('my_new_table')->object(function(\Butterfly\Framework\Data\ButterflyObject $object) {
// This will create a Main Menu with title: My Menu Title
$object->setAdminMenuTitle('My Menu Title');
// If you don't set the first argument, it will default to Object Name
$object->setAdminMenuTitle(); // will create a menu with title: My New Table
return $object;
});Renaming Table Names
You can rename table names of existing Objects.
db()->schema('old_table_name')->object(function (\Butterfly\Framework\Data\ButterflyObject $butterflyObject) {
$butterflyObject->setName('Desired Object Name');
$butterflyObject->renameTable('new_table_name');
});[!TIP] Renaming table name will change the name of Object. You may use
setNamefunction to override auto-generated object name
Creating new Object Specs
You can create new Object Specs for existing Objects using Migrations.
Example:
$response = db()->schema('my_existing_table')->objectSpecs(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->integer('votes');
$object->integer('vote_count')->defaultValue(100);
return $object;
});[!TIP] You can also check Create or Update Object section for adding new Specs to existing Objects. It will also upsert Object Specs.
Removing Object Specs
You can remove an existing Object Specs using Migrations.
Example:
$cmsObjectModel = new \Butterfly\Core\Model\CmsObject();
$cmsObjectModel->removeObjectSpec('test_table_name', 'test_column_name');will remove Object Spec with column name: test_column_name of the Object with table name: test_table_name
[!WARNING] This function removes column from database. Please beware that all data in the column will be destroyed.
Overriding Column Type
Sometimes you may need different column types in database, for example: default column type for integers is int(11) but you may want to increase the limit and update it to bigint(20). You can use columnType function to update column type.
Example:
$response = db()->schema('my_existing_table')->objectSpecs(function(\Butterfly\Framework\Data\ButterflyObject $object) {
$object->integer('votes');
$object->integer('vote_count')->columnType('bigint(20)');
return $object;
});Last updated