Миграции и пополнения — это мощные утилиты для базы данных, предоставляемые PHP-фреймворком Laravel, которые позволяют разработчикам быстро инициализировать, уничтожать и воссоздавать базу данных приложения. Эти утилиты помогают свести к минимуму проблемы несогласованности базы данных, которые могут возникать, когда несколько разработчиков работают над одним приложением: новым участникам нужно будет запустить всего несколько команд artisan
для настройки базы данных при новой установке.
В этом обучающем руководстве мы выполним миграцию и пополнения для заполнения базы данных демонстрационного приложения Laravel, используя примеры данных. В конце вы сможете уничтожать и воссоздавать таблицы базы данных в любой момент времени, пользуясь только командами artisan
.
Предварительные требования
Для выполнения этого обучающего руководства вам потребуется следующее:
Примечание. В этом обучающем руководстве мы будем использовать контейнеризованную среду разработки под управлением Docker Compose для запуска приложения, но вы можете использовать приложение на сервере LEMP. Чтобы воспользоваться этим вариантом, ознакомьтесь с нашим руководством по установке и настройке Laravel с LEMP в Ubuntu 18.04.
Шаг 1 — Получение демонстрационного приложения
Вначале мы получим демонстрационное приложение Laravel из репозитория GitHub. Нас интересует раздел tutorial-02
, который содержит настройку Docker Compose для запуска приложения в контейнерах. В данном примере мы загрузим приложение в домашнюю папку, но вы можете использовать любую директорию по вашему выбору:
- cd ~
- curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-2.0.1.zip -o travellist.zip
Поскольку мы загрузили код приложения в виде файла .zip
, нам нужно воспользоваться командой unzip
для распаковки архива. Если вы не использовали эту программу в последнее время, обновите локальный индекс пакетов вашего компьютера:
Затем выполните установку пакета unzip
:
Распакуйте содержимое приложения:
Далее необходимо переименовать директорию на travellist-demo для удобства доступа:
- mv travellist-laravel-demo-tutorial-2.0.1 travellist-demo
На следующем шаге мы создадим файл конфигурации .env
для настройки приложения.
Шаг 2 — Настройка файла .env
приложения
В Laravel файл .env
используется для настройки зависимых от среды конфигураций, например, учетных данных и любой информации, которая может отличаться для разных развертываний. Этот файл не включен в систему контроля версий.
Предупреждение. Файл конфигурации среды содержит важную информацию о вашем сервере, включая учетные данные базы данных и ключи безопасности. В связи с этим не следует предоставлять этот файл в открытый доступ.
Значения в файле .env
имеют приоритет по отношению к значениям в обычных файлах конфигурации, расположенных в директории config
. Для каждого случая установки в новую среду требуется персонализированный файл среды, где будут определены такие настройки, как параметры подключения к базе данных, параметры отладки, URL приложения и другие параметры, в зависимости от используемой для запуска приложения среды.
Перейдите в директорию travellist-demo
:
Теперь мы создадим новый файл .env
для настройки индивидуальных параметров конфигурации для создаваемой нами среды разработки. В комплектацию Laravel входит образец файла .env
, который мы скопируем для создания собственного файла:
Откройте этот файл с помощью nano
или другого текстового редактора на ваш выбор:
Теперь ваш файл .env
выглядит следующим образом:
.env
APP_NAME=Travellist
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=travellist
DB_USERNAME=travellist_user
DB_PASSWORD=password
…
Текущий файл .env
для демонстрационного приложе
ния travellist содержит настройки для работы в контейнеризованной среде, которую мы создали с помощью Docker Compose в последней статье данной серии. Вам не обязательно вносить изменения в эти значения, но вы можете изменить значения DB_DATABASE
, DB_USERNAME
и DB_PASSWORD
, если захотите, так как они автоматически подставляются из нашего файла docker-compose.yml
для настройки базы данных разработки. Убедитесь, что переменная DB_HOST
остается без изменений, поскольку она указывает имя нашей службы базы данных в среде Docker Compose.
При внесении любых изменений в файл обязательно сохраните и закройте его, нажав CTRL + X
, Y
, а затем ENTER
.
Примечание. Если вы хотите запустить приложение на сервере LEMP, вам нужно изменить выделенные значения в соответствии с собственными настройками базы данных, включая значение переменной DB_HOST
.
Шаг 3 — Установка зависимостей приложения с помощью Composer
Теперь мы воспользуемся Composer, инструментом для управления зависимостями PHP, чтобы установить зависимости приложения и обеспечить возможность выполнения команд artisan
.
Сформируйте вашу среду Docker Compose с помощью следующей команды. В результате будет создан образ travellist
для службы app
и добавлены дополнительные образы Docker, необходимые службам nginx
и db
, чтобы создать среду приложения:
Output
Creating network "travellist-demo_travellist" with driver "bridge"
Building app
Step 1/11 : FROM php:7.4-fpm
---> fa37bd6db22a
Step 2/11 : ARG user
---> Running in 9259bb2ac034
…
Creating travellist-app ... done
Creating travellist-nginx ... done
Creating travellist-db ... done
Выполнение этой операции может занять несколько минут. После завершения процесса мы сможем запустить Composer для установки зависимостей приложения.
Для выполнения composer
и других команд в контейнере службы app
мы будем использовать docker-compose exec
. Команда exec
позволяет нам выполнять любую команду по нашему выбору в контейнерах под управлением Docker Compose. Она имеет следующий синтаксис: docker-compose exec service_name command
.
Примечание. Если вы предпочитаете использовать сервер LEMP для запуска демонстрационного приложения, можно проигнорировать часть docker-compose exec app
для команд, представленных в рамках этого руководства. Например, вместо запуска следующей команды, как она написана, вы можете использовать следующую команду:
Чтобы выполнить установку composer
в контейнер приложения
, запустите следующую команду:
- docker-compose exec app composer install
Output
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 85 installs, 0 updates, 0 removals
- Installing doctrine/inflector (1.3.1): Downloading (100%)
- Installing doctrine/lexer (1.2.0): Downloading (100%)
- Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%)
…
Когда Composer выполнит установку зависимостей приложения, вы сможете выполнять команды artisan
. Чтобы убедиться, что приложение сможет подключиться к базе данных, выполните следующую команду, которая выполняет очистку всех существующих таблиц:
- docker-compose exec app php artisan db:wipe
Эта команда будет удалять все ранее существовавшие таблицы в настроенной базе данных. Если выполнение команды было завершено успешно, а приложению удалось подключиться к базе данных, вы увидите следующий результат:
Output
Dropped all tables successfully.
Теперь, когда вы установили зависимости приложения с помощью Composer, вы можете использовать инструмент artisan
для создания миграций и пополнений.
Шаг 4 — Создание миграций базы данных
Инструмент командной строки artisan
, предоставляемый вместе с Laravel, содержит ряд вспомогательных команд, которые могут использоваться для управления приложением и загрузки новых классов. Чтобы сгенерировать новый класс миграции, мы можем использовать команду make:migration
следующим образом:
- docker-compose exec app php artisan make:migration create_places_table
Laravel выводит операцию, которую необходимо выполнить (create
), имя таблицы (places
), а также то, будет ли эта миграция создавать новую таблицу или нет, на основе описательного имени, предоставленного команде make:migration
.
Вывод будет выглядеть следующим образом:
Output
Created Migration: 2020_02_03_143622_create_places_table
В результате будет создан новый файл в директории database/migrations
приложения. Отметка времени, которая включается в автоматически генерируемый файл, используется Laravel для определения того, в каком порядке следует выполнять миграции.
Используйте предпочитаемый вами текстовый редактор для открытия сгенерированного файла миграции. Обязательно замените выделенное значение на имя вашего файла миграции:
- nano database/migrations/2020_02_03_143622_create_places_table.php
Сгенерированный файл миграции содержит класс CreatePlacesTable
:
database/migrations/2020_02_03_143622_create_places_table.php
<?php
use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
class CreatePlacesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('places', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('places');
}
}
Этот класс имеет два метода: up
и down
. Оба метода содержат код начальной загрузки, который вы можете расширить, чтобы настроить то, что будет происходить, когда эта миграция выполняется, а также что будет происходить в случае отката изменений.
Мы изменим метод up
так, чтобы таблица places
имела структуру, которую мы уже использовали в текущей версии приложения:
id
: поле первичного ключа.name
: название места.visited
: было ли посещено это место или нет.
Конструктор схемы Laravel предоставляет методы для создания, обновления и удаления таблиц в базе данных. Класс Blueprint
определяет структуру таблицы и предоставляет несколько методов для абстракции определения каждого поля таблицы.
Автоматически генерируемый код задает поле основного идентификатора id
. Метод timestamps
создает два поля datetime
, которые автоматически обновляются классами соответствующей базы данных, когда данные помещаются в таблицу или обновляются. Помимо этого, нам потребуется добавить поля name
и visited
.
Наше поле name
будет иметь тип string
, а для поля visited
будет установлен тип boolean
. Также мы зададим значение по умолчанию 0
для поля visited
, так что если значение не будет передано, это будет означать, что место пока не посещено. Вот как в настоящий момент выглядит метод up
:
database/migrations/2020_02_03_143622_create_places_table.php
…
public function up()
{
Schema::create('places', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name', 100);
$table->boolean('visited')->default(0);
$table->timestamps();
});
}
…
Примечание. Вы можете найти полный список доступных типов столбцов в документации Laravel.
После добавления двух выделенных строк в вашем скрипте миграции сохраните и закройте файл.
Теперь ваша миграция готова к исполнению с помощью artisan migrate
. Однако в этом случае будет создана пустая таблица, а нам нужна возможность добавления примеров данных для разработки и тестирования. На следующем шаге мы узнаем, как сделать это с помощью пополнений базы данных.
Шаг 5 — Создание пополнений для базы данных
seeder — это специальный класс, используемый для генерации и вставки примеров данных в базу данных. Это очень важная функция для среды разработки, поскольку она позволяет воссоздать приложение с новой базой данных, используя примеры значений, которые вам в ином случае пришлось бы вручную вставлять при каждом воссоздании базы данных.
Теперь мы воспользуемся командой artisan
, которая генерирует новый класс seeder для нашей таблицы places
с названием PlacesTableSeeder
:
- docker-compose exec app php artisan make:seeder PlacesTableSeeder
Команда будет создавать новый файл с именем PlacesTableSeeder.php
внутри директории database/seeds
. Откройте этот файл в текстовом редакторе по выбору:
- nano database/seeds/PlacesTableSeeder.php
Вот как выглядит автоматически сгенерированный файл PlacesTableSeeder.php
:
database/seeds/PlacesTableSeeder.php
<?php
use IlluminateDatabaseSeeder;
class PlacesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
//
}
}
Наш новый класс seeder содержит пустой метод с именем run
. Этот метод будет вызываться при выполнении команды db:seed
Artisan.
Нам нужно изменить метод run
, чтобы включить инструкции по вставке примеров данных в базу данных. Мы воспользуемся конструктором запросов Laravel для организации этого процесса.
Конструктор запросов Laravel предоставляет гибкий интерфейс для операций с базами данных, например, для вставки, обновления и восстановления данных. Также он обеспечивает защиту от внедрения SQL-кода. Конструктор запросов определяется фасадом DB
, статическим прокси для классов базы данных в контейнере службы.
Для начала мы создадим переменную статического класса, хранящую все примеры мест, которые мы хотим вставить в базу данных в форме массива. Это позволит нам использовать цикл foreach
для итерации по всем значениям, вставляя все эти значения в базу данных с помощью конструктора запросов.
Мы назовем эту переменную $places
:
database/seeds/PlacesTableSeeder.php
<?php
use IlluminateDatabaseSeeder;
class PlacesTableSeeder extends Seeder
{
static $places = [
'Berlin',
'Budapest',
'Cincinnati',
'Denver',
'Helsinki',
'Lisbon',
'Moscow',
'Nairobi',
'Oslo',
'Rio',
'Tokyo'
];
…
Далее нам потребуется включить оператор use
сверху класса PlacesTableSeeder,
чтобы проще ссылаться на фасад DB
в коде:
database/seeds/PlacesTableSeeder.php
<?php
use IlluminateDatabaseSeeder;
use IlluminateSupportFacadesDB;
class PlacesTableSeeder extends Seeder
…
Теперь мы можем пробежаться по значениям массива $places
с помощью цикла foreach
и добавить их в нашу таблицу places
с помощью конструктора запросов:
database/seeds/PlacesTableSeeder.php
…
public function run()
{
foreach (self::$places as $place) {
DB::table('places')->insert([
'name' => $place,
'visited' => rand(0,1) == 1
]);
}
}
Цикл foreach
проходит по каждому значению статического массива $places
. В каждой итерации мы используем фасад DB
для добавления новой строки в таблице places
. Мы сохраним в поле name
название места, которое мы только что получили из массива $places
, а для поля visited
будет использоваться случайное значение 0
или 1
.
Класс PlacesTableSeeder
будет выглядеть следующим образом после всех обновлений:
database/seeds/PlacesTableSeeder.php
<?php
use IlluminateDatabaseSeeder;
use IlluminateSupportFacadesDB;
class PlacesTableSeeder extends Seeder
{
static $places = [
'Berlin',
'Budapest',
'Cincinnati',
'Denver',
'Helsinki',
'Lisbon',
'Moscow',
'Nairobi',
'Oslo',
'Rio',
'Tokyo'
];
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
foreach (self::$places as $place) {
DB::table('places')->insert([
'name' => $place,
'visited' => rand(0,1) == 1
]);
}
}
}
Сохраните и закройте файл после внесения всех изменений.
Классы типа seeder не загружаются автоматически в приложение. Нам нужно изменить главный класс DatabaseSeeder
, чтобы добавить вызов класса типа seeder, который мы только что создали.
Откройте файл database/seeds/DatabaseSeeder.php
с помощью nano
или вашего любимого редактора:
- nano database/seeds/DatabaseSeeder.php
Класс DatabaseSeeder
выглядит стандартным образом: он наследуется от класса Seeder
и имеет метод run
. Мы обновим этот метод, чтобы включить PlacesTableSeeder
.
Обновите текущий метод run
внутри вашего класса DatabaseSeeder
, удалив закомментированную строку и заменив ее на следующий выделенный код:
database/seeds/DatabaseSeeder.php
…
public function run()
{
$this->call(PlacesTableSeeder::class);
}
...
Так будет выглядеть класс DatabaseSeeder
после обновления:
database/seeds/DatabaseSeeder.php
<?php
use IlluminateDatabaseSeeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(PlacesTableSeeder::class);
}
}
Сохраните и закройте файл после внесения изменений в его содержимое.
Мы завершили настройку миграции и наполнения для нашей таблицы places
. На следующем шаге мы узнаем, как их запускать.
Шаг 6 — Запуск миграции и наполнения базы данных
Перед продолжением нужно убедиться, что ваше приложение готово и запущено. Мы настроим ключ шифрования приложения и получим доступ к приложению из браузера, чтобы протестировать веб-сервер.
Чтобы сгенерировать ключ шифрования, требуемый Laravel, вы можете использовать команду artisan key:generate
:
- docker-compose exec app php artisan key:generate
После получения ключа вы сможете получить доступ к приложению, указав в браузере имя хоста сервера или IP-адрес для порта 8000
:
http://server_host_or_ip:8000
Страница будет выглядеть следующим образом:
Это означает, что приложение может подключаться к базе данных, но оно не может найти таблицу с именем places
. Теперь мы создадим таблицу places
, используя следующую команду migrate
artisan:
- docker-compose exec app php artisan migrate
Вывод будет выглядеть следующим образом:
Output
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)
Migrating: 2020_02_10_144134_create_places_table
Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)
Вы увидите, что несколько других миграций было выполнено наряду с настроенной нами миграцией create_places_table
. Эти миграции генерируются автоматически, когда установлен Laravel. Хотя мы не будем использовать эти дополнительные таблицы сейчас, они будут необходимы в будущем при расширении приложения для зарегистрированных пользователей и запланированных заданий. Пока что вы можете оставить их как есть.
На данный момент наша таблица пустая. Нам нужно запустить команду db:seed
, чтобы наполнить базу данных нашими выбранными местами:
- docker-compose exec app php artisan db:seed
В результате будет запущен наш класс seeder и будут добавлены образцы значений, которые мы определили в нашем классе PlacesTableSeeder
. Вывод будет выглядеть следующим образом:
Output
Seeding: PlacesTableSeeder
Seeded: PlacesTableSeeder (0.06 seconds)
Database seeding completed successfully.
Теперь перезагрузите страницу приложения в браузере. Вы увидите приблизительно следующую страницу:
Каждый раз, когда вы захотите начать с нуля, вы можете удалить все ваши таблицы базы данных, используя следующую команду:
- docker-compose exec app php artisan db:wipe
Output
Dropped all tables successfully.
Чтобы запустить миграцию приложения и заполнение таблиц с помощью одной команды, вы можете использовать следующий вариант:
- docker-compose exec app php artisan migrate --seed
Output
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.07 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)
Migrating: 2020_02_10_144134_create_places_table
Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)
Seeding: PlacesTableSeeder
Seeded: PlacesTableSeeder (0.06 seconds)
Database seeding completed successfully.
Если вы захотите откатить изменения, запустите следующую команду:
- docker-compose exec app php artisan migrate:rollback
В результате будет запущен метод down
для каждого класса миграции внутри папки migrations
. Как правило, он удаляет все таблицы, созданные в классах миграции, оставляя все остальные таблицы, которые могли быть созданы вручную. Вывод будет выглядеть следующим образом:
Output
Rolling back: 2020_02_10_144134_create_places_table
Rolled back: 2020_02_10_144134_create_places_table (0.02 seconds)
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back: 2014_10_12_000000_create_users_table (0.02 seconds)
Команда отката изменений особенно полезна, когда вы вносите изменения в модели приложения, а команда db:wipe
не может использоваться, например, если несколько систем используют одну базу данных.
Заключение
В этом руководстве мы увидели, как использовать миграции и наполнения для облегчения настройки баз данных для разработки и тестирования приложения Laravel 6.
В качестве следующего шага вы можете ознакомиться с документацией Laravel для получения более подробной информации о том, как использовать конструктор запросов, и о том, как использовать модели Eloquent для дальнейшей абстракции схемы базы данных вашего приложения.