2015-10-17 177 views
1

这是我的第一个问题,所以我也希望提示如何正确提问。模型工厂内的依赖注入

因此,在我的Laravel应用程序中,我有一个包含用户的数据库表。首先,我想为它建立一个模型工厂。所以我把一个标准的代码laravel doc page

$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, 
    ]; 

}); 

在播种机I类写道:

factory(App\User::class)->create(); 

然后,当我用工匠,命令:

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 

C在学习上,依赖注入有问题,但我不知道是什么。我知道,在这种情况下,我可以手动创建我需要的类的实例,但我想知道,如何正确执行。谁能帮忙?

回答

1

如果您查看faker @https://github.com/fzaninotto/Faker#localization的文档,您会发现您可以简单地将正确的本地化作为参数来创建。

在你的情况下,只需使用:

Faker\Factory::create('it_IT'); 

你不需要在匿名函数在定义工厂增加更多的参数。

编辑:

只是为了增加依赖注入的问题。如果你跟踪源代码,它不会在下面进行任何依赖注入。

$factory->define(...) 

只设置的该实例FactoryBuilder 定义

public function define($class, callable $attributes, $name = 'default') 
{ 
    $this->definitions[$class][$name] = $attributes; 
} 

调用

Faker\Factory::create(); 

方法 “的”
factory(App\User::class)->create(); 

$factory->of($class) 

呼叫的阵列(见线Illuminate \ Database \ Eloquent \ Factory的169-172。PHP)

public function of($class, $name = 'default') 
{ 
    return new FactoryBuilder($class, $name, $this->definitions, $this->faker); 
} 

之后,它链 “创造” FactoryBuilder的方法称为 “制造” 方法,也叫 “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)); 
    }); 
} 

通知 “call_user_func” 内部 “makeInstance”,即负责调用匿名函数创建的第二个参数来定义(在ModelFactory.php中)。它专门通过仅2个参数的可调用的函数,它们是:

...$this->faker, $attributes); 

只有1摊贩的第一个参数和属性上的第二个参数数组(这是你对你的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), 
    ]; 
}); 

如果你真的需要其他类,可以初始化它的“定义”,并在这样的函数中使用它以外:

$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), 
    ]; 
}); 
+0

谢谢,好点!但问题是,如果我想在这个匿名函数中定义其他参数,我该怎么做?特别是,如何获得像这样初始化的类的对象?或者这是不可能的,或者没有必要,写得很好的代码? – Staszek

+0

@Staszek我已更新我的答案,以解决您的疑虑 –

+0

谢谢!现在一切都很清楚。 – Staszek

0

你可以把这个设置寄存器()AppServiceProvider的:

$this->app->singleton(\Faker\Generator::class, function() { 
     return \Faker\Factory::create('it_IT'); 
});