Настройка абстрактной базы данных в Laravel с помощью миграций и сидеров

Миграции и сидеры – производительные утилиты для работы с БД, предоставляемые PHP-фреймворком Laravel. Благодаря миграциям и сидерам разработчики могут быстро инициализировать, удалить и восстановить базу данных своего приложения. Эти утилиты помогают минимизировать несогласованности и конфликты данных внутри БД (они возникают в базах, с которыми одновременно работают несколько разработчиков ). Если к разработке приложения присоединяются новые участники, им нужно запустить всего несколько команд artisan, чтобы получить текущую базу данных.

В этом мануале вы научитесь использовать миграции и сидеры для заполнения базы данных простого тестового приложения Laravel. Вы узнаете, как с помощью этих утилит можно удалять и восстанавливать таблицы БД.

Требования

Примечание: Этот мануал протестирован в контейнеризованной среде разработки приложения на основе 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. Если вы еще не обновили индекс пакетов, сделайте это сейчас:

sudo apt update

Установите пакет unzip:

sudo apt install unzip

Распакуйте архив:

unzip travellist.zip

Переименуйте полученный каталог в travellist-demo, чтобы его было проще найти:

mv travellist-laravel-demo-tutorial-2.0.1 travellist-demo

Теперь у вас есть тестовое приложение. Можно приступать к настройке.

2: Создание файла .env для приложения

В Laravel файл .env позволяет создавать зависимую от среды конфигурацию (он хранит учетные данные и любую другую информацию, которая может отличаться в зависимости от развертывания). Этот файл не включается в контроль версий.

Важно! В конфигурационном файле среды хранится важная информация о сервере, в том числе учетные данные БД и ключи безопасности. Не рекомендуем выкладывать этот файл в открытый доступ.

Все значения из файла .env имеют более высокий приоритет, чем значения из обычных конфигурационных файлов в каталоге config. Каждая установка в новой среде требует индивидуальный файл среды, в котором определяются следующие настройки: параметры подключения к БД и отладки, URL приложения и другие параметры (это зависит от среды, которую вы используете для запуска приложения).

Перейдите в каталог travellist-demo:

cd travellist-demo

Сейчас нужно создать новый файл .env для хранения индивидуальных параметров нашей будущей среды разработки. Laravel предоставляет образец файла .env, его можно скопировать и использовать в качестве шаблона для нашего собственного файла:

cp .env.example .env

Откройте файл с помощью nano:

nano .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 можно установить все зависимости нашего приложения и включить поддержку команд artisan.

Запустите среду Docker Compose при помощи следующей команды. Это создаст образ travellist для сервиса app и добавит другие дополнительные образы Docker (они нужны сервисам nginx и db, чтобы создать среду).

docker-compose up -d

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 любые необходимые команды. exec использует следующий синтаксис:

docker-compose exec service_name command

Примечание: Если вы работаете на стеке LEMP, вы можете пропустить в командах часть «docker-compose exec app» в рамках этого мануала. То есть вместо следующей команды:

docker-compose exec app composer install

вы можете использовать команду:

composer install

Чтобы выполнить команду composer install в контейнере приложения, запустите:

docker-compose exec app composer install
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

Эта команда удалит все существовавшие таблицы в вашей БД. Если команда выполнена успешно, а приложение смогло подключиться к БД, вы увидите такой результат:

Dropped all tables successfully.

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

Инструмент командной строки artisan поставляется вместе с Laravel. Он предлагает ряд вспомогательных команд, при помощи которых можно управлять приложением и загружать новые классы. Чтобы создать новый класс миграции, используйте команду make:migration:

docker-compose exec app php artisan make:migration create_places_table

Laravel определяет операцию, которую необходимо выполнить (create), имя таблицы (places), а также запрашивает, должна ли данная миграция создать новую таблицу. Все эти данные включены в описательное имя в команде make:migration. Вывод будет выглядеть так:

Created Migration: 2020_02_03_143622_create_places_table

После этого в каталоге приложения database/migrations появится новый файл. С помощью метки времени, которая включается в этот сгенерированный файл, Laravel определяет, в каком порядке нужно выполнять миграции.

Откройте этот файл миграции. Обязательно укажите в этой команде имя вашего файла:

nano database/migrations/2020_02_03_143622_create_places_table.php

В файле находится класс по имени CreatePlacesTable:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
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. Полю visited мы зададим значение по умолчанию 0 (и если этому полю не будет передано значение, это будет означать, что данный город еще не посещен). В итоге метод up выглядит так:


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 по имени PlacesTableSeeder для таблицы places:

docker-compose exec app php artisan make:seeder PlacesTableSeeder

Команда создаст новый файл PlacesTableSeeder.php в каталоге database/seeds. Откройте его в редакторе:

nano database/seeds/PlacesTableSeeder.php

Автоматически сгенерированный файл PlacesTableSeeder.php выглядит так:

