如何使用数据库迁移和播种器在Laravel中抽象数据库设置

来自菜鸟教程
跳转至:导航、​搜索

MigrationsseedersLaravel PHP 框架提供的强大的数据库实用程序,允许开发人员快速引导、销毁和重新创建应用程序的数据库。 这些实用程序有助于最大程度地减少多个开发人员在同一应用程序上工作时可能出现的数据库不一致问题:新的贡献者只需运行几个 artisan 命令即可在全新安装时设置数据库。

在本指南中,我们将创建迁移和播种器,以使用示例数据填充 Laravel 演示应用程序的数据库。 最后,您将能够只使用 artisan 命令多次销毁和重新创建数据库表。

先决条件

为了遵循本指南,您需要:

注意:在本指南中,我们将使用由 Docker Compose 管理的容器化开发环境来运行应用程序,但您也可以选择在 LEMP 服务器上运行应用程序。 要进行此设置,您可以按照我们关于 如何在 Ubuntu 18.04 上使用 LEMP 安装和配置 Laravel 的指南进行操作。


第 1 步 — 获取演示应用程序

首先,我们将从其 GitHub 存储库 中获取演示 Laravel 应用程序。 我们对 tutorial-02 分支感兴趣,其中包括一个 Docker Compose setup 以在容器上运行应用程序。 在此示例中,我们将应用程序下载到我们的主文件夹,但您可以使用您选择的任何目录:

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 附带了一个 example.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
…

travellist 演示应用程序中的当前 .env 文件包含使用我们在本系列的最后一部分中使用 Docker Compose 创建的容器化环境的设置。 您不需要更改任何这些值,但您可以随意修改 DB_DATABASEDB_USERNAMEDB_PASSWORD,因为这些是由我们的 [ X155X] 文件自动设置开发数据库。 只需确保 DB_HOST 变量保持不变,因为它引用了我们在 Docker Compose 环境中的数据库服务的名称。

如果您对文件进行任何更改,请确保按 CTRL + XY,然后按 ENTER 保存并关闭它。

注意:如果您选择在 LEMP 服务器上运行应用程序,则需要更改突出显示的值以反映您自己的数据库设置,包括 [X185X ] 多变的。


第 3 步 — 使用 Composer 安装应用程序依赖项

我们现在将使用 PHP 的依赖项管理工具 Composer 来安装应用程序的依赖项,并确保我们能够执行 artisan 命令。

使用以下命令启动 Docker Compose 环境。 这将为 app 服务构建 travellist 镜像,并拉入 nginxdb 服务所需的额外 Docker 镜像,以创建应用环境:

docker-compose up -d
OutputCreating 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 来安装应用程序的依赖项。

要在 app 服务容器中执行 composer 和其他命令,我们将使用 docker-compose execexec 命令允许我们在 Docker Compose 管理的容器上执行我们选择的任何命令。 它使用以下语法:docker-compose exec service_name command

注意:如果您选择使用 LEMP 服务器来运行演示应用程序,您应该忽略本指南中列出的命令的 docker-compose exec app 部分。 例如,您只需运行以下命令,而不是运行以下命令:

composer install

要在 app 容器中执行 composer install,请运行:

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

此命令将删除已配置数据库上的所有预先存在的表。 如果它成功运行并且应用程序能够连接到数据库,您将看到如下输出:

OutputDropped all tables successfully.

现在您已经使用 Composer 安装了应用程序依赖项,您可以使用 artisan 工具来创建迁移和播种器。

第 4 步 — 创建数据库迁移

Laravel 附带的 artisan 命令行工具包含一系列帮助命令,可用于管理应用程序和引导新类。 要生成新的迁移类,我们可以使用 make:migration 命令如下:

docker-compose exec app php artisan make:migration create_places_table

Laravel 根据提供给make:migration 命令。

您将看到与此类似的输出:

OutputCreated Migration: 2020_02_03_143622_create_places_table

这将在应用程序的 database/migrations 目录中生成一个新文件。 Laravel 使用自动生成的文件中包含的时间戳来确定迁移的执行顺序。

使用您选择的文本编辑器打开生成的迁移文件。 请记住将突出显示的值替换为您自己的迁移文件名:

nano database/migrations/2020_02_03_143622_create_places_table.php

生成的迁移文件包含一个名为 CreatePlacesTable 的类:

数据库/迁移/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');
    }
}

这个类有两个方法:updown。 这两种方法都包含引导代码,您可以扩展这些代码以自定义执行迁移时发生的情况以及回滚时发生的情况。

