Laravel 8:将工厂属性传递给子关系

Laravel 8: Passing Factory properties into children relationships

我们目前正在开发 laravel 8 应用程序。我们正在尝试创建工厂来为基于手动/开发人员的应用程序测试创建一些虚拟数据。

我的主数据库播种器的当前代码如下:

class DatabaseSeeder extends Seeder
{

    public function run()
    {
        $this->call([
            UserTableSeeder::class,
        ]);
        \App\Models\User::factory(10)->create();
        \App\Models\Activity::factory(5)->create();

/* 1. try
        $tenFact = \App\Models\Tenant::factory(2)->has(
            \App\Models\Project::factory(2)->state(
                function (array $attributes, \App\Models\Tenant $tenant) {
                    return ['tenant_id' => $attributes['id']];
                } 
            )->hasTasks(5)->hasLocation()
        )->hasContracts(3)->create();

        */
        
/* Currently being used: */
        \App\Models\Tenant::factory(10)->has(
            \App\Models\Project::factory(5)->hasTasks(5)->hasLocation()
            )->hasContracts(3)->create();

    }

ProjectFactory.php:

class ProjectFactory extends Factory
{

    protected $model = Project::class;

    public function definition()
    {
        return [
            'name' => 'Projekt: '. $this->faker->name,
            'budget' => $this->faker->randomDigitNotNull*1000, 
            'progress' => $this->faker->randomDigitNotNull*10, 
            'budget_used' => $this->faker->randomDigitNotNull*50, 
            //'tenant_id' => Tenant::factory(),
            'location_id' => Location::factory()->hasTenant(1),
        ];
    }
}

LocationFactory.php:

class LocationFactory extends Factory
{

    protected $model = Location::class;

    public function definition()
    {
        return [
            'name' => 'Standort: ' . $this->faker->company,
            'street' => $this->faker->streetName,
            'house_number' => $this->faker->buildingNumber,
            'house_addition' => $this->faker->secondaryAddress,
            'zip' => $this->faker->postcode,
            'city' => $this->faker->city,
            'tenant_id' => Tenant::factory(),
        ];
    }
}

我们的关系是这样的:

Tenant 
  |-- Project (has: tenant_id, but also has location_id)
  |   | -- Task (has: project_id)
  |-- Locations (has: tenant_id)
  |-- Contracts (has: tenant_id)

使用上面命名的 Tenant-Factory 创建数据集时,会发生以下情况:

我们如何将 \App\Models\Tenant::factory(10) 的 id 传递给 Project::factory(5)->hasTasks(5)->hasLocation()?

此外,我们确实有问题,即使我们请求 10 个租户,我们也会得到大约 60 个,因为 Location/Project 在它们应该使用现有对象时创建新对象。

class ProjectFactory extends Factory
{
 $location_ids = App\Models\Location::pluck('id')->toArray();

    protected $model = Project::class;

    public function definition()
    {
        return [
            'name' => 'Projekt: '. $this->faker->name,
            'budget' => $this->faker->randomDigitNotNull*1000, 
            'progress' => $this->faker->randomDigitNotNull*10, 
            'budget_used' => $this->faker->randomDigitNotNull*50, 
            //'tenant_id' => Tenant::factory(),
            'location_id'=> $faker->randomElement($location_ids),
        ];
    }
}
class LocationFactory extends Factory
{
    $tenant_ids = App\Models\Tenant::pluck('id')->toArray();
    protected $model = Location::class;

    public function definition()
    {
        return [
            'name' => 'Standort: ' . $this->faker->company,
            'street' => $this->faker->streetName,
            'house_number' => $this->faker->buildingNumber,
            'house_addition' => $this->faker->secondaryAddress,
            'zip' => $this->faker->postcode,
            'city' => $this->faker->city,
            'tenant_id'=> $faker->randomElement($tenant_ids),
        ];
    }
}

我放弃了使用 Tenant-Factory 的链式使用 - 我最终使用了一些 for-Loop,通过使用 laravels for() 和 state() 方法将相关对象连接到每个用户:

       for ($i=0; $i < 10 ; $i++) { 
            $tenant = \App\Models\Tenant::factory()->hasContracts(3)->create();
            for ($j=0; $j < 5; $j++) { 
                $location = \App\Models\Location::factory(1)->for($tenant)->create();
                $project = \App\Models\Project::factory(1)->state([
                    'location_id' => $location->first()['id'],
                    'tenant_id' => $tenant['id']])->hasTasks(5)->create();
            }
        }