bake migration_snapshot drops collation and engine from table definitions
@jamisonbryant is already working on this.
Since Jul 13, 2026.
- Dominant language
- PHP
- Stars
- 134
- Forks
- 122
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 3
Description
Description
bake migration_snapshot silently drops table level options from the generated $this->table() statement. Only the primary key portion is rendered, so collation and engine are omitted entirely and any database rebuilt from the snapshot loses them.
Table options are already documented and supported on the write path — Creating a Table lists comment, collation, row_format, engine, signed, and limit, and MysqlAdapter::createTable() consumes them. So a user can write a table's collation or engine in a migration, but bake cannot read it back.
Reproduction
Against MySQL, with a database whose default collation is utf8mb4_0900_ai_ci:
CREATE TABLE events (
id INT NOT NULL AUTO_INCREMENT,
title VARCHAR(255) NULL,
PRIMARY KEY (id)
) COLLATE=utf8mb3_hungarian_ci;
CREATE TABLE parts (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM;
bin/cake bake migration_snapshot TableOptionsProof
Expected — the snapshot preserves the options:
$this->table('events', ['collation' => 'utf8_hungarian_ci'])
->addColumn('title', 'string', [...])
->create();
$this->table('parts', ['engine' => 'MyISAM'])
->addColumn('name', 'string', [...])
->create();
Actual — both options are missing:
$this->table('events')
->addColumn('title', 'string', [...])
->create();
$this->table('parts')
->addColumn('name', 'string', [...])
->create();
Running the generated migration produces events with the database default collation and parts with the InnoDB engine.
Impact
A table whose collation or engine differs from the connection defaults is rebuilt from the snapshot with the connection defaults instead of its real ones.
Snapshots rebuild fresh databases (CI, test, new environments) while existing databases keep their real schema, so the source and the rebuilt database diverge. Collation determines string comparison semantics and index key length.
It makes the snapshot unusable as a migration baseline, which is its primary use case: squashing a long migration history into a snapshot silently rewrites the schema.
Observed in a CakePHP 5.3 / migrations 5.0.0 application on eight tables declared with 'collation' => 'utf8_unicode_ci', which regenerate as utf8mb4_unicode_ci.
Root cause
This is not a reflection gap. The values are present on the TableSchema at bake time — MysqlSchemaDialect::describeOptions() returns engine and collation, and SchemaDialect::describe() applies them via setOptions().
They are dropped at render time. templates/bake/element/create-tables.twig builds the table options array from the primary key alone and never reads TableSchema::getOptions().
Column collation is affected as a consequence: MigrationHelper::attributes() strips a column's collate when it equals the table's collation, which is only sound if the table collation is rendered.
Table options are reflected for MySQL only; the other dialects return [] from describeOptions().
Versions
- migrations: 5.x
- CakePHP: 5.3
- Database: MySQL / MariaDB (table options are only reflected in
MysqlSchemaDialect)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.