Изменение существующих таблиц
Что это
Когда таблица уже создана, а нужно добавить колонку, индекс или изменить тип — новая миграция с Schema::table.
Создание
php artisan make:migration add_status_to_posts_table --table=posts
Флаг --table=posts создаёт заготовку.
Файл:
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
//
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
//
});
}
Добавление колонки
Schema::table('posts', function (Blueprint $table) {
$table->string('status')->default('draft')->after('title');
});
down:
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('status');
});
Несколько колонок сразу
Schema::table('posts', function (Blueprint $table) {
$table->string('status')->default('draft');
$table->boolean('featured')->default(false);
$table->timestamp('published_at')->nullable();
});
Одна миграция — одна логическая группа. Например, все поля «статус» вместе.
Удаление колонки
$table->dropColumn('status');
$table->dropColumn(['status', 'featured', 'published_at']);
⚠️ Потеря данных — необратимо.
В down нужно вернуть колонку:
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->string('status')->default('draft');
});
}
⚠️ Данные не восстановятся. Только структура.
Переименование колонки
$table->renameColumn('title', 'name');
⚠️ Требует doctrine/dbal в старых MySQL:
composer require doctrine/dbal
Laravel 11+ — не требует.
⚠️ Потеря данных, если длины не совпадают.
Изменение типа — change()
Требует полного переопределения:
$table->string('title', 500)->change();
$table->integer('views')->nullable()->change();
$table->text('bio')->change();
Полный пример:
Schema::table('posts', function (Blueprint $table) {
$table->string('title', 500)->change();
$table->string('slug')->unique()->change();
});
Что задаёшь — то и станет. Всё, что не указал, сбросится.
⚠️ Порядок: для change нужен doctrine/dbal (старые MySQL) или свежая версия Laravel.
Индексы
Добавить:
$table->index('status');
$table->unique('slug');
$table->fullText('body');
$table->index(['status', 'published_at']);
Удалить:
$table->dropIndex(['status']); // по колонкам
$table->dropUnique(['slug']);
$table->dropFullText('body');
$table->dropIndex('posts_status_idx'); // по имени
Внешние ключи
Добавить:
$table->foreignId('user_id')
->after('id')
->constrained()
->cascadeOnDelete();
Удалить:
$table->dropForeign(['user_id']);
$table->dropConstrainedForeignId('user_id'); // + колонка
Переименование таблицы
Schema::rename('posts', 'articles');
⚠️ Ломает код — модели, роуты, FK.
Безопасное удаление
Если колонки может не быть:
if (Schema::hasColumn('posts', 'status')) {
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('status');
});
}
Полезно в миграциях между средами.
Порядок операций
В up:
- Добавить колонку.
- Заполнить данными (если нужно).
- Добавить индекс / FK.
В down:
- Удалить индекс / FK.
- Удалить колонку.
⚠️ Не оставляй orphan-индексы.
Изменение существующих данных
В миграции можно обновлять данные:
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->string('status')->default('draft');
});
DB::table('posts')->whereNull('status')->update(['status' => 'draft']);
}
⚠️ Осторожно на больших таблицах — может блокировать.
Полный пример
public function up(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->string('status')
->default('draft')
->after('title')
->index();
$table->boolean('featured')
->default(false)
->after('status');
$table->timestamp('published_at')
->nullable()
->after('featured');
$table->index(['status', 'published_at']);
});
}
public function down(): void
{
Schema::table('posts', function (Blueprint $table) {
$table->dropIndex(['status', 'published_at']);
$table->dropColumn(['status', 'featured', 'published_at']);
});
}
Практика
1. Добавь в posts:
status— enum(draft/published), default draft.published_at— timestamp, nullable.views_count— integer, default 0.
2. Добавь индекс:
- Составной по
status, published_at.
3. Напиши down — точно наоборот.
4. Проверь:
php artisan migrate
php artisan db:show --table=posts
php artisan migrate:rollback
Частые ошибки
1. Schema::create вместо Schema::table:
Schema::create('posts', ...); // ОШИБКА: таблица уже есть
// Правильно:
Schema::table('posts', ...)
2. Забыли down:
public function down(): void { }
// migrate:rollback не откатит
3. dropColumn без down для добавления:
up(): добавь колонку
// down: пусто → колонка останется
4. change без полного описания:
$table->string('title')->change(); // длина 255, not null
// Потеряли nullable и default
5. renameColumn без doctrine/dbal (старые MySQL):
composer require doctrine/dbal
Итог
Schema::table— для изменения.dropColumn— удалить.renameColumn— переименовать.->change()— изменить тип.dropIndex,dropForeign— удалить индексы.down— точное отражениеup.- Правило: данные теряются, но структура — восстанавливается.
Дальше — индексы и производительность.