<?php
use Illuminate\Database\Seeder;
class PlacesTableSeeder extends Seeder
{
/**
     * Run the database seeds.
     *
     * @return void
     */
public function run()
{
//
}
}

Новый сидер содержит пустой метод run. Он будет вызываться при выполнении команды db:seed.

Теперь нужно отредактировать метод run и добавить в него инструкции для вставки данных в БД. Для этого мы используем конструктор запросов Laravel.

С помощью этого конструктора Laravel предоставляет гибкий и удобный интерфейс для работы с БД (в том числе для вставки, обновления и восстановления данных). Также конструктор запросов защищает приложение от инъекций SQL-кода. Конструктор запросов определяется фасадом DB (это статический прокси для классов БД в контейнере сервиса).

Давайте создадим переменную статического класса, которая в форме массива будет хранить названия всех городов, которые мы хотим вставить в БД. Благодаря этому мы сможем использовать цикл foreach для итерации по всем значениям и вставить все эти значения в БД.

Давайте назовем эту переменную $places:

<?php
use Illuminate\Database\Seeder;
class PlacesTableSeeder extends Seeder
{
static $places = [

'Berlin',


'Budapest',


'Cincinnati',


'Denver',


'Helsinki',


'Lisbon',


'Moscow',


'Nairobi',


'Oslo',


'Rio',


'Tokyo'


];

После этого нужно включить в начало класса PlacesTableSeeder оператор use, чтобы упростить ссылку на фасад DB в коде:

<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class PlacesTableSeeder extends Seeder

Теперь можно итерировать массив $places с помощью цикла foreach и вставить все значения из массива в таблицу places при помощи конструктора запросов.


public function run()
{
foreach (self::$places as $place) {
DB::table('places')->insert([
'name' => $place,
'visited' => rand(0,1) == 1
]);
}
}

Цикл foreach переберет все значения статического массива $places. При каждой итерации фасад DB используется для добавления новой строки в таблицу places. Название города, которое мы только что извлекли из массива $places, вставляется в поле name, а в поле visited вставляется случайное значение 0 или 1.

Учитывая все изменения, класс PlacesTableSeeder будет выглядеть так:

<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
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
]);
}
}
}

Сохраните и закройте файл.

Классы сидеров не загружаются в приложение автоматически. Для этого нам нужно самостоятельно отредактировать главный класс DatabaseSeeder и включить в него новый сидер.

Откройте database/seeds/DatabaseSeeder.php:

nano database/seeds/DatabaseSeeder.php

Класс DatabaseSeeder выглядит так же, как любой стандартный сидер: он расширяется из класса Seeder и включает метод run. Давайте обновим этот метод, включив в него PlacesTableSeeder.

Обновите метод run в классе DatabaseSeeder. Для этого удалите закомментированную строку и замените ее следующей:


public function run()
{
$this->call(PlacesTableSeeder::class);
}
...

Теперь ваш класс DatabaseSeeder выглядит так:

<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
     * Seed the application's database.
     *
     * @return void
     */
public function run()
{
$this->call(PlacesTableSeeder::class);
}
}

Сохраните и закройте файл.

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

6: Запуск миграций и сидеров БД

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

Чтобы создать ключ шифрования для Laravel, используйте команду:

docker-compose exec app php artisan key:generate

Создав ключ, вы сможете открыть приложение в браузере, указав имя хоста или IP-адрес и порт 8000:

http://server_host_or_ip:8000

На странице будет фраза:

A table was not found
You might have forgotten to run your migrations […]

Это значит, что приложение подключается к БД, но не находит таблицу по имени places. Давайте создадим таблицу places с помощью этой команды:

docker-compose exec app php artisan migrate

Вывод будет выглядеть так:

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 установлен. Сейчас мы не будем использовать эти дополнительные таблицы, но они пригодятся в будущем при расширении функционала приложения (например, при настройке аутентификации пользователей и планирования заданий). Пока что вы можете оставить эти таблицы без изменений.

На данный момент таблица places пуста. Запустите следующую команду, чтобы заполнить БД данными:

docker-compose exec app php artisan db:seed

Эта команда запустит сидер, а он добавит в таблицу значения, которые мы определили в классе PlacesTableSeeder. Вывод будет выглядеть так:

Seeding: PlacesTableSeeder
Seeded:  PlacesTableSeeder (0.06 seconds)
Database seeding completed successfully.

Перезагрузите страницу в браузере. Вы увидите список городов.

Если вам нужно начать все сначала, вы можете очистить все таблицы вашей БД с помощью команды:
docker-compose exec app php artisan db:wipe

Dropped all tables successfully.

Чтобы запустить миграцию и заполнить таблицы данными с помощью одной команды, используйте эту команду:

docker-compose exec app php artisan migrate --seed
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. Как правило, этот метод удаляет все таблицы, созданные в классах миграции, оставляя те таблицы, которые могли быть созданы вручную. Вы увидите такой вывод:

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).

Tags: , , , , ,

Добавить комментарий