Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Migrations Laravel Package

laravel-doctrine/migrations

Laravel Doctrine Migrations integrates Doctrine's migration library with Laravel, providing a service provider, publishable configuration, and Artisan commands to run, roll back, and inspect database migrations in Laravel Doctrine applications.

View on GitHub
Deep Wiki
Context7

Getting Started

laravel-doctrine/migrations wires the standalone doctrine/migrations library into a Laravel app: it builds a Doctrine DependencyFactory from your Laravel DB config, registers the Doctrine console commands under the doctrine: namespace, and gives you a publishable config file. Release 3.4.4 is a compatibility release (adds Laravel 13 support, CI matrix updated) — no API or config changes, so it is a drop-in bump from 3.4.3. It requires the matching Laravel major, so pin accordingly if you are still on Laravel 10/11/12.

Minimal setup:

  1. composer require laravel-doctrine/migrations
  2. Publish the config: php artisan vendor:publish --tag=doctrine-migrations (the provider is auto-discovered; check the tag name in the README for your version).
  3. Edit config/doctrine-migrations.php — at minimum migrations_paths (namespace → path, e.g. DoctrineMigrations → database_path('migrations')) and the table_storage.table_name (default doctrine_migration_versions).
  4. Create the metadata table: php artisan doctrine:migrations:sync-metadata-storage.
  5. Generate your first migration and run it.

Where to look first: the published config file, then php artisan list doctrine — the registered commands mirror Doctrine Migrations' own console names with a doctrine: prefix (doctrine:migrations:migrate, :status, :diff, :generate, :execute, :version, :sync-metadata-storage). Exact names vary by version, so trust artisan list over any blog post.

First real use case: you have an existing schema (or Doctrine entities via laravel-doctrine/orm) and want versioned, reversible, diffable migrations with a schema-aware up(Schema $schema) / down(Schema $schema) API instead of raw SQL strings. Run doctrine:migrations:diff to have Doctrine introspect the database and emit a VersionYYYYMMDDHHMMSS.php class extending Doctrine\Migrations\AbstractMigration, then doctrine:migrations:migrate to apply it.

Implementation Patterns

Migration authoring. Each migration is a class extending Doctrine\Migrations\AbstractMigration with getDescription() plus up(Schema $schema) / down(Schema $schema). Prefer the schema API ($schema->createTable(), $table->addColumn(), $table->addForeignKeyConstraint()) over $this->addSql('...') — it stays platform-portable and is what diff produces, so hand-written and generated migrations look the same to reviewers.

Diff-driven workflow (the one that pays off daily).

doctrine:migrations:diff --allow-empty-diff   # review the generated Version*.php
doctrine:migrations:migrate --dry-run         # sanity check SQL
doctrine:migrations:migrate

With laravel-doctrine/orm installed, the diff compares your entity mappings against the live DB, which makes diff the primary authoring tool and hand-writing migrations the exception. Without the ORM, it still diffs against the current schema.

Coexistence with Laravel's own migrations. This package does not replace php artisan migrate; it adds a second, independent migration system with its own doctrine_migration_versions table. Two workable patterns:

  • Doctrine-only: forbid artisan make:migration, and put doctrine:migrations:migrate in your deploy script. Cleanest, but migrate:fresh, db:wipe, and RefreshDatabase need teaching.
  • Split by ownership: Laravel migrations for framework/package tables, Doctrine migrations for domain tables. Workable but you must document which system owns which tables, forever.

Deploy pipeline. Treat migrations as a discrete deploy step, not something a rolling app boot does:

Artisan::call('doctrine:migrations:migrate', ['--no-interaction' => true]);

Better: a shell step before the new release is promoted, so a failing migration aborts the deploy rather than leaving a half-migrated fleet. Add --dry-run/--write-sql output to CI for review, and gate on doctrine:migrations:status if you want an explicit "is the DB current" check.

Test suite integration. RefreshDatabase only knows Laravel's migrator. Either call doctrine:migrations:migrate in setUp/a base TestCase, or (faster) use doctrine:migrations:dump-schema where available and load a SQL fixture. For parallel test runs, each worker needs its own database and its own doctrine_migration_versions table — the version table is per-database, so this resolves itself once each worker has a distinct DB.

Rollback strategy. Doctrine Migrations v3 dropped the old rollback command; you go backwards with doctrine:migrations:migrate --to=<version> (or prev). Always write a real down() — a down() that throws is a legitimate choice for destructive migrations, but make it a deliberate choice, documented in getDescription().

Seeding and data migrations. Doctrine migrations are good at data backfills ($this->addSql("UPDATE ...") plus a batched query if the table is big). Keep them idempotent enough that a re-run after a failed deploy is safe, and never assume the app's Eloquent models are available inside a migration — instantiate query builder / raw SQL instead, so a later model refactor can't break an old migration.

Gotchas and Tips

  • Laravel 13 support is the only change in 3.4.4. No config keys, command names, or class signatures moved. If you are on Laravel ≤12 you can stay on 3.4.3 with zero behavioural difference; upgrade when you move the framework. The practical risk of this release is Composer conflict resolution, not code.
  • Two migration tables, two sources of truth. doctrine_migration_versions and migrations are unrelated. php artisan migrate:fresh will happily drop every table while leaving Doctrine's version table populated and lying about what is applied. If you use freshen/wipe in dev, also truncate doctrine_migration_versions (or run doctrine:migrations:version --delete --all --no-interaction).
  • DBAL version detection. Doctrine needs to know the server version to pick a platform. If you see MySQL-vs-MariaDB or "unknown database platform" errors, set server_version in config/database.php for that connection rather than letting Doctrine probe. This is the single most common source of noise in this stack.
  • MySQL/MariaDB DDL is not transactional. Implicit commits mean all_or_nothing gives you less than it promises; a mid-migration failure leaves partial DDL and a version row that was not written. Keep migrations small and single-purpose so recovery is "fix forward", and be suspicious of long multi-statement migrations on MySQL.
  • diff is a starting point, not gospel. It will happily generate destructive DROP TABLE/DROP COLUMN statements for anything it no longer sees in metadata — the classic cause being "I forgot to hydrate the entity mapping". Read every generated diff. --allow-empty-diff in CI catches the "diff produced nothing but I expected a change" case, which usually means a mapping/config path is wrong.
  • Version naming is load-bearing. Files must be VersionYYYYMMDDHHMMSS.php with the class name matching. Renaming or hand-numbering files breaks ordering and --to targeting. When two branches both generate a diff, the timestamps usually sort fine but the logical order may not — rebase and regenerate rather than trusting the clock.
  • migrations_paths is a namespace→path map, not a list. Registering the same path under two namespaces produces duplicate-class and "migration not found" confusion. One namespace (DoctrineMigrations) for the whole app is fine at almost any scale; add sub-namespaces only if you genuinely need per-module organisation.
  • Extension points. custom_template in the config lets you shape generated migrations (add headers, enforce a base class, inject a lint-friendly skeleton) — the cheapest way to standardise a team's migrations. For anything deeper, rebind or decorate Doctrine's DependencyFactory; that is the seam every command resolves through, so a container binding there affects all of them.
  • Debugging tip. When a command behaves oddly, --dry-run, --write-sql, and -vvv in that order. --write-sql dumps the exact SQL Doctrine intends to run without touching the DB, which distinguishes "Doctrine generated the wrong thing" from "the database rejected the right thing" — two very different bugs.
  • Keep the version table out of your app's reach. It is infrastructure. Exclude it from any Eloquent model, schema dump, or "compare table lists" test, or you will spend an afternoon on a phantom drift failure.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin