Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions src/Command/BakeMigrationDiffCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,15 @@ protected function getColumns(): void
) {
$changedAttributes = array_diff_assoc($column, $oldColumn);

$isDecimal = isset($column['type']) && $column['type'] === 'decimal';

foreach (['type', 'length', 'null', 'default'] as $attribute) {
$phinxAttributeName = $attribute;
if ($attribute === 'length') {
$phinxAttributeName = 'limit';
$migrationAttributeName = $attribute;
if ($attribute === 'length' && !$isDecimal) {
$migrationAttributeName = 'limit';
}
if (!isset($changedAttributes[$phinxAttributeName])) {
$changedAttributes[$phinxAttributeName] = $column[$attribute];
if (!isset($changedAttributes[$migrationAttributeName])) {
$changedAttributes[$migrationAttributeName] = $column[$attribute];
}
}

Expand All @@ -300,12 +302,34 @@ protected function getColumns(): void
}
}

if (isset($changedAttributes['length'])) {
if (!isset($changedAttributes['limit'])) {
$changedAttributes['limit'] = $changedAttributes['length'];
// For decimal columns, CakePHP schema uses (length, precision) but migrations use (precision, scale)
// Mapping: CakePHP 'length' → migration 'precision' (total digits)
// CakePHP 'precision' → migration 'scale' (decimal places)
// Example: DECIMAL(6,2) in DB = CakePHP ['length' => 6, 'precision' => 2]
// = Migration ['precision' => 6, 'scale' => 2]
if ($isDecimal) {
$decimalAttributes = [];

// Copy all non-decimal-specific attributes (type, null, default, etc.)
foreach ($changedAttributes as $key => $value) {
if ($key !== 'length' && $key !== 'precision') {
$decimalAttributes[$key] = $value;
}
}

unset($changedAttributes['length']);
// Always set both precision and scale for decimal columns
$decimalAttributes['precision'] = $column['length'];
$decimalAttributes['scale'] = $column['precision'];

$changedAttributes = $decimalAttributes;
} else {
if (isset($changedAttributes['length'])) {
if (!isset($changedAttributes['limit'])) {
$changedAttributes['limit'] = $changedAttributes['length'];
}

unset($changedAttributes['length']);
}
}

$this->templateData[$table]['columns']['changed'][$columnName] = $changedAttributes;
Expand Down
24 changes: 22 additions & 2 deletions src/Db/Adapter/MysqlAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,24 @@ protected function afterClause(Column $column): string
*/
protected function getRenameColumnInstructions(string $tableName, string $columnName, string $newColumnName): AlterInstructions
{
$columns = $this->getColumns($tableName);
$targetColumn = null;

foreach ($columns as $column) {
if (strcasecmp($column->getName(), $columnName) === 0) {
$targetColumn = $column;
break;
}
}

if ($targetColumn === null) {
throw new InvalidArgumentException(sprintf(
"The specified column doesn't exist: %s",
$columnName,
));
}

// Fetch raw MySQL column info for the full definition string
$rows = $this->fetchAll(sprintf('SHOW FULL COLUMNS FROM %s', $this->quoteTableName($tableName)));

foreach ($rows as $row) {
Expand All @@ -624,8 +642,10 @@ static function ($value) {
$extra = ' ' . implode(' ', $extras);

if (($row['Default'] !== null)) {
$phinxTypeInfo = $this->getPhinxType($row['Type']);
$extra .= $this->getDefaultValueDefinition($row['Default'], $phinxTypeInfo['name']);
$columnType = $targetColumn->getType();
// Column::getType() can return string|Literal, but getDefaultValueDefinition expects string|null
$columnTypeName = is_string($columnType) ? $columnType : null;
$extra .= $this->getDefaultValueDefinition($row['Default'], $columnTypeName);
}
$definition = $row['Type'] . ' ' . $null . $extra . $comment;

Expand Down
16 changes: 15 additions & 1 deletion tests/TestCase/Command/BakeMigrationDiffCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function tearDown(): void
if (env('DB_URL_COMPARE')) {
// Clean up the comparison database each time. Table order is important.
$connection = ConnectionManager::get('test_comparisons');
$tables = ['articles', 'categories', 'comments', 'users', 'orphan_table', 'phinxlog', 'tags', 'test_blog_phinxlog'];
$tables = ['articles', 'categories', 'comments', 'users', 'orphan_table', 'phinxlog', 'tags', 'test_blog_phinxlog', 'products'];
foreach ($tables as $table) {
$connection->execute("DROP TABLE IF EXISTS $table");
}
Expand Down Expand Up @@ -240,6 +240,20 @@ public function testBakingDiffWithAutoIdIncompatibleUnsignedPrimaryKeys(): void
$this->runDiffBakingTest('WithAutoIdIncompatibleUnsignedPrimaryKeys');
}

/**
* Tests that baking a diff with decimal column changes uses precision and scale
*
* Regression test for https://github.com/cakephp/migrations/issues/659
*
* @return void
*/
public function testBakingDiffDecimalColumn(): void
{
$this->skipIf(!env('DB_URL_COMPARE'));

$this->runDiffBakingTest('DecimalColumn');
}

/**
* Tests that baking a diff with --plugin option only includes tables with Table classes
*/
Expand Down
Loading
Loading