在 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 为测试目的而保留。
现在,让我们为 Issues 模型创建一个新的工厂。以下是完成的代码
$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()
的意思是在英文中是,构建一个 User 类,我们想要 2 个用户,然后将它们创建出来,并保存到数据库中。
接下来是一个集合的 each 函数,它将对每个创建的用户运行。最后,在每个用户中保存一个与创建用户相关联的问题。
运行 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 模型工厂进行测试
使用模型工厂的一个主要好处是,我们现在可以在我们的测试套件中使用它们。为我们的 Issues 创建一个新的测试
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();
Factory make 方法与 create 方法
在最后一个示例中,您可能已经注意到我调用了 ->make()
而不是 ->create()
,就像之前做的那样。这两个方法做了两件不同的事情,“create” 尝试将数据存储到数据库中,这与在 Eloquent 中保存数据相同。另一方面,make 创建模型,但不会实际插入。如果您熟悉 Eloquent,它相当于
$issue = new \App\Issue(['subject' => 'My Subject']);
结束
如你所见,模型工厂是 Laravel 中一个强大的功能,有助于简化测试和数据库播种。
此外,请查看 v5.3.17 中的 Laravel 模型工厂状态。