blixem/third-party-migrations
Install the Package
composer require blixem/third-party-migrations
For Symfony projects, ensure the bundle is registered in bundles.php (automatically added via Flex).
Publish the Migration Table
Run the initial migration to create the package_schema_version table:
php bin/console doctrine:migrations:execute --query="SELECT * FROM package_schema_version" --dry-run
If the table doesn’t exist, manually create it or let the package handle it via its own migration (check vendor/blixem/third-party-migrations/migrations/).
Define a Third-Party Migration
Create a migration file in your package’s src/Migrations/ (or a custom directory) with a naming convention:
VersionYYYYMMDD_HHMMSS_Install.phpVersionYYYYMMDD_HHMMSS_UpdateToX.php (e.g., Version20231015_UpdateTo2_0_0.php).
Example:namespace YourVendor\YourPackage\Migrations;
use Blixem\ThirdPartyMigrations\Migration\ThirdPartyMigration;
use Doctrine\DBAL\Schema\Schema;
class Version20231015_UpdateTo2_0_0 extends ThirdPartyMigration
{
public function getPackageName(): string
{
return 'your-package-name';
}
public function getSchemaVersion(): string
{
return '2.0.0';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE users ADD COLUMN api_token VARCHAR(255)');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE users DROP COLUMN api_token');
}
}
Register the Migration
Add your migration class to the bundle’s configuration in config/packages/third_party_migrations.yaml:
third_party_migrations:
migrations:
- YourVendor\YourPackage\Migrations\Version20231015_UpdateTo2_0_0
Or use a service tag (Symfony-specific):
services:
YourVendor\YourPackage\Migrations\Version20231015_UpdateTo2_0_0:
tags: ['third_party_migration']
Run Migrations Execute migrations for your package:
php bin/console third_party:migrations:migrate --package="your-package-name"
Or run all third-party migrations:
php bin/console third_party:migrations:migrate
Package Development Workflow
UpdateToX_Y_Z migration for schema changes. Name it sequentially (e.g., Version20231015_UpdateTo2_0_0 after Version20230901_UpdateTo1_2_0).VersionXXXX_Install for packages with no prior migrations (e.g., initial schema setup).php bin/console third_party:migrations:execute --package="your-package" --dry-run
Symfony Bundle Integration
composer.json:
"autoload-dev": {
"psr-4": {
"YourVendor\\YourPackage\\Migrations\\": "src/Migrations/"
}
}
ThirdPartyMigrationsEvents (e.g., MigrationsExecuted) to trigger post-migration logic:
use Blixem\ThirdPartyMigrations\Event\MigrationsExecuted;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class YourSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
MigrationsExecuted::class => 'onMigrationsExecuted',
];
}
public function onMigrationsExecuted(MigrationsExecuted $event): void
{
if ($event->getPackageName() === 'your-package') {
// Post-migration logic (e.g., seed data, send notifications)
}
}
}
Dependency Management
Version + timestamp to control order.getSchemaVersion() to skip migrations if the target version is already installed.Rollbacks
down() in migrations. Rollback specific packages:
php bin/console third_party:migrations:migrate --package="your-package" --direction=down
Schema Version Table Corruption
package_schema_version table might get out of sync if migrations fail mid-execution.TRUNCATE package_schema_version;
public function up(Schema $schema): void
{
$this->connection->beginTransaction();
try {
$this->addSql('ALTER TABLE users ADD COLUMN ...');
$this->connection->commit();
} catch (\Exception $e) {
$this->connection->rollBack();
throw $e;
}
}
Migration Naming Collisions
VersionXXXX prefix.YourPackage_Version20231015_UpdateTo1_0_0).Circular Dependencies
order tag:
services:
YourVendor\PackageA\Migrations\Version...:
tags: ['third_party_migration', { order: 10 }]
YourVendor\PackageB\Migrations\Version...:
tags: ['third_party_migration', { order: 20 }]
Doctrine Migrations Conflict
# config/packages/doctrine_migrations.yaml
doctrine_migrations:
migrations_paths:
'Blixem\ThirdPartyMigrations\Migrations': ~
Or run them separately.Dry Runs
Always test migrations with --dry-run:
php bin/console third_party:migrations:execute --package="your-package" --dry-run
Logging Enable verbose output for debugging:
php bin/console third_party:migrations:migrate --package="your-package" -v
Database State Inspection
Check the package_schema_version table:
SELECT * FROM package_schema_version WHERE package_name = 'your-package';
Custom Migration Table Override the default table name in config:
third_party_migrations:
db_table_name: custom_package_versions
Migration Filters Filter migrations by package or version in code:
$migrationRunner = $container->get('third_party_migrations.migration_runner');
$migrationRunner->setPackageFilter('your-package');
$migrationRunner->setVersionFilter('>=1.0.0');
Custom Migration Classes
Extend ThirdPartyMigration to add package-specific logic:
abstract class CustomThirdPartyMigration extends ThirdPartyMigration
{
protected function logMigration(string $message): void
{
// Custom logging (e.g., to Sentry)
}
}
Pre/Post Migration Hooks Use Symfony events to add logic before/after migration execution:
// Subscribe to MigrationsPreExecuted or MigrationsPostExecuted
Version_UsersTable.php, Version_ProductsTable.php).down() for Complex Schemas: If down() is impractical, document manual rollback steps in the migration class.How can I help you explore Laravel packages today?