Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Exponential migrations for Doctrine users

For developers who know Doctrine Migrations from the DXP and now work on an Exponential 6 site - what is the same, what differs (content as well as schema, captions, commit, tag and push, environments, the…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/dxp-developers/exponential-migrations-for-doctrine-users.md

On this page

Exponential migrations for Doctrine users

This page is for developers who change the database of DXP projects with Doctrine Migrations (Doctrine migrations) and now work on an Exponential 6 site, the kernel without Symfony. Exponential 6.0.15 has migrations of its own. The idea is the one you know; the scope and the safety net are wider.

What is the same

  • One file per change, named by a timestamp, kept in git with the code that needs it.
  • Applied in order, recorded per database, never applied twice; a migration that ran is never edited.
  • A dry run before the real run, up() to apply, down() to take one back.
  • One command in the deploy that applies what is pending.

What differs

TopicDoctrine Migrations (DXP)Exponential 6 migrations
What a migration changesSQL of the schema and your own tablesanything: tables, content classes, content, roles, settings, through the kernel's APIs
The classfinal class Version20261101100000 extends AbstractMigrationfinal class NewsNote20261101100000 extends \expMigrationPhp in Site\Migrations
Orderby versionby id, plus requires: in the header (other migrations, extensions, kernel upgrade steps)
The recorddoctrine_migration_versionsexp_migration and exp_migration_run, mirrored to migrations/status/<environment>.json in git
Changed filesnot noticedrefused by a checksum guard unless --force --reason accepts them
Before a runyour own backupa caption (dump, storage, settings) taken automatically, reused while nothing changed
After a failurethe database as the failure left it (MySQL commits DDL)the transaction rolled back where the engine can, then the caption restored
After a runnothingthe status file and run log committed, tagged and pushed
Environments--env selects the Symfony configa header environments: staging, production limits where a migration runs
Schema diffdoctrine:migrations:diff generates from entitiesno diff generator; exp:migration:generate --skeleton writes an empty class
EnginesMySQL, PostgreSQL, SQLiteMySQL/MariaDB, PostgreSQL, SQLite, Oracle, MongoDB
User interfaceconsole onlyconsole and Setup > Migrations in the administration

The commands side by side

Doctrine (DXP)Exponential 6
php bin/console doctrine:migrations:status./console exp:migration:status
doctrine:migrations:migrate --dry-run./console exp:migration:migrate (a dry run until --apply)
doctrine:migrations:migrate./console exp:migration:migrate --apply
doctrine:migrations:generate./console exp:migration:generate --skeleton <name> --apply
doctrine:migrations:execute --down <version>./console exp:migration:rollback <migration-id> --apply
(none)./console exp:migration:rollback <run-id> --apply: the caption taken before a run
(none)./console exp:migration:dry-run --simulate --diff: run and roll back, show what changed
(none)./console exp:migration:check: the lint for CI, no database

The DXP's own pages write the commands with the alias doctrine:migration:*; both spellings work there.

The same table in both

Doctrine:

final class Version20261101100000 extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'A table for news notes';
    }

    public function up( Schema $schema ): void
    {
        $this->addSql( 'CREATE TABLE news_note (id INT NOT NULL, title VARCHAR(150) NOT NULL, PRIMARY KEY(id))' );
    }

    public function down( Schema $schema ): void
    {
        $this->addSql( 'DROP TABLE news_note' );
    }
}

Exponential 6: the table in the format of share/db_schema.dba, created on every engine by the kernel:

<?php
// description: A table for news notes
namespace Site\Migrations;

final class NewsNote20261101100000 extends \expMigrationPhp
{
    const TABLE = 'news_note';

    public static function schema()
    {
        return array( self::TABLE => array(
            'name' => self::TABLE,
            'fields' => array(
                'id' => array( 'length' => 11, 'type' => 'int', 'not_null' => '1', 'default' => 0 ),
                'title' => array( 'length' => 150, 'type' => 'varchar', 'not_null' => '1', 'default' => '' ),
            ),
            'indexes' => array( 'PRIMARY' => array( 'type' => 'primary', 'fields' => array( 'id' ) ) ),
        ) );
    }

    public function plan( $context )
    {
        return array( 'create the table ' . self::TABLE );
    }

    public function detect( $context )
    {
        return \expKernelTableSchema::exists( self::TABLE, $context->db(), true ) ? \expMigration::DONE : null;
    }

    public function up( $context )
    {
        $messages = array();
        if ( !\expKernelTableSchema::install( array( self::TABLE ), $context->db(), self::schema(), $messages ) )
            throw new \RuntimeException( 'the table could not be created: ' . implode( '; ', $messages ) );
        return array( 'created ' . self::TABLE );
    }

    public function down( $context )
    {
        $context->db()->query( 'DROP TABLE ' . self::TABLE );
        \expKernelTableSchema::reset();
        return array( 'dropped ' . self::TABLE );
    }
}

The differences in the code: no SQL per engine (the schema handler writes it), plan() instead of a description only, detect() so an installation that has the table already counts it as done, and every call goes through $context->db(), the run's connection. Kernel code stays PHP 7.4 compatible: no return types are needed.

When each stack applies

You work onUse
a DXP project (Symfony, the content repository)Doctrine Migrations, as the DXP's skeleton does
an Exponential 6 site (the kernel, ./console)exp:migration:*
a project that runs botheach stack's own tool on its own database; never record one stack's change in the other's table

Choosing DXP, Legacy, Nexus or Exponential 6 explains the stacks. Moving a site from one stack to the other is a site migration, not a migration file: Migrations versus migrating a site.

Where to go next

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x