One of the changes in Laravel 8 was the overhaul of the model factories which led to factories being namespaced. Seeders are also affected in the same way, but this is a different topic for now.

Now I did not paid enough attention to grasp why such change was introduced or even necessary, but it is at the very top of the list of the high impact changes, so I decided to play along.

Just a few days into usage I was searching for a way to efficiently generate multiple records with one-to-one relationship. Maybe I was searching for wrong keywords or maybe just the planets were just not aligned, but all the solutions I could find looked too complicated. This was true until I stumbled upon this humble StackOverflow answer where an exactly right solution was presented. Let's look at it.

A Lair

For the lair, most of the files are absolutely bare bones, could be used straight as Artisan generates them. Keep in mind that this is intended to be a minimal (hopefully) working example. We could add a hasOne relation here later, but for the actual example to work it is not required.

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Lair extends Model {

}

A migration is also bare bones, but for real-life lair, we would probably add some columns like name of the mountain where is it located.

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateLairsTable extends Migration {

  public function up() {
    Schema::create('lairs', function (Blueprint $table) {
      $table->id();
      $table->timestamps();
    });
  }

  public function down() {
    Schema::dropIfExists('lairs');
  }
}

The above holds true here for the factory, straight from the generator. Since we did not add any specific columns, we do not need to fake any values here.

<?php
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\Lair;

class LairFactory extends Factory {

  protected $model = Lair::class;

  public function definition() {
    return [
      //
    ];
  }
}

The Dragon

There's a first important bit here, a lair_id column marking a foreign key.

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateDragonsTable extends Migration {

  public function up() {
    Schema::create('dragons', function (Blueprint $table) {
      $table->id();
      $table->foreignId('lair_id')->constrained();
      $table->timestamps();
    });
  }

  public function down() {
    Schema::dropIfExists('dragons');
  }
}

A model for the Dragon on contains a belongsTo relationship. Although the example would work without this method, it is here to signify that there could be many Lairs throughout the land but should there exist any Dragon, he has to be living in one of them.

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Lair;

class Dragon extends Model {
  use HasFactory;

  public function lair() {
    return $this->belongsTo(Lair::class);
  }
}

And finally a promised factory. Again, almost bare bones with one extra line:

<?php
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\Lair;
use App\Models\Dragon;

class DragonFactory extends Factory {

  protected $model = Dragon::class;

  public function definition() {
    return [
      'lair_id' => Lair::factory()
    ];
  }
}

The line specifically is this:

'lair_id' => Lair::factory()->create()->id

The result of the above is that now we can generate many Dragons at once via DragonFactory like so:

<?php
use App\Models\Dragon;

//

Dragon::factory(200);

Here, every Dragon would have it's own Lair generated with him. Note that a similar approach could be used in Laravel 7 and below as well, but here wanted to express the namespacing changes Laravel 8 brought in. Convenient.