我们将修改 up 方法,以便 places 表反映我们在当前应用程序版本中已经使用的结构:

  • id:主键字段。
  • name:地点名称。
  • visited:这个地方是否已经被访问过。

Laravel 模式构建器公开了在数据库中创建、更新和删除表的方法。 Blueprint类定义了表的结构,它提供了几种方法来抽象每个表字段的定义。

自动生成的代码设置了一个名为 id 的主要 id 字段。 timestamps 方法创建两个 datetime 字段,当在该表中插入或更新数据时,底层数据库类会自动更新这些字段。 除了这些,我们还需要包含一个 name 和一个 visited 字段。

我们的 name 字段将是 string 类型,我们的 visited 字段将设置为 boolean 类型。 我们还将为 visited 字段设置默认值 0,这样如果没有传递任何值,则表示该地点尚未访问。 这就是 up 方法现在的样子:

数据库/迁移/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 命令为我们的 places 表生成一个名为 PlacesTableSeeder 的新播种器类:

docker-compose exec app php artisan make:seeder PlacesTableSeeder

该命令将在 database/seeds 目录中创建一个名为 PlacesTableSeeder.php 的新文件。 使用您选择的文本编辑器打开该文件:

nano database/seeds/PlacesTableSeeder.php

这是自动生成的 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 Artisan 命令时会调用此方法。

我们需要编辑 run 方法以包含在数据库中插入样本数据的指令。 我们将使用 Laravel 查询构建器 来简化这个过程。

Laravel 查询构建器为数据库操作提供了一个流畅的界面,例如插入、更新、删除和检索数据。 它还引入了针对 SQL 注入攻击的保护措施。 查询构建器由 DB facade 公开 - 服务容器中底层数据库类的静态代理。

首先,我们将创建一个静态类变量来保存我们想要作为数组插入数据库的所有示例位置。 这将允许我们使用 foreach 循环遍历所有值,使用查询生成器将每个值插入数据库中。

我们称这个变量为 $places

数据库/种子/PlacesTableSeeder.php

<?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 外观:

数据库/种子/PlacesTableSeeder.php

<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class PlacesTableSeeder extends Seeder
…

我们现在可以使用 foreach 循环遍历 $places 数组值,并使用查询生成器将每个值插入我们的 places 表中:

数据库/种子/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 字段设置为 [ X158X] 或 1

这是完整的 PlacesTableSeeder 类在所有更新后的样子:

数据库/种子/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 类以包含对我们刚刚创建的播种器的调用。

使用 nano 或您喜欢的编辑器打开 database/seeds/DatabaseSeeder.php 文件:

nano database/seeds/DatabaseSeeder.php

DatabaseSeeder 类看起来像任何其他播种器:它扩展自 Seeder 类并具有 run 方法。 我们将更新此方法以包含对 PlacesTableSeeder 的调用。

通过删除注释掉的行并将其替换为以下突出显示的代码来更新 DatabaseSeeder 类中当前的 run 方法:

数据库/种子/DatabaseSeeder.php

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

这是完整的 DatabaseSeeder 类在更新后的样子:

数据库/种子/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 步 — 运行数据库迁移和播种器

在继续之前,我们需要确保您的应用程序已启动并正在运行。 我们将设置应用程序加密密钥,然后从浏览器访问应用程序以测试 Web 服务器。

要生成 Laravel 所需的加密密钥,可以使用 artisan key:generate 命令:

docker-compose exec app php artisan key:generate

生成密钥后,您将能够通过将浏览器指向端口 8000 上的服务器主机名或 IP 地址来访问应用程序:

http://server_host_or_ip:8000

你会看到这样的页面:

这意味着应用程序能够连接到数据库,但找不到名为 places 的表。 我们现在将使用以下 migrate artisan 命令创建 places 表:

docker-compose exec app php artisan migrate

你会得到类似这样的输出:

OutputMigration 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

这将运行我们的播种器并插入我们在 PlacesTableSeeder 类中定义的样本值。 您将看到与此类似的输出:

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

现在,在浏览器上重新加载应用程序页面。 你会看到一个类似这样的页面:

每当您需要从头开始时,您可以使用以下命令删除所有数据库表:

docker-compose exec app php artisan db:wipe
OutputDropped all tables successfully.

要在单个命令中运行应用程序迁移并为表提供种子,您可以使用:

docker-compose exec app php artisan migrate --seed
OutputMigration 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

这将为 migrations 文件夹中的每个迁移类触发 down 方法。 通常,它会删除所有通过迁移类创建的表,只留下可能手动创建的任何其他表。 你会看到这样的输出:

OutputRolling 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 模型 进一步抽象应用程序数据库模式的更多详细信息.