2015-10-17 178 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'); 
});