Install the Bundle
composer require dosfarma/migrations-bundle
Enable the Bundle
Add to config/bundles.php:
return [
DosFarma\MigrationsBundle\DosFarmaMigrationsBundle::class => ['dev' => true, 'test' => true],
];
Configure Basic Parameters
Update config/services.yaml with your migration directory and control table:
parameters:
dos_farma.migrations.migrations_directory: '%kernel.project_dir%/migrations/postgresql/'
dos_farma.migrations.control_table: 'migrations'
First Migration Generate a migration file using the provided template:
php bin/console dosfarma:migrations:generate --name="CreateUsersTable"
This creates a .php file in your migrations directory with a Twig-rendered template.
Run Migrations
php bin/console dosfarma:migrations:migrate
Use this bundle to manage non-Doctrine DBAL migrations (e.g., PostgreSQL-specific extensions, custom SQL, or non-PHP-based migrations). For example:
// migrations/20240101000000_AddPostgresExtension.php
public function up()
{
$this->execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;");
}
public function up()
{
$this->execute("ALTER TABLE users ADD COLUMN IF NOT EXISTS bio TEXT;");
}
Migration Generation
Use the generate command to scaffold migrations with a predefined template (e.g., DBAL SQL or raw SQL):
php bin/console dosfarma:migrations:generate --template=dbalSql --name="AddIndexToUsers"
config/services.yaml or extend via Twig.Migration Execution
php bin/console dosfarma:migrations:migrate
php bin/console dosfarma:migrations:rollback
php bin/console dosfarma:migrations:status
Multi-Engine Support
Configure separate adapters for different databases (e.g., PostgreSQL, MySQL) by defining multiple services in services.yaml:
services:
dosfarma.migrations.postgres.adapter:
class: DosFarma\MigrationsBundle\Infrastructure\Service\Phpmig\Adapter\DbalAdapter
arguments:
$connection: '@connection.postgres'
$tableName: 'postgres_migrations'
Dependency Injection
Inject the ConfigurationContainer into services to programmatically trigger migrations:
use DosFarma\MigrationsBundle\Infrastructure\Service\Phpmig\ConfigurationContainer;
public function __construct(private ConfigurationContainer $migrations) {}
public function deploy()
{
$this->migrations->getMigrator()->migrate();
}
connection.dbal.myservice (or similar) is properly configured in config/packages/doctrine.yaml.%env% to dynamically set migration directories:
parameters:
dos_farma.migrations.migrations_directory: '%kernel.project_dir%/migrations/%env(DB_ENGINE)%/'
namespace App\Migrations;
use DosFarma\MigrationsBundle\Infrastructure\Service\Phpmig\Migration;
class BaseMigration extends Migration
{
protected function log(string $message) {
// Custom logging (e.g., to Monolog)
}
}
Then reference it in your migration files:
class AddFeatureFlag extends \App\Migrations\BaseMigration { ... }
Control Table Conflicts
control_table must exist and be writable. If using a schema (e.g., serviceschema.migrations), ensure the schema exists:
php bin/console doctrine:schema:create --schema=serviceschema
CREATE TABLE serviceschema.migrations (
version VARCHAR(191) NOT NULL PRIMARY KEY,
executed_at TIMESTAMP NOT NULL,
executed_by VARCHAR(191) NOT NULL
);
Template Rendering Issues
dos_farma.migrations.migration_template exists and is accessible.dos_farma.migrations.migration_template: '%kernel.project_dir%/vendor/dosfarma/migrations-bundle/src/Resources/templates/dbalSql.php.twig'
Connection Misconfiguration
connection.dbal.myservice is defined in services.yaml.public: true to the adapter service to inspect it:
DosFarma\MigrationsBundle\Infrastructure\Service\Phpmig\Adapter\Adapter: { ... public: true }
Then dump it in a command:
$adapter = $container->get('dosfarma.migrations.postgres.adapter');
var_dump($adapter->getConnection()->getDatabasePlatform());
Migration Ordering
20240101000000_) to enforce order.README.md in your migrations directory to document dependencies between migrations.Verbose Output Enable debug mode for detailed logs:
php bin/console dosfarma:migrations:migrate --verbose
Dry Runs Test migrations without executing them:
php bin/console dosfarma:migrations:status --dry-run
Custom Logging
Override the log() method in your migration class to integrate with Monolog or other loggers:
protected function log(string $message) {
$this->container->get('logger')->info($message, ['migration' => static::class]);
}
Custom Adapters
Extend DbalAdapter to support non-DBAL engines (e.g., MongoDB, Elasticsearch):
namespace App\Migrations\Adapter;
use DosFarma\MigrationsBundle\Infrastructure\Service\Phpmig\Adapter\AdapterInterface;
class ElasticsearchAdapter implements AdapterInterface
{
public function execute(string $sql): void
{
// Custom logic for Elasticsearch "migrations"
}
}
Register it in services.yaml:
services:
dosfarma.migrations.elasticsearch.adapter:
class: App\Migrations\Adapter\ElasticsearchAdapter
Pre/Post Migration Hooks Use Symfony events to run logic before/after migrations:
# config/services.yaml
services:
App\EventSubscriber\MigrationSubscriber:
tags:
- { name: kernel.event_subscriber }
namespace App\EventSubscriber;
use DosFarma\MigrationsBundle\Event\MigrationEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MigrationSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
MigrationEvents::MIGRATION_PRE_UP => 'onPreUp',
MigrationEvents::MIGRATION_POST_UP => 'onPostUp',
];
}
public function onPreUp(): void { /* ... */ }
public function onPostUp(): void { /* ... */ }
}
Migration Validation Add validation to migration files using PHPStan or custom scripts. Example PHPStan rule:
// phpstan.neon
parameters:
level: 8
paths:
- migrations
excludePaths:
- vendor
rules:
DosFarma\MigrationsBundle\:
- methodCallArgumentType.migrationExecute
public function up()
{
$this->execute("BEGIN;");
$this->execute("ALTER TABLE large_table ADD COLUMN new_col INT;");
How can I help you explore Laravel packages today?