База данных: Миграции

Миграции — это как система контроля версий для вашей базы данных. Представьте, что вы работаете над проектом в команде и каждый разработчик меняет структуру базы данных по-своему (кто-то добавил колонку, кто-то переименовал таблицу). Через неделю никто не помнит, что и когда менялось. Миграции решают эту проблему — каждая миграция это как коммит в git, но для схемы базы данных.

Миграции позволяют:

  • Синхронизировать схему БД между разработчиками
  • Версионировать изменения структуры
  • Откатывать изменения, если что-то пошло не так
  • Обновлять базу на продакшене без потери данных

Конфигурирование

По умолчанию Imhotep использует таблицу migrations для отслеживания выполненных миграций:

'migrations' => [
    'table' => 'migrations',
    'connection' => null,  // Подключение для миграций (null = default)
],
PHP

Создание миграций

Для создания миграции, воспользуйтесь консольной командой:

php imhotep make:migration create_users_table
BASH

Команда создаст файл в папке database/migrations с именем, содержащим текущую дату и время:

database/migrations/
└── 2026_08_05_103245_create_users_table.php
TEXT

Именование миграций

Imhotep определяет тип операции по имени миграции:

Имя миграции Что делает
create_users_table Создание таблицы users
add_role_to_users_table Добавление колонки role
drop_role_from_users_table Удаляет колонку role из таблицы users
rename_role_column Переименовывает колонку (если указана таблица)

Совет: Давайте миграциям осмысленные имена. Через месяц вы будете благодарны себе, когда увидите в списке add_soft_deletes_to_users_table вместо update_users.

Структура миграции

Пример миграции с дополнительными полезными свойствами, которые не обязательно указывать.

<?php

use Imhotep\Database\Migrations\Migration;
use Imhotep\Database\Schema\Blueprint;

