Repository navigation
Conversation
Add support for the `fixed` attribute on binary columns to distinguish between fixed-length BINARY and variable-length VARBINARY types. This mirrors cakephp/cakephp#19207. * Add test cases for fixed option on binary columns Tests cover: - Column class getter/setter for fixed option - Column::toArray() including fixed in output - Column::setOptions() accepting fixed option - MigrationHelper::getColumnOption() including/excluding fixed - MysqlAdapter creating BINARY vs VARBINARY based on fixed option * Add column type assertions to binary fixed test
Only show 'Set legacyTables => false' step after tables have been dropped, as the upgrade command becomes unavailable once this config is set. Fixes #1036
* Fix upgrade command not matching plugins with slashes When upgrading from legacy phinxlog tables, the plugin name was being derived by camelizing the table prefix (e.g. cake_d_c_users -> CakeDCUsers). This didn't work for plugins with slashes in their names like CakeDC/Users since the slash was replaced with underscore during table name generation. This fix builds a map of loaded plugin names to their expected table prefixes, allowing proper matching of plugins like CakeDC/Users. Fixes #1038 * Fix test for SQL Server compatibility
* Add TYPE_BIT constant to AdapterInterface Adds the TYPE_BIT constant mapping to TableSchemaInterface::TYPE_BIT for consistency with the core BIT type support added in cakephp/cakephp#19223. This allows migration users to reference AdapterInterface::TYPE_BIT when defining BIT columns in MySQL migrations. * Bump cakephp/database constraint to ^5.3.2 for TYPE_BIT support
When a foreign key is added without an explicit name, the MysqlAdapter and SqliteAdapter now generate a name following the pattern 'tablename_columnname' (e.g., 'articles_user_id' for a FK on the user_id column in the articles table). This matches the behavior of PostgresAdapter and SqlserverAdapter, which already auto-generate FK names. This ensures constraint names are always strings and prevents issues with constraint lookup methods that expect string names.
Update the expected FK names in comparison files and schema dumps to match the new auto-generated naming pattern (tablename_columnname).
The FK constraint name change from auto-generated (ibfk_N) to explicit (table_column) also affects the implicit index MySQL creates for FKs. Update comparison files to reflect the index rename from user_id to articles_user_id.
With the FK naming changes, both the lock file and database have the index named articles_user_id, so no diff is needed for this index. Remove the index rename operations that were incorrectly added.
Merge 5.x into 5.next
* Add conflict resolution for auto-generated FK constraint names When auto-generating FK constraint names, check if the name already exists and append a counter suffix (_2, _3, etc.) if needed. This prevents duplicate constraint name errors when multiple FKs are created on the same columns with different references. * Remove unused variable * Truncate FK constraint names to max 128 characters Limit auto-generated foreign key constraint names to 125 characters to ensure the final name (including potential _XX counter suffix) stays within 128 characters. This prevents identifier length errors on databases with strict limits (MySQL: 64, PostgreSQL: 63). * Use database-specific identifier length limits - MySQL: 61 chars (64 limit - 3 for _XX suffix) - PostgreSQL: 60 chars (63 limit - 3 for _XX suffix) - SQL Server: 125 chars (128 limit - 3 for _XX suffix) - SQLite: No limit needed * Use IDENTIFIER_MAX_LENGTH class constant for clarity Each adapter now defines its database-specific identifier length limit as a class constant, making the code more self-documenting.
When generating migrations, the 'fixed' option could be set to null for binary columns, which causes an error when running the migration because Column::setFixed() expects a bool, not null. Fixes #1046
Add upgrade documentation explaining the new auto-generated FK constraint naming behavior introduced in #1041 and #1042, including: - New consistent naming pattern across all adapters - Potential impact on existing migrations with rollbacks - Conflict resolution with counter suffixes - Database-specific name length limits
* add using when changing column type to json (#1031) * Fix CI failures on MySQL/MariaDB (#1034) 1. Handle uninitialized Column::$fixed property in BakeMigrationDiffCommand When TableSchema::getColumn() is called on cached/serialized schema objects, the Column::$fixed property may not be initialized, causing an Error. Added safeGetColumn() helper that catches this error and uses reflection to initialize uninitialized properties before retry. 2. Fix CURRENT_TIMESTAMP test assertion for MySQL/MariaDB Different versions of MySQL and MariaDB return CURRENT_TIMESTAMP in different formats (CURRENT_TIMESTAMP, current_timestamp(), CURRENT_TIMESTAMP()). Changed the test to use a regex that accepts all valid formats case-insensitively. Fixes #1033 * Fix TEXT column variants not round-tripping correctly (#1032) When using migration_diff, TEXT column variants (TINYTEXT, MEDIUMTEXT, LONGTEXT) were not being properly mapped back from the database. The BLOB type handling already used rawType to distinguish BLOB variants, but TEXT variants were missing equivalent handling. This adds similar rawType-based mapping for TEXT columns in mapColumnType() and includes round-trip tests. Fixes #1029 * Add fixed option for binary column type (#1014) Add support for the `fixed` attribute on binary columns to distinguish between fixed-length BINARY and variable-length VARBINARY types. This mirrors cakephp/cakephp#19207. * Add test cases for fixed option on binary columns Tests cover: - Column class getter/setter for fixed option - Column::toArray() including fixed in output - Column::setOptions() accepting fixed option - MigrationHelper::getColumnOption() including/excluding fixed - MysqlAdapter creating BINARY vs VARBINARY based on fixed option * Add column type assertions to binary fixed test * Fix misleading next steps message in upgrade command (#1037) Only show 'Set legacyTables => false' step after tables have been dropped, as the upgrade command becomes unavailable once this config is set. Fixes #1036 * Fix upgrade command not matching plugins with slashes (#1039) * Fix upgrade command not matching plugins with slashes When upgrading from legacy phinxlog tables, the plugin name was being derived by camelizing the table prefix (e.g. cake_d_c_users -> CakeDCUsers). This didn't work for plugins with slashes in their names like CakeDC/Users since the slash was replaced with underscore during table name generation. This fix builds a map of loaded plugin names to their expected table prefixes, allowing proper matching of plugins like CakeDC/Users. Fixes #1038 * Fix test for SQL Server compatibility * Add TYPE_BIT constant to AdapterInterface (#1013) * Add TYPE_BIT constant to AdapterInterface Adds the TYPE_BIT constant mapping to TableSchemaInterface::TYPE_BIT for consistency with the core BIT type support added in cakephp/cakephp#19223. This allows migration users to reference AdapterInterface::TYPE_BIT when defining BIT columns in MySQL migrations. * Bump cakephp/database constraint to ^5.3.2 for TYPE_BIT support * Bump PHPStan level +1 * Make props non-nullable * Add null guards for getConstraint() in BakeMigrationDiffCommand * Fix nullable return types in Column and ForeignKey Column::getNull() now coalesces the nullable bool property to false. ForeignKey::getOnDelete()/getOnUpdate() guard against null from getDelete()/getUpdate() before calling mapAction(). * Fix null safety in Db adapters and domain classes Cast preg_replace results to string, coalesce nullable getColumns() returns, cast nullable getReferencedTable()/getName() at call sites, and use null-safe operator for optional ConsoleIo. * Fix remaining PHPStan level 8 null safety issues Add null guards for constraint diff, fail-fast for null column type, fix import order, and remaining null safety in BaseSeed, ColumnParser, TableFinder, and MigrationHelper. * Replace assert with RuntimeException in AbstractAdapter::getConnection() Assertions can be disabled in production, which would allow a null connection to slip through silently. Throw a RuntimeException instead to fail fast in all environments. * Use truthiness checks for optional nullable getters Replace (string) casts with assign-then-check pattern for optional values that can legitimately be null: Index::getWhere(), ForeignKey::getName(), Index::getName(), Column::getGenerated(). This avoids silently converting null to empty string. * Throw on null for required Column::getName() and FK::getReferencedTable() Replace (string) casts with explicit null checks and InvalidArgumentException throws for values that must be present: Column::getName() in SQL generation and ForeignKey::getReferencedTable() in FK definition builders. A column without a name or a foreign key without a referenced table are always programming errors that should fail fast rather than silently produce broken SQL. * Narrow ForeignKey::getColumns() return type and remove null guards Override getColumns() in Migrations ForeignKey to return array instead of the parent's ?array. The $columns property is always initialized as [] in the constructor, making null unreachable. This is a covariant return type narrowing, same pattern used for Column::getNull(). Removes the now-unnecessary ?? [] fallbacks from all 6 call sites across the adapter and plan classes. * Narrow Column::getName() return type and remove dead null checks Override getName() in Migrations Column to return string instead of the parent's ?string. The $name property is typed as string (not ?string) in the constructor, making null unreachable. This is a covariant return type narrowing, same pattern used for ForeignKey::getColumns(). Removes now-unnecessary null checks across adapter/action files and the dead null guard in Table::setPrimaryKey(). * Add null guards for column diff loop in BakeMigrationDiffCommand Use early-continue pattern to narrow nullable safeGetColumn() return types before array operations, fixing PHPStan level 8 errors. * Cast nullable getName() to string for drop FK/index instructions * Fix phpcs coding standard violations Remove unused InvalidArgumentException import from RecordingAdapter, extract assignment out of if condition in PostgresAdapter, and remove blank line before closing brace in ForeignKeyTest. * Consolidate null guard conditions in BakeMigrationDiffCommand * Fix inverted condition in ChangeColumn name fallback * Accept null in Column::setFixed() for snapshot compatibility Generated migration snapshots can emit 'fixed' => null for binary columns, which causes a TypeError since setFixed() only accepted bool. Widen the parameter to ?bool to match the property and getter types. Fixes #1046. --------- Co-authored-by: Matthias Wirtz <matthias.wirtz@hotmail.de> Co-authored-by: Mark Scherer <dereuromark@users.noreply.github.com> Co-authored-by: Jamison Bryant <jbryant@ticketsauce.com>
Update bake templates and internal code to use the non-deprecated setDelete() and setUpdate() methods instead of the deprecated setOnDelete() and setOnUpdate() methods. Fixes #1045
* Auto-generate foreign key constraint names when not provided When a foreign key is added without an explicit name, the MysqlAdapter and SqliteAdapter now generate a name following the pattern 'tablename_columnname' (e.g., 'articles_user_id' for a FK on the user_id column in the articles table). This matches the behavior of PostgresAdapter and SqlserverAdapter, which already auto-generate FK names. This ensures constraint names are always strings and prevents issues with constraint lookup methods that expect string names. * Update test comparison files for new FK naming convention Update the expected FK names in comparison files and schema dumps to match the new auto-generated naming pattern (tablename_columnname). * Update test comparison files with index rename operations The FK constraint name change from auto-generated (ibfk_N) to explicit (table_column) also affects the implicit index MySQL creates for FKs. Update comparison files to reflect the index rename from user_id to articles_user_id. * Remove unnecessary index operations from comparison file With the FK naming changes, both the lock file and database have the index named articles_user_id, so no diff is needed for this index. Remove the index rename operations that were incorrectly added. * Add conflict resolution for auto-generated FK constraint names (#1042) * Add conflict resolution for auto-generated FK constraint names When auto-generating FK constraint names, check if the name already exists and append a counter suffix (_2, _3, etc.) if needed. This prevents duplicate constraint name errors when multiple FKs are created on the same columns with different references. * Remove unused variable * Truncate FK constraint names to max 128 characters Limit auto-generated foreign key constraint names to 125 characters to ensure the final name (including potential _XX counter suffix) stays within 128 characters. This prevents identifier length errors on databases with strict limits (MySQL: 64, PostgreSQL: 63). * Use database-specific identifier length limits - MySQL: 61 chars (64 limit - 3 for _XX suffix) - PostgreSQL: 60 chars (63 limit - 3 for _XX suffix) - SQL Server: 125 chars (128 limit - 3 for _XX suffix) - SQLite: No limit needed * Use IDENTIFIER_MAX_LENGTH class constant for clarity Each adapter now defines its database-specific identifier length limit as a class constant, making the code more self-documenting.
Document foreign key constraint naming changes
* Add support for database views and triggers (#347) This implements support for creating and managing database views and triggers through CakePHP migrations, addressing issue #347. - Create and drop database views in migrations - Support for OR REPLACE syntax (MySQL, PostgreSQL) - Materialized views support (PostgreSQL only) - Database-agnostic API with adapter-specific implementations - Create and drop database triggers in migrations - Support for BEFORE/AFTER/INSTEAD OF timing - Support for INSERT/UPDATE/DELETE events - Support for multiple events per trigger - FOR EACH ROW vs FOR EACH STATEMENT options **Value Objects:** - `Migrations\Db\Table\View` - Represents a database view - `Migrations\Db\Table\Trigger` - Represents a database trigger **Actions:** - `Migrations\Db\Action\CreateView` - Action for creating views - `Migrations\Db\Action\DropView` - Action for dropping views - `Migrations\Db\Action\CreateTrigger` - Action for creating triggers - `Migrations\Db\Action\DropTrigger` - Action for dropping triggers **Core:** - `AbstractAdapter` - Added abstract methods for view/trigger support - `Table` - Added createView(), dropView(), createTrigger(), dropTrigger() - `BaseMigration` - Added convenience methods for easy migration usage **Adapters:** - `MysqlAdapter` - MySQL-specific view/trigger SQL generation - `PostgresAdapter` - PostgreSQL implementation with materialized views - `SqliteAdapter` - SQLite-specific syntax handling - `SqlserverAdapter` - SQL Server implementation ```php // Create a view $this->createView( 'active_users', 'SELECT * FROM users WHERE status = "active"' ); // Create a materialized view (PostgreSQL) $this->createView( 'user_stats', 'SELECT user_id, COUNT(*) FROM posts GROUP BY user_id', ['materialized' => true] ); // Create a trigger $this->createTrigger( 'users', 'log_changes', 'INSERT', "INSERT INTO audit_log VALUES (NEW.id, NOW())", ['timing' => 'AFTER'] ); // Drop view/trigger $this->dropView('active_users'); $this->dropTrigger('users', 'log_changes'); ``` Added comprehensive tests for view and trigger functionality in MysqlAdapterTest covering creation, querying, and deletion. Added example migration file demonstrating various view and trigger scenarios with database-specific considerations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix AbstractAdapterTest by adding stub implementations for view/trigger methods The anonymous test class extending AbstractAdapter needs to implement the new abstract methods for view and trigger support. * Fixes. * Fixes. * Fix missing imports and add return types after merge - Add missing `use Exception` and `use Migrations\Db\Table` imports to AbstractAdapter - Add `: void` return types to algorithm/lock test methods in MysqlAdapterTest - Fix alphabetical ordering of use statements
The issue was a mismatch between CakePHP's LENGTH_LONG constant (4294967295) and migrations' TEXT_LONG constant (2147483647). When using `bake migration_diff`, CakePHP's schema reflection returns LENGTH_LONG for LONGTEXT columns, but MysqlAdapter expected TEXT_LONG. This fix: 1. MigrationHelper: Convert LENGTH_LONG to TEXT_LONG when generating migrations 2. MysqlAdapter: Accept both constants for backward compatibility with existing migrations that have the wrong value Fixes #1029
* Add fluent Table API for check constraints Add addCheckConstraint() and dropCheckConstraint() methods to the Table class, allowing users to manage check constraints using the same fluent API pattern used for indexes and foreign keys. The adapter already had the underlying implementation, this adds: - AddCheckConstraint action class - DropCheckConstraint action class - Table::addCheckConstraint() method - Table::dropCheckConstraint() method - Table::hasCheckConstraint() method - Plan.php updated to handle check constraint actions - Unit tests for the new methods * docs: Fix check constraint API examples Update examples to use the correct API signature: - addCheckConstraint($expression, $options) not addCheckConstraint($name, $expression) - Replace non-existent checkConstraint() fluent builder with CheckConstraint object - Fix all examples throughout the check constraints section
# Conflicts: # src/Db/Adapter/MysqlAdapter.php # src/Db/Adapter/SqliteAdapter.php
* Add migrations reset command for development workflow Implements the "nuclear option" for migrations as discussed in #972: - Drops all application tables (excluding migration tracking tables) - Re-runs all migrations from scratch - Requires interactive Y/N confirmation for safety (default: N) - Supports --dry-run mode to preview changes - Dispatches Migration.beforeReset and Migration.afterReset events This is useful during development when you want a fresh database without manually rolling back or dropping tables. Refs #972 * Fix foreign key handling for PostgreSQL and SQL Server - PostgreSQL: Use CASCADE in DROP TABLE statement - SQL Server: Drop foreign key constraints first before dropping tables - MySQL/SQLite: Continue using session-level FK check toggle * Update completion test to include reset command * Improve reset command logic - Remove sessions from protected tables (true nuclear option) - Rename protectedTables to trackingTables for clarity - Clear seed records (cake_seeds) along with migration records - Rename clearMigrationRecords to clearTrackingRecords * Simplify reset command to drop all tables Instead of preserving tracking tables and clearing their records, just drop everything and let migrations recreate the tables. * Use instanceof for driver type checking and extract helper method - Replace string operations on class names with instanceof checks - Extract runMigrationsAndDispatch() to reduce code duplication * Move FK constraint handling to adapter layer - Add disableForeignKeyConstraints/enableForeignKeyConstraints to AdapterInterface - Implement FK methods in MysqlAdapter (SET FOREIGN_KEY_CHECKS) - Implement FK methods in SqliteAdapter (PRAGMA foreign_keys) - Implement FK methods in SqlserverAdapter (drop all FK constraints) - PostgresAdapter uses no-op methods with CASCADE in dropTable - Add FK methods to AdapterWrapper for delegation - Refactor ResetCommand to use adapter methods instead of dialect-specific code * Add FK constraint methods to test trait
When using the unified `cake_migrations` table, `BakeMigrationDiffCommand::checkSync()` was comparing the last migrated version (from ALL contexts including plugins) against the last migration file in the current context (app or specific plugin). This caused false "not in sync" errors when a plugin had more recent migrations than the app being baked. The fix filters migrated versions to only consider those that have corresponding files in the current context before comparing. Fixes #1060
* initial vitepress conversion * clean up version switcher * add Dockerfile for docs build step * docs: Add anonymous migration classes documentation (#1056) Document the --style anonymous option for bake migration including: - Benefits of anonymous migration classes - Command usage example - Generated code structure - Global Migrations.style configuration option * Fix prev verion urls Use shorthand npm package syntax * Don't run CI on doc changes * adjust docs deploy --------- Co-authored-by: Kevin Pfeifer <kevin.pfeifer@sunlime.at> Co-authored-by: Mark Scherer <dereuromark@users.noreply.github.com>
# Conflicts: # .github/workflows/ci.yml # docs/en/writing-migrations.rst
The MySQL adapter built `DROP FOREIGN KEY <name>` without quoting the
constraint identifier. That produces invalid SQL whenever the constraint
name is not a bare identifier, e.g. names containing whitespace, or the
numeric names ("1", "2", ...) that MariaDB 12 auto-assigns to foreign
keys created without an explicit name.
Quote the identifier via quoteColumnName(), matching the Postgres and
SQL Server adapters, which already quote the dropped constraint name.
* update stan * fix rector issues
Avoids duplicating version support info that is already maintained in the wiki, reducing maintenance burden.
Add security policy
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6 to 7. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](codecov/codecov-action@v6...v7) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](actions/cache@v5...v6) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#1095) Baking a migration with multiple integer primary key columns, e.g. a join table: bin/cake bake migration CreateArticlesTags article_id:integer:primary tag_id:integer:primary generated `autoIncrement => true` on every integer primary key column. MySQL then rejects the table: SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key By convention only a single integer primary key auto-increments; a composite primary key (typical for join tables) must not. ColumnParser now only emits autoIncrement when there is exactly one primary key column.
`AddCheckConstraint::build()` defaults a missing name to an empty string, but the adapters only auto-generated a name when it was `null`. Since `Cake\Database\Schema\Constraint` types the name as a non-nullable string, `getName()` never returns `null`, so the auto-generation branch was dead code and an unnamed check constraint produced invalid SQL, e.g. `ADD CONSTRAINT CHECK (...)` which PostgreSQL rejects with `SQLSTATE[42601]: Syntax error at or near "CHECK"`. Treat an empty string the same as `null` in the Postgres, MySQL and SQLite adapters so a name is generated. Add regression tests for the empty-name path and tighten the MySQL/MariaDB expectation now that migrations supplies the generated name explicitly instead of relying on the database fallback.
The adapter was only set on the migration/seed by the Environment, right before running the migration body - after the shouldExecute() gate in the Manager. As a result shouldExecute() could not query the database (calling getAdapter() threw "Adapter not set."), so eligibility could only depend on local application state, not the state of the database. Set the environment's adapter on the migration and seed before the shouldExecute() check. getEnvironment()->getAdapter() is memoized, so this adds no extra connection, and the Environment still (re)sets and wraps the adapter before executing the body, leaving migrate/rollback behavior unchanged.
#1086) * Add ReversibleMigrationInterface and DirectionalMigrationInterface Introduce two marker interfaces so migrations can declare their style explicitly: - ReversibleMigrationInterface for migrations defining a single change() method (handled with the recording adapter for the down direction). - DirectionalMigrationInterface for migrations defining separate up() and down() methods. Environment now dispatches via instanceof first and keeps the existing method_exists fallback for migrations that have not adopted either interface yet, so the change is backwards compatible. The interfaces declare their method contracts via PHPDoc method tags only (not as real abstract methods), so adopting them is a single-line implements addition with no signature validation pressure. The 6.x release is expected to promote the PHPDoc method tags to real abstract method declarations and drop the method_exists fallback. * Emit capability interface in bake templates Bake-generated migrations now declare implements ReversibleMigrationInterface (change-style) or implements DirectionalMigrationInterface (up/down-style) out of the box. Updated templates: - skeleton.twig (reversible) - skeleton-anonymous.twig (reversible) - diff.twig (directional) - snapshot.twig (reversible or directional based on useChange) All bake comparison fixtures under tests/comparisons/ are updated to match the new output so the bake tests stay green. * Add AddMigrationCapabilityInterfaceRector Ship a rector rule that retrofits the capability interfaces onto existing migrations during the 5.x upgrade. For every class that extends BaseMigration (directly or transitively): - If the class defines change(), add implements ReversibleMigrationInterface. - If the class defines up() or down(), add implements DirectionalMigrationInterface. - Classes already implementing either interface are skipped. - Classes defining both styles are left alone, since the choice is a deliberate one. Abstract migration bases and anonymous migration classes are both supported so the interface propagates through inheritance and through bake's anonymous migration shape. * Document capability interfaces and the upgrade path Add a dedicated upgrade guide at docs/en/upgrades/upgrading-to-capability-interfaces.md covering motivation, per-app before/after examples for both styles, the rector-driven automatic upgrade, the manual residuals (Phinx-style bases, dynamically generated classes, third-party plugins), and the 6.x forward direction. Wire the new page into the VitePress sidebar (toc_en.json) and update the Migration Methods guide so the inline examples already include the implements clause and link to the upgrade guide. * Exclude src/Rector/ from PHPStan analysis The rector rule extends rector/rector base classes which are installed on-demand through the rector-setup composer script rather than as a permanent dev dependency. PHPStan runs before that script in CI and therefore cannot resolve AbstractRector or the Symplify value objects. The rule is type-checked by rector itself when invoked, and downstream apps that wire it into their own rector.php have rector installed locally, so excluding the directory here is the minimal fix that keeps the existing on-demand dependency pattern intact. * Update docs/en/upgrades/upgrading-to-capability-interfaces.md Co-authored-by: Mark Story <mark@mark-story.com> * Match parent visibility of buildOptionParser() The buildOptionParser() overrides in BakeMigrationCommand and the CustomBakeMigrationDiffCommand test command were public, while the parent Command::buildOptionParser() and every other command in the package declare it protected. Rector's MakeInheritedMethodVisibilitySameAsParentRule flagged the mismatch, failing the cs-stan CI job. Align both to protected. * Fix capability-interface Rector rule edge cases Two correctness gaps in AddMigrationCapabilityInterfaceRector surfaced in review: - The rule only checked the target interface, so a class already implementing DirectionalMigrationInterface that also defined change() had ReversibleMigrationInterface added on top, producing a class implementing both mutually exclusive interfaces. Now skip any class already implementing either capability interface, keeping the rule idempotent and honoring the documented "skip if already annotated" behavior. - Directional adoption used "up() OR down()", so a one-way migration (only up() or only down()) had DirectionalMigrationInterface added. Environment calls the matching direction unconditionally for interface-based migrations, so rolling back such a migration turned a previous method_exists() no-op into a fatal undefined-method error. Only adopt the directional interface when both up() and down() exist; one-way migrations stay on the runtime fallback. Mixed-style detection (change() plus any directional method) is preserved. Docblock and the upgrade guide updated to match. --------- Co-authored-by: Mark Story <mark@mark-story.com>
CakePHP reflects `ON UPDATE CURRENT_TIMESTAMP` on datetime/timestamp columns as an `onUpdate` column attribute, but MigrationHelper dropped it in two places: the valid-options list in attributes() and the wanted- options list in getColumnOption(). The clause never reached the template, so any column declaring it lost it when snapshotted. Databases rebuilt from a snapshot then silently stopped auto-updating those columns on writes that bypass the ORM, while existing databases kept the real schema. Let the attribute through both filters and translate it to Phinx's `update` option, mirroring the existing collate/collation handling. Both filters drop the attribute when empty, since Column::toArray() always emits an onUpdate key and Column::setUpdate() is not nullable. * Cover the attributes() half of the ON UPDATE fix The two existing tests fed getColumnOption() a hand-built array, which bypasses attributes() entirely. Removing 'onUpdate' from the valid-options list in attributes() therefore broke snapshot output with zero test failures, even though it is one of the two changes the fix depends on. Add a test that drives attributes() directly and one that walks the whole snapshot path (columns() -> getColumnOption()). Both build the schema by hand rather than reflecting it, so they run on every driver. * Add snapshot regression test for ON UPDATE The MigrationHelper tests build their schema by hand, so they prove the helper emits the option but not that a baked snapshot keeps it. Cover the end-to-end path: reflect a real ON UPDATE column, bake a snapshot, and compare the generated migration against a checked-in file. Gated on MySQL because only MysqlSchemaDialect reflects onUpdate; the other drivers never produce the attribute. Mirrors the existing non-default-collation test, which faces the same constraint. The comparison file differs from the plain snapshot by a single 'update' => 'CURRENT_TIMESTAMP' line on users.updated, while users.created stays bare, so the test also pins down that the option is not applied to columns that never declared it.
EventDispatcherTrait is no longer generic, so the use tag annotations are reported as errors by PHPStan. Unknown subcommands are rejected before they reach EntryCommand, so the error message differs between 5.3 and 5.4. Only the parts both messages have in common are asserted.
Seed classes are not namespaced, so deriving the plugin from the class name never matched and plugin seeds were logged with a null plugin. The plugin of the current run is used instead, matching how migrations are tracked. Because of the null plugin, plugin seeds were also never detected as executed, so they ran again on every seeds run and were skipped by seeds reset. Seed log entries written before this fix are still matched for plugin seeds so that they are not executed a second time. * Use instanceof check for the seed config * Assert command output in plugin seed status and reset tests
This improves the output of `cake` with no parameters.
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.16 to 8.5.25. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.16...8.5.25) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.25 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Pin the image revision used for dokku deployments and reduce permissions for deploy jobs. Pinning the image revision reduces the chances of supply chain attacks on images with access to real credentials.
Migrator::runMany() decided whether to drop tables once per migration set. A migration history is keyed by connection and plugin only, never by source, so two sets differing only in their source write to one history while each of them sees just its own directory on disk. Every set therefore reported its siblings' applied migrations as missing, and the connection was wiped on every run even when the database was already up to date. Sets are now grouped by the history they share, and a logged migration found on disk in any set of the group no longer counts as missing. testRunManyMultipleSkip relied on that spurious drop to trigger its failure, so it now forgets an applied migration to give the second run a genuine reason to drop. It no longer has to be skipped when the unified table is in use.
Co-authored-by: Kevin Pfeifer <kevin@KP-MBP16M4-2025.local> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bring the published
6.xbranch up to current5.nextbefore applying the CakePHP 6 compatibility changes in #1121.This preserves the existing 6.x history, including the nullable modified-column fix from #1026, and merges 5.next rather than replaying that history. The single conflict is the serialized MySQL default-schema fixture; it uses the current 5.next fixture. The resulting files match the previously prepared sync snapshot exactly.
The branch includes the separate 5.next CI repair in #1120. Merge order:
5.next.6.x, preserving its merge ancestry.sync/6.x-5.nextto6.x, then merge its two CakePHP 6 compatibility/code-standard commits.The long commit history in this PR is the intervening 5.next development. The CakePHP 6 dependency, command, schema and code-standard changes are reviewed separately in #1121.
Validation in an isolated installation using this sync snapshot's CakePHP 5 dependencies on PHP 8.5.11:
The published
6.xbranch is unchanged until this PR is merged.