Миграции и структура базы данных

Рейтинг: 64.6% · 12 голосов
Курс по Laravel: маршруты, Eloquent, Blade, миграции, очереди и API. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
oleg_php
Сообщения: 25
Зарегистрирован: 14 май 2026, 08:06

Миграции и структура базы данных

Сообщение oleg_php »

АкадемияLaravel с нуляГлава 4 из 18
Оглавление курса (18)
  1. Знакомство с Laravel и установка окружения
  2. Маршруты и контроллеры
  3. Blade: шаблоны и вёрстка страниц
  4. Миграции и структура базы данных (вы здесь)
  5. Eloquent ORM: модели и CRUD
  6. Связи в Eloquent: hasMany, belongsTo и другие
  7. Формы и валидация данных
  8. Аутентификация пользователей
  9. Middleware и защита маршрутов
  10. Очереди и фоновые задачи
  11. Отправка почты и уведомления
  12. Строим REST API на Laravel
  13. Авторизация: Gates и Policies
  14. Работа с файлами: загрузка, Storage, диски local и S3
  15. Тестирование: Pest и PHPUnit, фабрики, сидеры, RefreshDatabase
  16. Сервис-контейнер, провайдеры, свои artisan-команды и планировщик
  17. Деплой в продакшен и обзор современного фронтенда (Vite, Livewire, Inertia)
  18. События и слушатели, кеширование, логирование
До этой главы мы обходились без базы: маршруты, контроллеры и Blade жили на жестко прописанных массивах. Дальше так не выйдет, любому реальному приложению нужно хранилище. Эта глава про миграции, механизм, которым Laravel описывает и версионирует структуру базы данных.

Зачем вообще миграции:

Миграция это PHP-файл, который описывает одно изменение схемы: создать таблицу, добавить колонку, повесить индекс. Файлы лежат в database/migrations и попадают в git вместе с остальным кодом. Коллега делает git pull, запускает одну команду и получает ту же структуру базы, что у вас. Никаких "скинь дамп" и SQL-скриптов в чате.

Подключение к базе:

Laravel начиная с 11 версии по умолчанию использует SQLite, файл database/database.sqlite создается при установке проекта. Для учебы этого хватает, но мы сразу настроим MySQL, потому что на боевом хостинге чаще всего будет он или PostgreSQL. Открываем .env:

Код: Выделить всё

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=secret
Саму базу blog нужно создать руками, через консольный клиент mysql или phpMyAdmin. Таблицы внутри нее Laravel дальше создаст за нас. После правки .env проверяем подключение командой db:show, она выведет драйвер, версию сервера и список таблиц.

Первая миграция:

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

Код: Выделить всё

php artisan make:migration create_posts_table
php artisan migrate
php artisan migrate:status
Имя миграции не случайное: по шаблону create_xxx_table артисан сам понимает, что создается таблица posts, и генерирует заготовку с нужным каркасом. В database/migrations появится файл вида 2026_06_11_142530_create_posts_table.php, префикс с датой задает порядок выполнения. Дописываем колонки:

Код: Выделить всё

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title', 200);
            $table->string('slug')->unique();
            $table->text('body');
            $table->boolean('is_published')->default(false);
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
Метод up() применяет изменение, down() его откатывает. $table->id() создает автоинкрементный bigint с первичным ключом, timestamps() добавляет created_at и updated_at, их потом будет автоматически заполнять Eloquent (о нем в следующей главе). Типов колонок десятки: integer, decimal, date, json и так далее, но девяносто процентов времени хватает string, text, boolean, integer и foreignId.

Команда migrate выполняет все миграции, которые еще не применялись, и записывает их в служебную таблицу migrations. Состояние смотрим через migrate:status. Откатить последнюю пачку: migrate:rollback. Снести все таблицы и накатить с нуля: migrate:fresh. На локалке это нормальный рабочий инструмент, на проде путь к увольнению, команда удаляет все таблицы вместе с данными.

Меняем существующую таблицу:

Схема никогда не финальна. Допустим, постам понадобился автор. В старую миграцию не лезем, создаем новую: make:migration add_user_id_to_posts_table с флагом --table=posts. Внутри:

Код: Выделить всё

public function up(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->foreignId('user_id')
            ->after('id')
            ->constrained()
            ->cascadeOnDelete();
    });
}

