In the end, I couldn't find a native solution. If one does exist, please share it. I'll leave my own solution here, which I achieved using a Blueprint macro.
For column declaration, you currently need to specify the column type, for example, you can create a varchar
by using the string()
function. It is not possible to reference an existing column without specifying the type.
I created a macro for Blueprint that I named column
. I pass the name of the existing column to it. (1) It queries the column's data based on the table and column name, then calls the appropriate function with the correct parameters. (2) After this, it becomes easy to set the current attributes based on the data found in the database. These will be overridable later.
Blueprint::macro('column', function (string $column) {
/** @var \Illuminate\Database\Schema\Blueprint $this */
$table = $this->getTable();
$columns = collect(Schema::getColumns($table));
$columnData = $columns->firstWhere('name', $column);
/** Get current definition by column's type */
$type = $columnData['type'];
if (preg_match('/^(\w+)(?:\(([^)]+)\))?$/', $type, $matches)) {
$dataType = $matches[1]; // ex. varchar(255) -> varchar
$parameters = isset($matches[2]) ? explode(',', $matches[2]) : []; // ex. varchar(255) -> [255]
return $this->addColumn($dataType, $column, ...array_map('trim', $parameters));
}
else {
throw new \RuntimeException(sprintf(
'Invalid column type format: "%s". Expected a valid SQL type like "varchar(255)" or "boolean".',
$type
));
}
/** Set current attributes */
if ($columnData['nullable']) {
$definition->nullable();
} else {
$definition->notNullable();
}
if (! is_null($columnData['default'])) {
$definition->default($columnData['default']);
}
if (strpos($columnData['type'], 'unsigned') !== false) {
$definition->unsigned();
}
if ($columnData['auto_increment']) {
$definition->autoIncrement();
}
if (! is_null($columnData['comment'])) {
$definition->comment($columnData['comment']);
}
return $definition;
});
It retains its previous type, unsigned, default(1), and comment attributes, and from now on, it will also be nullable.
Schema::table('users', function (Blueprint $table) {
$table->column('votes')->nullable()->change();
});