I am trying to seed a table with a foreign key and I'm stuck on how I would tell the model to randomly pull values from what already exists.
ModelFactory
$factory->define(App\Vendor::class, function(Faker\Generator $faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Device::class, function(Faker\Generator $faker) {
return [
'vendor' => ,
'name' => $faker->company,
'mac_address' => $faker->macAddress,
];
});
Seeds
VendorTableSeeder
public function run()
{
factory(App\Vendor::class, 150)->create();
}
DeviceTableSeeder
public function run()
{
factory(App\Device::class, 50)->create();
}
DataSeeder
$this->call(VendorTableSeeder::class);
$this->call(DeviceTableSeeder::class);
I seed the Vendor table before the Device table and would like to populate a random vendor id from the existing vendors.
'vendor' => 'factory::App\Vendor'
But I am getting
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: foreign key constraint fails
It looks like the insert is trying to insert factory::App\Vendor
as a string for the vendor column. I am trying to figure out how to have it pull from the existing vendors.
Seed them at the same time from the VendorTableSeeder
.
Will you ever need Devices without Vendors? Or Vendors without Devices? If not, then this is the best option. Related tables should be seeded together.
A better example would be a School. The School is the main seed, and for each School, you would also seed a Principal, several Teachers, and 100 Students. If you seed them all at once that eliminates the concerns about foreign keys or ordering.
factory(App\Vendor::class, 150)
->create()
->each(function (App\Vendor $vendor) {
$vendor->devices()->save(
factory(App\Device::class)->make()
);
// For some randomness
$vendor->devices()->save(
factory(App\Device::class, rand(0, 4))->make()
);
});
If you do want the flexibility of seeding them separately then you have a couple other options. You can pull in a random Vendor inside the Device factory itself.
$factory->define(App\Device::class, function(Faker\Generator $faker) {
// Grab a random vendor
$vendor = App\Vendor::orderByRaw('RAND()')->first();
// Or create a new vendor
$vendor = factory(App\Vendor::class)->create();
return [
'vendor_id' => $vendor->id,
'name' => $faker->company,
'mac_address' => $faker->macAddress,
];
});
Or you can pass extra attributes which are merged with the factory-generated attributes.
// $vendor is a Vendor object
factory(App\Device::class, 50)->create([
'vendor_id' => $vendor->id,
]);