return new class extends Migration
{
    // Какое подключение к БД использовать (по умолчанию текущее)
    public ?string $connection = 'mysql';
    
    // Выполнять миграцию в транзакции (по умолчанию true)
    public bool $useTransaction = true;

    // Код, который применяет изменения
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    // Код, который откатывает изменения
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
PHP
  • Метод up() — выполняется при применении миграции. Здесь вы создаете таблицы, добавляете колонки, индексы.
  • Метод down() — выполняется при откате. Здесь вы отменяете изменения, сделанные в up().

Управление миграциями

Ниже предоставлен список основных команд, которые вам понадобятся:

# Применить все ожидающие миграции
php console migrate

# Показать, что будет выполнено (без реальных изменений)
php console migrate --pretend

# Увеличить batch для каждой миграции (полезно для CI/CD)
php console migrate --step

# Применить конкретную миграцию по имени файла
php console migrate --name=create_users_table

# Откатить последнюю миграцию
php console migrate:rollback

# Откатить указанное количество миграций
php console migrate:rollback --step=3

# Откатить все миграции
php console migrate:reset

# Откатить и применить заново (сброс)
php console migrate:refresh

# Показать статус всех миграций
php console migrate:status

# Создать таблицу миграций (если не создана)
php console migrate:install
BASH

Работа с базами данных

Фасад Schema позволяет создавать и удалять базы данных. Это удобно для настройки окружений, тестирования и автоматизации развертывания.

Некоторые СУБД (например, SQLite) используют файлы вместо классических баз данных, поэтому методы createDatabase и dropDatabase работают с файловой системой.

use Imhotep\Facades\Schema;

// Создание базы данных
Schema::createDatabase('my_database');

// Удаление базы данных
Schema::dropDatabase('my_database');

// Безопасное удаление (проверка существования)
Schema::dropDatabaseIfExists('my_database');

// Получение списка таблиц
Schema::getTables();
PHP

Работа с таблицами

Таблицы — основа любой базы данных. Фасад Schema предоставляет методы для создания, изменения, переименования и удаления таблиц.

Создание таблицы

use Imhotep\Database\Schema\Table;
use Imhotep\Facades\Schema;

Schema::create('users', function (Table $table) {
    $table->id();
    $table->string('name', 60);
    $table->timestamps();
});
PHP

Изменение таблицы

use Imhotep\Database\Schema\Table;
use Imhotep\Facades\Schema;

Schema::table('table_name', function (Table $table) {
    // Добавление новых колонок
    $table->string('phone', 20)->nullable();
    $table->timestamp('last_login_at')->nullable();
    
    // Изменение колонок
    $table->string('name', 255)->change();
    
    // Переименование колонок
    $table->renameColumn('old_name', 'new_name');
});
PHP

Переименование таблицы

use Imhotep\Facades\Schema;

Schema::rename('old_users', 'new_users');
PHP

Удаление таблиц

use Imhotep\Facades\Schema;

// Безусловное удаление
Schema::drop('users');

// Безопасное удаление (только если существует)
Schema::dropIfExists('users');

// Удаление всех таблиц в базе данных
Schema::dropAllTables();
PHP

Работа со столбцами

После создания таблицы часто требуется добавлять, изменять или удалять отдельные столбцы. Фасад Schema позволяет управлять структурой колонок без полной перестройки таблицы.

Проверка существования

use Imhotep\Facades\Schema;

// Проверка одной колонки
if (Schema::hasColumn('users', 'email')) {
    // Колонка email существует
}

// Проверка нескольких колонок
if (Schema::hasColumns('users', ['email', 'phone'])) {
    // Все колонки существуют
}
PHP

Получение информации

use Imhotep\Facades\Schema;

// Список всех колонок
$columns = Schema::getColumns('users');

// Тип колонки
$type = Schema::getColumnType('users', 'email');
echo "Тип: {$type}\n";
PHP

Переименование столбца

use Imhotep\Facades\Schema;

Schema::renameColumn('old_column', 'new_column');
PHP

Удаление столбцов

use Imhotep\Facades\Schema;

Schema::dropColumn('column');
Schema::dropColumns('table', ['column1', 'column2']);
PHP

Типы столбцов

При создании таблицы нужно указать тип данных для каждой колонки. Imhotep поддерживает все основные типы SQL, адаптированные под конкретную СУБД.

Автоинкремент

$table->id();                           // bigIncrements('id')
$table->bigIncrements('user_id');       // BIGINT UNSIGNED AUTO_INCREMENT
$table->increments('item_id');          // INT UNSIGNED AUTO_INCREMENT
$table->smallIncrements('category_id'); // SMALLINT UNSIGNED AUTO_INCREMENT
PHP

Строковые типы

$table->string('name', 100);             // VARCHAR(100)
$table->char('code', 10);                // CHAR(10)
$table->text('content');                 // TEXT
$table->mediumText('description');       // MEDIUMTEXT
$table->longText('article');             // LONGTEXT
$table->json('meta_data');               // JSON
$table->uuid('id')->primary();           // UUID
PHP

Числовые типы

// Целые числа
$table->integer('age');                   // INT
$table->tinyInteger('status');            // TINYINT
$table->smallInteger('year');             // SMALLINT
$table->mediumInteger('score');           // MEDIUMINT
$table->bigInteger('views');              // BIGINT

// Числа с плавающей точкой
$table->float('price', 8, 2);             // FLOAT(8,2)
$table->double('amount', 15, 8);          // DOUBLE(15,8)

// Десятичные числа (точные)
$table->decimal('salary', 10, 2);         // DECIMAL(10,2)
$table->boolean('is_active');             // BOOLEAN
PHP

Логические типы

$table->boolean('is_active');             // BOOLEAN
PHP

Дата и время

$table->date('birthday');                     // DATE
$table->dateTime('created_at');               // DATETIME
$table->dateTimeTz('created_at');             // DATETIME with timezone
$table->time('start_time');                   // TIME
$table->timeTz('start_time');                 // TIME with timezone
$table->timestamp('created_at');              // TIMESTAMP
$table->timestampTz('created_at');            // TIMESTAMP with timezone
$table->year('founded');                      // YEAR

// Автоматические метки
$table->timestamps();                         // created_at и updated_at
$table->softDeletes();                        // deleted_at для мягкого удаления
PHP

Бинарные типы

$table->binary('image_data');                 // BLOB
PHP

Модификаторы столбцов

Модификаторы уточняют поведение колонки: можно ли хранить NULL, какое значение по умолчанию, нужен ли индекс и т.д. Модификаторы применяются цепочкой после метода типа.

$table->string('name')
    ->nullable()                              // Разрешить NULL
    ->default('John Doe')                     // Значение по умолчанию
    ->unique()                                // Уникальное значение
    ->index()                                 // Индекс
    ->primary()                               // Первичный ключ
    ->comment('User full name');              // Комментарий

$table->integer('position')
    ->unsigned()                              // Беззнаковое целое
    ->autoIncrement()                         // Автоинкремент
    ->after('id');                            // Разместить после колонки

$table->decimal('price', 10, 2)
    ->default(0.00)
    ->change();                               // Изменить существующую колонку
PHP

Внешние ключи

Внешние ключи обеспечивают целостность данных на уровне базы данных. Они связывают таблицы и автоматически контролируют изменения связанных записей.

Создание внешних ключей

use Imhotep\Facades\Schema;

Schema::create('posts', function (Table $table) {
    $table->id();
    
    $table->foreignId('user_id')
        ->constrained('users') // Ссылка на users.id
        ->onDeleteCascade();   // Удаление постов при удалении пользователя
        
    $table->foreignId('category_id')
        ->references('id')->on('categories')
        ->onDeleteRestrict();  // Запрет удаления категории с постами
        
    $table->foreign(['user_id', 'role_id'])
        ->references(['id', 'role_id'])->on('user_roles')
        ->onUpdateCascade();
});
PHP

Действия ON DELETE и ON UPDATE

При создании внешнего ключа можно указать, что произойдет с зависимыми записями при удалении или обновлении родительской записи.

  • CASCADE - Автоматически удалить/обновить зависимые записи;
  • RESTRICT - Запретить удаление/обновление, если есть зависимые записи;
  • SET NULL - Установить NULL в поле внешнего ключа;
  • SET DEFAULT - Установить значение по умолчанию в поле внешнего ключа;
  • NO ACTION - Ничего не делать (проверка в конце транзакции).

Для каждого действия есть соответствующий метод:

ON DELETE ON UPDATE
onDeleteCascade() onUpdateCascade()
onDeleteRestrict() onUpdateRestrict()
onDeleteSetNull() onUpdateSetNull()
onDeleteSetDefault() onUpdateSetDefault()
// ON DELETE CASCADE — удаление пользователя удаляет все его посты
$table->foreignId('user_id')
    ->constrained('users')
    ->onDeleteCascade();

// ON DELETE RESTRICT — нельзя удалить категорию, если есть посты
$table->foreignId('category_id')
    ->constrained('categories')
    ->onDeleteRestrict();

// ON DELETE SET NULL — при удалении пользователя,
// поле user_id становится NULL
$table->foreignId('user_id')
    ->constrained('users')
    ->onDeleteSetNull();

// ON DELETE SET DEFAULT — при удалении пользователя,
// поле user_id получает значение по умолчанию
$table->foreignId('user_id')
    ->constrained('users')
    ->onDeleteSetDefault();

// ON UPDATE CASCADE — при изменении ID пользователя,
// обновляются все связанные записи
$table->foreignId('user_id')
    ->constrained('users')
    ->onUpdateCascade();

// Комбинация ON DELETE и ON UPDATE
$table->foreignId('user_id')
    ->constrained('users')
    ->onDeleteCascade()
    ->onUpdateCascade();
PHP

Удаление внешних ключей

use Imhotep\Facades\Schema;

Schema::table('posts', function (Table $table) {
    // Удаление по имени колонки
    $table->dropForeign(['user_id']);
    
    // Удаление по имени внешнего ключа
    $table->dropForeign('posts_user_id_foreign');
});
PHP

Индексы

Индексы ускоряют поиск данных, но замедляют операции вставки и обновления. Используйте их осознанно:

  • primary — для первичных ключей (autoincrement)
  • unique — для уникальных значений (email, slug)
  • index — для часто фильтруемых колонок
  • fulltext — для полнотекстового поиска
  • spatial — для геоданных

Создание индексов

use Imhotep\Facades\Schema;

Schema::create('posts', function (Table $table) {
    // Простые индексы
    $table->index('title');                    // INDEX
    $table->index(['title', 'content']);      // Составной индекс
    
    // Уникальные индексы
    $table->unique('slug');                   // UNIQUE INDEX
    $table->unique(['category_id', 'slug']);  // Составной уникальный
    
    // Первичный ключ
    $table->primary('id');                    // PRIMARY KEY
    $table->primary(['user_id', 'role_id']); // Составной первичный ключ
    
    // Полнотекстовый индекс
    $table->fulltext('content');              // FULLTEXT INDEX
    
    // Пространственный индекс (для гео-данных)
    $table->spatial('location');              // SPATIAL INDEX
    
    // Индекс с пользовательским именем
    $table->index('title', 'idx_posts_title');
});
PHP

Добавление индексов в существующую таблицу

use Imhotep\Facades\Schema;

Schema::table('posts', function (Table $table) {
    $table->index('title');
    $table->unique('slug');
});
PHP

Удаление индексов

use Imhotep\Facades\Schema;

Schema::table('posts', function (Table $table) {
    // По имени колонки
    $table->dropIndex(['title']);
    $table->dropUnique(['slug']);
    $table->dropPrimary(['id']);
    
    // По имени индекса
    $table->dropIndex('idx_posts_title');
    $table->dropUnique('posts_slug_unique');
});
PHP

Особенности СУБД

PostgreSQL

  • Поддерживает serial и bigserial типы
  • Есть timestampTz и timeTz для работы с часовыми поясами
  • Поддерживает jsonb тип

MySQL

  • Поддерживает tinyInteger, mediumInteger
  • Есть enum тип
  • Поддерживает charset и collate для колонок

SQLite

  • Ограниченная поддержка ALTER TABLE
  • Нельзя удалять или переименовывать колонки в одной транзакции