semisedlak / migratte
Migratte is a simple database migration tool for PHP.
Installs: 22 150
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 0
Open Issues: 0
Requires
- php: >=7.4
- ext-json: *
- dibi/dibi: ^4 || ^5
- symfony/console: ^4 || ^5 || ^6
Requires (Dev)
README
- How it works
- Migration anatomy
- Configuration
- Executable file
- Commands
- Are you using Nette Framework?
- Changelog
Migratte is simple SQL migrations management standalone CLI app, framework-agnostic. It is inspired by Phinx, but it is much simpler, and it doesn't require CakePHP framework to be installed.
You can install it using composer:
$ composer require semisedlak/migratte
How it works
It is controlled by (Symfony Console) CLI commands for:
- generate new migration
- commit migration
- rollback migration
- showing migrations status
- showing configuration info
Migration anatomy
Migrations are simple PHP files keeping plain SQL queries. If plain SQL so why PHP files then? Answer is simple. For keeping "up" (for commit) and "down" (for rollback) SQL queries with additional metadata all together.
💡 Migratte doesn't provide (yet) rich migrations management. It is just a simple tool for executing your SQL queries and it is up to you to write them. You can use any SQL query you want.
You can still use Phinx with CakePHP Migrations for migrations management. I recommend Adminer for database management.
Specific migration class extends from basic migration class. It contains timestamp in file name and class name witch should not be modified.
Migration file that doesn't contain down()
method is "breakpoint", that means rollback cannot be performed. BUT! There is an option --force
to perform rollback with this kind of migration.
This tool creates it's "memory" in same database as migrations target. It uses dibi database layer for connection and queries executions.
You can use it with:
- MySQL database
- PostgreSQL database
- SQLite database
Configuration
You can override this default configuration options:
'timezone' => 'UTC', 'migrationsDir' => "$workingDir/database/migrations", 'migrationsTable' => [ 'name' => 'migrations', 'primaryKey' => 'id', 'fileName' => 'filename', 'groupNo' => 'group', 'committedAt' => 'committed_at', ], 'connection' => [ 'driver' => 'sqlite', // mysqli or postgre 'database' => "$workingDir/database/migratte.s3db", ],
providing options array as first argument of Application::boot()
method from executable file. You can read how to set up connection in dibi documentation.
Executable file
Create a file bin/migrations
in the root dir of your project with following content:
#!/usr/bin/env php <?php use Semisedlak\Migratte\Application\Application; require __DIR__ . '/../vendor/autoload.php'; (Application::boot())->run();
Don't forget to change permission using chmod +x bin/migrations
Commands
When you run bin/migrations
in CLI you will see "help" overview with possible commands.
root@12345:/var/www/html# bin/migrations
Migratte 0.5.0
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
help Display help for a command
list List commands
migratte
migratte:commit Commit (run) migrations
migratte:generate Generate new migration file
migratte:info Show migrations configuration info
migratte:rollback Rollback migrations
migratte:status Show migrations status
💡 Hint: You can use
--help
(or-h
) option for each command to see more details.
migratte:generate
Command generates new migration file which then can be modified. You can specify migration name as first argument. Write it as normal sentence, it will be converted to desired form automatically.
$ bin/migrations migratte:generate "Create users table"
This will generate file database/migrations/20190101_120000-create-users-table.php
with following content:
<?php use Semisedlak\Migratte\Migrations\Migration; class Migration_20190101_120000 extends Migration { public static function getName(): string { return 'Create users table'; } public static function up(): string { return <<<SQL -- UP: Create users table SQL; } public static function down(): ?string { return NULL; } }
⚠️ Warning! Don't modify migration class name. Don't modify file name after it was committed. You can modify
up()
anddown()
methods to contain your SQL queries.
If you want to change migration name you can change it in getName()
method. It is used only for displaying purposes.
Then copy your SQL queries to up()
and down()
methods. If down()
method returns NULL or FALSE it is considered as "breakpoint" migration (it cannot be rollbacked because it doesn't provide "down" operation).
Example migration
public static function up(): string { return <<<SQL CREATE TABLE `users` ( `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(255) NOT NULL ) ENGINE='InnoDB' COLLATE 'utf8mb4_general_ci'; SQL; } public static function down(): ?string { return <<<SQL DROP TABLE `users`; SQL; }
migratte:commit
Command commits (runs) new migrations. By default, it will run all non-committed migrations one-by-one. You can specify less to commit with limit
(first) argument:
$ bin/migrations migratte:commit 3
But there is more. You can specify datetime limits --from
and --to
for limiting committing.
Are you unsure what migrations will be committed? Use --dry-run
(or -d
) option to see what migrations will be committed without actually committing them.
Migratte automatically put migrations into groups. These groups are simply integer numbers and they are important for rollback strategy. You can't specify group number. It will be automatically incremented. If you use default rollback strategy (by commit date) it will rollback migrations from the last group (with highest number) in reverse order of committing.
migratte:rollback
Command performs rollback operation to already committed migrations back to previous state. Rollback will be done only on (by default) migrations from latest group. You can specify more migrations to rollback with limit
(first) argument:
$ bin/migrations migratte:rollback 3
In this case, it will ignore groups and rollback last 3 committed migrations.
If migration doesn't contain down()
method or this method simply returns NULL or FALSE it is considered as "breakpoint". Calling rollback on "breakpoint" will throw an error. This can be bypassed by using --force
(or -f
) option.
Rollback strategy
You can specify rollback strategy by using --strategy
option. There are currently three strategies for rollback:
- by commit "date" (this is default) (
--strategy=date
) - rollback by commit date (migrations from last group will be rollbacked by commit date in reverse order of committing) - by migration "order" (
--strategy=order
) - rollback migrations by migrations order (if you sort files by name, you will get migrations order, so last committed file will be rollbacked first) - by specific "file" (
--strategy=file
) - rollback specific migration file. You have to provide migration file name (without path) as--file
option. Hint: you can omit.php
extension.
migratte:status
Command shows current migrations' status (what is or isn't committed, which migration is breakpoint and more).
There is also an option --compact
(or -c
) to show compact table of migrations.
migratte:info
Command shows current Migratte configuration.
Are you using Nette framework?
Great! You can use Nette DI extension to register a Migratte panel into Tracy (something like migratte:status
and migratte:info
combined but... in HTML... with styles). It will use dibi
extension for connection definition.
extensions: migratte: Semisedlak\Migratte\Nette\DiExtension migratte: debug: true
Changelog
0.4.0
Please update your bin/migrations
executable file Application
class namespace like this:
// use Semisedlak\Migratte\Migrations\Application; // OLD NAMESPACE use Semisedlak\Migratte\Application\Application; // NEW NAMESPACE