A factory describes one plausible row. php artisan make:factory ProductFactory writes the class to database/factories, and the model's HasFactory trait finds it by name (#[UseFactory] overrides that). definition() returns attributes built with fake(), the FakerPHP 3,995 (https://github.com/FakerPHP/Faker 3,995 ) generator (1.24.1, a require-dev package) in the APP_FAKER_LOCALE locale:
return [
'sku' => Str::upper(fake()->unique()->bothify('BK-????-##')),
'isbn' => fake()->unique()->isbn13(),
'title' => Str::title(fake()->words(3, true)),
'category_id' => Category::factory(),
'price' => fake()->randomFloat(2, 5, 60),
'stock' => fake()->numberBetween(1, 50),
'attributes' => ['format' => fake()->randomElement(['paperback', 'ebook']),
'pages' => fake()->numberBetween(120, 600)],
];make() builds unsaved models, create() inserts them and raw() returns the array. A factory used as a value, like Category::factory(), creates the parent row, even under make(). On an empty database, in php artisan tinker:
use App\Models\{Category, Product};
echo json_encode(Product::factory()->make()->only('sku', 'category_id', 'price')), "\n";
echo 'categories: ', Category::count(), "\n";
echo 'without: ', var_export(Product::factory()->withoutParents()->make()->category_id, true);{"sku":"BK-VGQZ-57","category_id":1,"price":"16.52"}
categories: 1
without: NULLwithoutParents() keeps unit tests off the database. Because composer install --no-dev removes Faker, factories belong only in seeders that never run in production.