Использование миграции и пополнения базы данных для настройки абстрактной базы данных в Laravel

PostedMarch 5, 2020 846 views PHPPHP FrameworksDatabasesLaravel

Миграции и пополнения — это мощные утилиты для базы данных, предоставляемые 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 для распаковки архива. Если вы не использовали эту программу в последнее время, обновите локальный индекс пакетов вашего компьютера:

  • sudo apt update

Затем выполните установку пакета unzip:

  • sudo apt install unzip

Распакуйте содержимое приложения:

  • unzip travellist.zip

Далее необходимо переименовать директорию на travellist-demo для удобства доступа:

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

На следующем шаге мы создадим файл конфигурации .env для настройки приложения.

Шаг 2 — Настройка файла .env приложения

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

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

Значения в файле .env имеют приоритет по отношению к значениям в обычных файлах конфигурации, расположенных в директории config. Для каждого случая установки в новую среду требуется персонализированный файл среды, где будут определены такие настройки, как параметры подключения к базе данных, параметры отладки, URL приложения и другие параметры, в зависимости от используемой для запуска приложения среды.

Перейдите в директорию travellist-demo:

  • cd travellist-demo

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

  • cp .env.example .env

Откройте этот файл с помощью nano или другого текстового редактора на ваш выбор:

  • nano .env

Теперь ваш файл .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, чтобы создать среду приложения:

  • docker-compose up -d
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 install

Чтобы выполнить установку 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 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. Также мы зададим значение по умолчанию 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 Illuminate\Database\Seeder;

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 Illuminate\Database\Seeder;

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 Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

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 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
            ]);
        }
    }
}

Сохраните и закройте файл после внесения всех изменений.

Классы типа 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 Illuminate\Database\Seeder;

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

Страница будет выглядеть следующим образом:

Ошибка MySQL

Это означает, что приложение может подключаться к базе данных, но оно не может найти таблицу с именем 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.

Теперь перезагрузите страницу приложения в браузере. Вы увидите приблизительно следующую страницу:

Демонстрационное приложение Laravel

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

  • 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 для дальнейшей абстракции схемы базы данных вашего приложения.

0 Comments

Creative Commons License