这是我的第一个问题,所以我也希望获得有关如何正确提问的提示。
所以,在我的 Laravel 应用程序中,我有一个包含用户的数据库表。首先,我想要一个模型工厂。所以我从laravel文档页面获取了标准代码:
$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),
];
});
我将其更改为:
$factory->define(App\User::class,
function(Faker\Generator $faker) {
return [
'name' => $faker->name(),
'email' => $faker->safeEmail(),
'password' => bcrypt(str_random(10)),
'phone_number' => $faker->phoneNumber(),
'remember_token' => str_random(10),
'account_type' => 0,
];
});
到目前为止,一切正常。但我希望它更加复杂,因此我决定使用更具体的 Faker 类来生成意大利数据。我把它改为:
$factory->define(App\User::class,
function(Faker\Generator $faker,
Faker\Provider\it_IT\PhoneNumber $fakerITPN,
Faker\Provider\it_IT\Person $fakerITPER,
Faker\Provider\it_IT\Internet $fakerITInt) {
return [
'name' => $fakerITPER->name(),
'email' => $fakerITInt->safeEmail(),
'password' => bcrypt(str_random(10)),
'phone_number' => $fakerITPN->phoneNumber(),
'remember_token' => str_random(10),
'account_type' => 0,
];
});
在播种者课堂上我写道:
factory(App\User::class)->create();
然后,在我使用 Artisan 后,命令:
artisan migrate:refresh --seed -vvv
我收到以下错误(只是头部,为了清除):
[ErrorException]
Argument 2 passed to Illuminate\Database\Eloquent\Factory::{closure}() must be an instance of Faker\Provider\it_IT\PhoneNumber, array given
Exception trace:
() at /home/vagrant/php/housing/database/factories/ModelFactory.php:19
Illuminate\Foundation\Bootstrap\HandleExceptions->handleError() at /home/vagrant/php/housing/database/factories/ModelFactory.php:19
Illuminate\Database\Eloquent\Factory::{closure}() at n/a:n/a
call_user_func() at /home/vagrant/php/housing/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:130
Illuminate\Database\Eloquent\FactoryBuilder->Illuminate\Database\Eloquent\{closure}() at /home/vagrant/php/housing/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2308
Illuminate\Database\Eloquent\Model::unguarded() at /home/vagrant/php/housing/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:133
Illuminate\Database\Eloquent\FactoryBuilder->makeInstance() at /home/vagrant/php/housing/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:105
Illuminate\Database\Eloquent\FactoryBuilder->make() at /home/vagrant/php/housing/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:83
Illuminate\Database\Eloquent\FactoryBuilder->create() at /home/vagrant/php/housing/database/seeds/UsersTableSeeder.php:24
UsersTableSeeder->run() at /home/vagrant/php/housing/vendor/laravel/framework/src/Illuminate/Database/Seeder.php:42
显然,依赖注入有问题,但我不知道是什么。我知道,在这种情况下,我可以手动创建我需要的类的实例,但我想知道如何正确执行它。有人可以帮忙吗?
如果你看一下 faker @ 的文档 https://github.com/fzaninotto/Faker#localization,你会发现你可以简单地分配正确的本地化作为参数来创建。
在您的情况下,只需使用:
Faker\Factory::create('it_IT');
定义工厂时,不需要在匿名函数中添加更多参数。
编辑:
只是补充一下依赖注入的问题。如果你跟踪源代码,它并没有在下面进行任何依赖注入。
$factory->define(...)
仅设置定义数组
public function define($class, callable $attributes, $name = 'default')
{
$this->definitions[$class][$name] = $attributes;
}
打电话
Faker\Factory::create();
或
factory(App\User::class)->create();
$factory->of($class)
调用实例化 FactoryBuilder 的“of”方法 (参见 Illuminate\Database\Eloquent\Factory.php 第 169-172 行)
public function of($class, $name = 'default')
{
return new FactoryBuilder($class, $name, $this->definitions, $this->faker);
}
之后,它链接FactoryBuilder的“create”方法,该方法调用“make”方法,该方法也调用“makeInstance”
protected function makeInstance(array $attributes = [])
{
return Model::unguarded(function () use ($attributes) {
if (! isset($this->definitions[$this->class][$this->name])) {
throw new InvalidArgumentException("Unable to locate factory with name [{$this->name}].");
}
$definition = call_user_func($this->definitions[$this->class][$this->name], $this->faker, $attributes);
return new $this->class(array_merge($definition, $attributes));
});
}
注意“makeInstance”中的“call_user_func”,它负责调用作为定义的第二个参数创建的匿名函数(在 ModelFactory.php 中)。它专门只向可调用函数传递 2 个参数,它们是:
...$this->faker, $attributes);
仅在第一个参数上传递 1 个 faker,在第二个参数上传递属性数组(这是您之前在 ErrorException 中看到的)
这意味着你只能用这种方式定义你的工厂:
$factory->define(App\User::class,
function (Faker\Generator $faker, $attributes=array()) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
如果你确实需要其他类,你可以在“define”之外初始化它并在函数中使用它,如下所示:
$sampleInstance = app(App\Sample::class);
$factory->define(App\User::class,
function (Faker\Generator $faker, $attributes=array()) use($sampleInstance){
//...do something here
//...or process the $attributes received
//...or call a method like
$sampleData = $sampleInstance->doSomething();
return [
'someField' => $sampleData,
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
您可以将此设置放在AppServiceProvider的register()中:
$this->app->singleton(\Faker\Generator::class, function () {
return \Faker\Factory::create('it_IT');
});