public function down(): void
{
    Schema::table('posts', function (Blueprint $table) {
        $table->dropConstrainedForeignId('user_id');
    });
}
foreignId('user_id')->constrained() создает колонку и внешний ключ на users.id, имя таблицы Laravel выводит из имени колонки. cascadeOnDelete() удалит посты вместе с их пользователем. Таблица users у вас уже есть, она идет в комплекте со свежим проектом. К связям на уровне моделей мы вернемся в главе про hasMany и belongsTo, на уровне базы фундамент закладывается именно здесь.

Типичные грабли:

Правка уже выполненной миграции. На вашей машине она применилась, повторный migrate ее не тронет, а у коллеги и на проде выполнится уже исправленная версия. Базы разъедутся, и поймать это потом тяжело. Правило: миграция ушла в общую ветку, значит она неприкосновенна, любые изменения только новым файлом. Пока работаете один на локалке, можно откатить через rollback, поправить и накатить снова.

Пустой down(). Заготовка генерирует откат, не выкидывайте его. Без рабочего down() команда rollback однажды упадет в самый неподходящий момент.

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

SQLite локально, MySQL на проде. Работает, пока не наткнетесь на различия в поведении (SQLite заметно терпимее к типам и ограничениям). Надежнее держать локально ту же СУБД, что на боевом сервере, с Docker или Laravel Sail это вопрос пяти минут.

Что усвоили: миграции версионируют схему базы так же, как git версионирует код. Структура описывается через Schema и Blueprint, изменения накатываются вперед новыми файлами, а не правкой старых, и для каждого изменения есть откат. В следующей главе на эти таблицы лягут модели Eloquent, и мы наконец начнем читать и писать данные из контроллеров.
👍4 ❤️2 🔥 😄 🤔1
✔ Лучший ответ сформирован автоматически — mickey101
oleg_php писал(а):на проде путь к увольнению, команда удаляет все таблицы вместе с данными прочитал и вспотел. месяц назад на тестовом стенде сделал fresh вместо rollback и снес данные, которые QA набивали две недели. справедливости ради, при APP_ENV=production laravel переспрашивает подтверждение перед migrate:fresh, так что совсем случайно в прод не выстрелишь. но алиас с лишним вопросом я себе…
Перейти к ответу →
Аватара пользователя
mickey101
Сообщения: 1
Зарегистрирован: 15 май 2026, 00:44

Re: Миграции и структура базы данных

Сообщение mickey101 »

✔ Лучший ответ — сформирован автоматически
oleg_php писал(а):на проде путь к увольнению, команда удаляет все таблицы вместе с данными
прочитал и вспотел. месяц назад на тестовом стенде сделал fresh вместо rollback и снес данные, которые QA набивали две недели. справедливости ради, при APP_ENV=production laravel переспрашивает подтверждение перед migrate:fresh, так что совсем случайно в прод не выстрелишь. но алиас с лишним вопросом я себе все равно завел
👍1 ❤️1 🔥 😄 🤔1
Аватара пользователя
bashsre
Сообщения: 3
Зарегистрирован: 21 май 2026, 17:41

Re: Миграции и структура базы данных

Сообщение bashsre »

а почему базу blog надо создавать руками? логично же было бы первой миграцией сделать CREATE DATABASE и дальше уже таблицы. или миграции в принципе не умеют работать, пока базы нет, потому что им самим нужно куда-то подключиться?
👍3 ❤️1 🔥 😄 🤔
Аватара пользователя
pythonsmith
Сообщения: 1
Зарегистрирован: 13 май 2026, 11:03

Re: Миграции и структура базы данных

Сообщение pythonsmith »

вопрос про изменение типа. если колонка уже на проде и надо string поменять на text, я правильно понимаю, что делаю новую миграцию с $table->text('body')->change()? и нужен ли для change() пакет doctrine/dbal, в старых статьях везде пишут что без него никак
👍 ❤️2 🔥 😄 🤔
Аватара пользователя
ser53
Сообщения: 2
Зарегистрирован: 11 май 2026, 20:46

Re: Миграции и структура базы данных

Сообщение ser53 »

oleg_php писал(а):Надежнее держать локально ту же СУБД, что на боевом сервере
подпишусь, проверено на своей шкуре. миграция с dropColumn у меня на sqlite проходила без вопросов, а на mysql на сервере упала, потому что колонка висела во внешнем ключе и его надо было дропать отдельно. два часа жизни. с тех пор только sail с mysql 8, как на хостинге
👍1 ❤️1 🔥 😄 🤔1
Ответить
← Предыдущая глава
Blade: шаблоны и вёрстка страниц
Следующая глава →
Eloquent ORM: модели и CRUD

Все главы курса «Laravel с нуля»

Поделиться темой: ✈ Telegram VK

Вернуться в «Laravel с нуля»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей