Installation
composer require effiana/migration-bundle
Register the bundle in config/bundles.php:
return [
// ...
Effiana\MigrationBundle\EffianaMigrationBundle::class => ['all' => true],
];
Generate a Migration Use the bundle’s command to scaffold a new migration:
php bin/console effiana:migration:generate
This creates a migration class in Migrations\Schema/{version_number}/ (e.g., Migrations\Schema/20240101000000/).
Define a Schema Migration
Implement the Migration interface in your new class:
namespace App\Migrations\Schema\20240101000000;
use Effiana\MigrationBundle\Migration\Migration;
use Effiana\MigrationBundle\Migration\Schema;
class AddUserTable implements Migration
{
public function up(Schema $schema, $queries): void
{
$schema->createTable('users', function ($table) {
$table->addColumn('id', 'integer', ['autoincrement' => true]);
$table->addColumn('name', 'string', ['length' => 255]);
$table->addPrimaryKey(['id']);
});
}
}
Run the Migration Execute the migration via:
php bin/console effiana:migration:migrate
Use this bundle to version-control database schema changes (e.g., adding tables, columns, or constraints) in a portable, framework-agnostic way (via DBAL). Ideal for:
Schema-First Approach
Schema object to define changes declaratively (e.g., createTable, addColumn, addForeignKey).$schema->table('users')->addColumn('created_at', 'datetime');
Query Bag for Custom SQL
queries->addPreQuery() or queries->addPostQuery() for raw SQL when DBAL lacks support (e.g., database-specific syntax).$queries->addPreQuery('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";');
Fixtures for Data Migrations
Effiana\MigrationBundle\Migration\Fixture for data seeding (e.g., inserting default records).namespace App\Migrations\Fixtures\20240101000000;
use Effiana\MigrationBundle\Migration\Fixture;
class SeedUsers implements Fixture
{
public function load(): void
{
$this->insert('users', ['name' => 'Admin'], ['id' => 1]);
}
}
php bin/console effiana:migration:fixtures
Rollbacks
down() method in your migration to reverse changes (if needed):
public function down(Schema $schema, $queries): void
{
$schema->dropTable('users');
}
php bin/console effiana:migration:rollback
Versioning Strategy
20240101000000) for migrations to ensure chronological ordering.Environment-Specific Migrations
Migrations\Schema/production/20240101000000/).Testing Migrations
$this->assertDatabaseHas('users', ['name' => 'Admin']);
Combining with Doctrine Migrations
Version Number Conflicts
20240101000000_app_) or namespace migrations by bundle.Database-Specific Syntax
Schema object for portability; wrap custom SQL in try-catch blocks.Missing down() Method
down() is not implemented.down() for critical migrations or document why it’s omitted.Fixture Dependencies
roles before users).Transaction Failures
Dry Runs
Use --dry-run to preview changes:
php bin/console effiana:migration:migrate --dry-run
Logging Enable verbose output for debugging:
php bin/console effiana:migration:migrate -v
Schema Dumps Export the current schema for comparison:
php bin/console doctrine:schema:dump-sql > schema.sql
Custom Migration Directories
Override the default migration path in config/packages/effiana_migration.yaml:
effiana_migration:
schema_migrations_directory: '%kernel.project_dir%/custom/migrations'
Event Listeners
Subscribe to migration events (e.g., MigrationEvents::PRE_MIGRATE) to add pre/post hooks:
use Effiana\MigrationBundle\Event\MigrationEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MigrationSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
MigrationEvents::PRE_MIGRATE => 'onPreMigrate',
];
}
public function onPreMigrate($event)
{
// Add logic here (e.g., backup database)
}
}
Custom Query Bag
Extend QueryBag to add database-specific methods:
namespace App\Migration;
use Effiana\MigrationBundle\Migration\QueryBag;
class CustomQueryBag extends QueryBag
{
public function addPostgresExtension(string $extension): void
{
$this->addPostQuery("CREATE EXTENSION IF NOT EXISTS {$extension};");
}
}
Bind it in your migration:
$queries = new CustomQueryBag();
$queries->addPostgresExtension('uuid-ossp');
Autoloading Migrations
Ensure migrations are autoloaded by Composer. Add this to composer.json:
"autoload": {
"psr-4": {
"App\\Migrations\\": "Migrations/"
}
}
Case-Sensitive Paths
Doctrine vs. DBAL Conflicts
How can I help you explore Laravel packages today?