学习在 Laravel 中使用模型工厂
发布于 作者: Eric L. Barnes
Laravel 5.1 带有一个名为模型工厂的功能,旨在让您快速构建“假”模型。
它们有几个用例,其中两个最大的用例是测试和数据库播种。让我们通过构建一个小型虚构应用程序的开始来更深入地了解此功能。
开始
假设您被 LEMON 定制房屋建筑商雇用,他们需要一种方法让客户在房屋建成后提交故障单。拥有像 LEMON 这样的名字,您知道他们将被问题淹没,因此您的任务是简化此流程。
为了创建绝对的最小值,我们可以使用用户表作为客户并创建一个新的问题表。所以让我们开始构建它们。
创建一个新应用程序
laravel new lemon-support
接下来,让我们从 artisan 控制台命令中创建我们的问题模型和迁移。我们可以通过使用make:model
命令并传递-m
或--migration
标志来在一个命令中创建两者。
php artisan make:model Issues -m
如果您打开app/
文件夹,您将看到 Issues.php。然后在database/migrations/
中找到新的create_issues_table
迁移文件。
继续打开 app/User.php 模型文件并定义问题关系
public function issues(){ return $this->hasMany('issues');}
现在是编辑您的.env
并更改数据库名称的好时机,如果您不想使用默认的 homestead。
现在让我们填写迁移文件。
创建迁移
打开 database/migrations/datetime_create_issues_table.php 并将 up 方法调整为以下内容
public function up(){ Schema::create('issues', function (Blueprint $table) { $table->increments('id'); $table->integer('user_id'); $table->string('subject'); $table->text('description'); $table->timestamps(); });}
在此迁移中,我们只是在用户表中添加了一个 user_id 关系,一个问题的主题和一个描述,以便客户可以提供详细的报告。
现在运行迁移
php artisan migrate
它应该输出以下内容
Migration table created successfully.Migrated: 2014_10_12_000000_create_users_tableMigrated: 2014_10_12_100000_create_password_resets_tableMigrated: 2015_10_03_141020_create_issues_table
接下来让我们设置数据库播种,以便我们可以使用示例数据。
构建数据库种子
数据库种子是一种以编程方式将数据插入数据库的方法,使用它们的优点之一是您可以快速将虚拟数据放入应用程序中。这在处理用户界面以及与团队合作时非常有用。
让我们从为用户创建一个种子开始。这可以使用以下命令生成
php artisan make:seeder UserTableSeeder
继续为问题创建一个种子
php artisan make:seeder IssueTableSeeder
现在打开 database/seeds/DatabaseSeeder.php 文件并将 run 方法调整为以下内容
public function run(){ Model::unguard(); $this->call(UserTableSeeder::class); $this->call(IssueTableSeeder::class); Model::reguard();}
现在,在这些种子类有用之前,它们需要有关要插入内容的说明。让我们使用模型工厂来实现这一点。
创建模型工厂
过去,在创建种子数据时,您可以使用 Eloquent 或 Laravel 的查询生成器,这种方法仍然受支持。但是,随着模型工厂的引入,您可以使用它们来构建“虚拟”模型,这些模型可用于种子数据和测试。
打开 database/factories/ModelFactory.php,您将看到一个默认的已定义工厂
$factory->define(App\User::class, function (Faker\Generator $faker) { return [ 'name' => $faker->name, 'email' => $faker->email, 'password' => bcrypt(str_random(10)), 'remember_token' => str_random(10), ];});
解释一下,我们定义了“App\User::class” 模型作为第一个参数,然后是一个定义列中数据的回调。此回调还注入 Faker,这是一个生成虚假数据的 PHP 库。Faker 功能强大,可用于多种不同的字段类型。以下是显示的示例
- $fake->name – “John Smith”
- $faker->email – “[email protected]”
请注意:如果您的应用程序要发送真实电子邮件,则应使用$faker->safeEmail
而不是->email
。这样做的原因是->email
可能生成真实的电子邮件,而 safeEmail 使用 example.org,该域名由 RFC2606 保留用于测试目的。
现在,让我们为我们的问题模型创建一个新工厂。以下是完成的代码
$factory->define(App\Issues::class, function (Faker\Generator $faker) { return [ 'subject' => $faker->sentence(5), 'description' => $faker->text(), ];});
使用此定义,我们为主题生成一个包含五个单词的句子,最后为描述生成一些虚拟文本。
现在让我们切换回种子类并使用这些工厂来生成数据。
打开 UserTableSeeder 并调整 run 方法
public function run(){ factory(App\User::class, 2)->create()->each(function($u) { $u->issues()->save(factory(App\Issues::class)->make()); });}
这可能看起来很复杂,所以让我们分解一下。factory(App\User::class, 2)->create()
的意思是用英语说,构建一个用户类,我们想要 2 个用户,然后通过保存在数据库中来创建它们。
接下来是一个集合,它将遍历“每个”创建的用户。最后,在每个用户中保存一个与创建的用户相关的 issues。
运行 artisan 命令
$ php artisan migrate --seedMigrated: 2014_10_12_000000_create_users_tableMigrated: 2014_10_12_100000_create_password_resets_tableMigrated: 2015_10_03_141020_create_issues_tableSeeded: UserTableSeeder
现在我们的数据库将包含我们的表,它们将包含从模型工厂生成的示例数据。
使用 Laravel 模型工厂进行测试
使用模型工厂的一个主要好处是,我们现在可以在测试套件中使用它们。为我们的问题创建一个新测试
php artisan make:test IssuesTest
打开 tests/IssuesTest.php 并添加一个新方法来测试问题创建
<?php use Illuminate\Foundation\Testing\WithoutMiddleware;use Illuminate\Foundation\Testing\DatabaseMigrations;use Illuminate\Foundation\Testing\DatabaseTransactions; class IssuesTest extends TestCase{ use DatabaseTransactions; public function testIssueCreation() { factory(App\Issues::class)->create([ 'subject' => 'NAIL POPS!' ]); $this->seeInDatabase('issues', ['subject' => 'NAIL POPS!']); }}
在此测试中,我们使用DatabaseTransactions
特性,以便每个测试都包含在一个事务中。在 testIssueCreation 中添加了我们的模型工厂,它具有一个新功能。create 方法传递了一个包含列名称和预设值的数组。这使您可以覆盖原始模型工厂定义中存储的内容。
对于实际测试,我们使用seeInDatabase
,顾名思义,它搜索数据库,如果找到给定的列和值,则返回绿色。
现在我们已经看到了这些模型工厂如何用于播种和测试,让我们来看看它提供的一些有用功能。
其他模型工厂功能
在为与 LEMON 房屋的第一次会议做准备时,您注意到原始设置存在问题。您忘记添加一种方法来标记问题已解决。这将令人尴尬。
多种工厂类型
在为“已完成”字段添加新的迁移后,需要调整模型工厂,但拥有一个单独的模型工厂会很方便,这样您就可以轻松创建已完成的问题。像这样定义一个新工厂
$factory->defineAs(App\Issues::class, 'completed', function ($faker) use ($factory) { $issue = $factory->raw(App\Issues::class); return array_merge($issue, ['completed' => true]);});
这个工厂使用一个名称作为第二个参数,在本例中为“completed”,在回调中,我们创建一个新的问题并将已完成的列合并到其中。
如果您想创建一个“已完成”的问题,现在只需运行
$completedIssue = factory(App\Issue::class, 'completed')->make();
工厂 make 和 create 方法
在最后一个示例中,您可能已经注意到我调用了->make()
而不是->create()
,就像之前一样。这两种方法执行不同的操作,“create”尝试将数据存储在数据库中,这与在 Eloquent 中保存相同。另一方面,make 创建模型,但实际上不插入。如果您熟悉 Eloquent,它相当于
$issue = new \App\Issue(['subject' => 'My Subject']);
结束
如您所见,模型工厂是 Laravel 中一个强大的功能,有助于简化测试和数据库播种。
此外,请查看 v5.3.17 中的 Laravel 模型工厂状态。