fix: proper type coercion for raw SQL import columns
Read column metadata (type, nullable, default) from SHOW COLUMNS and coerce values accordingly: empty string/false → 0 for NOT NULL numeric columns, null for nullable ones. Fixes is_internal import error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -309,9 +309,12 @@ class EntityImporter
|
||||
return $newId;
|
||||
}
|
||||
|
||||
/** @var array<string, string[]> Cache of existing columns per table */
|
||||
/** @var array<string, string[]> Cache of existing column names per table */
|
||||
private array $tableColumnsCache = [];
|
||||
|
||||
/** @var array<string, array<string, array>> Cache of column metadata per table */
|
||||
private array $tableColumnMetaCache = [];
|
||||
|
||||
/** @var array<string, string[]> Skipped columns log per entity type */
|
||||
private array $skippedColumnsLog = [];
|
||||
|
||||
@@ -348,10 +351,8 @@ class EntityImporter
|
||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
// Fix empty strings for integer/bool columns (MySQL strict mode)
|
||||
if ($value === '' || $value === false) {
|
||||
$value = null;
|
||||
}
|
||||
// Coerce value to match target column type
|
||||
$value = $this->coerceValue($tableName, $column, $value);
|
||||
|
||||
$columns[] = "`{$column}`";
|
||||
$values[] = $value;
|
||||
@@ -377,16 +378,59 @@ class EntityImporter
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
$sth = $pdo->query("SHOW COLUMNS FROM `{$tableName}`");
|
||||
$columns = [];
|
||||
$meta = [];
|
||||
|
||||
while ($row = $sth->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$columns[] = $row['Field'];
|
||||
$meta[$row['Field']] = [
|
||||
'type' => $row['Type'],
|
||||
'nullable' => $row['Null'] === 'YES',
|
||||
'default' => $row['Default'],
|
||||
];
|
||||
}
|
||||
|
||||
$this->tableColumnsCache[$tableName] = $columns;
|
||||
$this->tableColumnMetaCache[$tableName] = $meta;
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce a value to be compatible with the target column type.
|
||||
*/
|
||||
private function coerceValue(string $tableName, string $column, mixed $value): mixed
|
||||
{
|
||||
$meta = $this->tableColumnMetaCache[$tableName][$column] ?? null;
|
||||
|
||||
if ($meta === null) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$type = strtolower($meta['type']);
|
||||
$isNumeric = str_contains($type, 'int') || str_contains($type, 'decimal')
|
||||
|| str_contains($type, 'float') || str_contains($type, 'double')
|
||||
|| str_contains($type, 'tinyint') || str_contains($type, 'smallint')
|
||||
|| str_contains($type, 'bigint');
|
||||
|
||||
if ($isNumeric && ($value === '' || $value === false)) {
|
||||
if ($meta['nullable']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$meta['nullable'] && $value === null) {
|
||||
if ($isNumeric) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $meta['default'] ?? '';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string[]> entityType => [skipped column names]
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user