Migrations 和 seeders 是 Laravel PHP 框架提供的强大的数据库实用程序,允许开发人员快速引导、销毁和重新创建应用程序的数据库。 这些实用程序有助于最大程度地减少多个开发人员在同一应用程序上工作时可能出现的数据库不一致问题:新的贡献者只需运行几个 artisan
命令即可在全新安装时设置数据库。
在本指南中,我们将创建迁移和播种器,以使用示例数据填充 Laravel 演示应用程序的数据库。 最后,您将能够只使用 artisan
命令多次销毁和重新创建数据库表。
先决条件
为了遵循本指南,您需要:
- 以具有 sudo 权限的非 root 用户身份访问 Ubuntu 18.04 本地计算机或开发服务器。 如果您使用的是远程服务器,建议安装活动防火墙。 要设置这些,请参阅我们的 Ubuntu 18.04 初始服务器设置指南。
- 按照 How To Install and Use Docker on Ubuntu 18.04 的 Step 1 和 Step 2 在您的服务器上安装 Docker。
- 按照 How To Install Docker Compose on Ubuntu 18.04 的 Step 1 在您的服务器上安装 Docker Compose。
注意:在本指南中,我们将使用由 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_DATABASE
、DB_USERNAME
和 DB_PASSWORD
,因为这些是由我们的 [ X155X] 文件自动设置开发数据库。 只需确保 DB_HOST
变量保持不变,因为它引用了我们在 Docker Compose 环境中的数据库服务的名称。
如果您对文件进行任何更改,请确保按 CTRL + X
、Y
,然后按 ENTER
保存并关闭它。
注意:如果您选择在 LEMP 服务器上运行应用程序,则需要更改突出显示的值以反映您自己的数据库设置,包括 [X185X ] 多变的。
第 3 步 — 使用 Composer 安装应用程序依赖项
我们现在将使用 PHP 的依赖项管理工具 Composer 来安装应用程序的依赖项,并确保我们能够执行 artisan
命令。
使用以下命令启动 Docker Compose 环境。 这将为 app
服务构建 travellist
镜像,并拉入 nginx
和 db
服务所需的额外 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 exec
。 exec
命令允许我们在 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'); } }
这个类有两个方法:up
和down
。 这两种方法都包含引导代码,您可以扩展这些代码以自定义执行迁移时发生的情况以及回滚时发生的情况。
我们将修改 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 模型 进一步抽象应用程序数据库模式的更多详细信息.