Poznajemy seeding z dwoma typami relacji (jeden do jednego i jeden do wielu). Dzięki temu możemy szybko wytworzyć fejkowe dane do manualnych testów aplikacji.

Ok, przypomnijmy na czym stanęliśmy. AdresFactory:

class AddressFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'city' => fake()->city(),
            'street' => fake()->streetName()
        ];
    }
}

PersonFactory z różnymi stanami (male, female, adults, kids):

class PersonFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'firstName' => fake()->firstName(),
            'lastName' => fake()->lastName(),
            'age' => fake()->numberBetween(16, 60),
            'created_at' => fake()->dateTimeBetween('-2 years'),
            'updated_at' => fake()->dateTimeBetween('created_at', 'now')
        ];
    }

    public function adults()
    {
        return $this->state(function (array $attributes) {
            return [
                'age' => fake()->numberBetween(19, 60),
            ];
        });
    }

    public function kids()
    {
        return $this->state(function (array $attributes) {
            return [
                'age' => fake()->numberBetween(14, 18),
            ];
        });
    }

    public function male()
    {
        return $this->state(function (array $attributes) {
            return [
                'firstName' => fake()->firstName('male'),
               'lastName' => fake()->lastName('male'),
            ];
        });
    }

    public function female()
    {
        return $this->state(function (array $attributes) {
            return [
                'firstName' => fake()->firstName('female'),
            'lastName' => fake()->lastName('female'),
            ];
        });
    }

}

PersonSeeder z relacją 1 do 1 Person hasOne Address, Address belongsTo person:

use App\Models\Person;
use App\Models\Address;

class PersonSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        Person::factory()
        ->count(5)
        ->male()
        ->create()
        ->each(function($person){
            $person->address()->save(Address::factory()->make());
        });

        Person::factory()
        ->count(5)
        ->female()
        ->create()
        ->each(function($person){
            $person->address()->save(Address::factory()->make());
        });

        Person::factory()
        ->count(5)
        ->kids()
        ->create()
        ->each(function($person){
            $person->address()->save(Address::factory()->make());
        });

        Person::factory()
        ->count(5)
        ->adults()
        ->create()
        ->each(function($person){
            $person->address()->save(Address::factory()->make());
        });
    }
}

A co dodać chcemy? Notes:

  • relacja jeden do wielu
  • Person hasMany Note
  • Note belongsTo Person

Ok, NoteFactory:

 */
class NoteFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'title' => fake()->sentence(6),
            'content' => fake()->sentence(12)
        ];
    }
}

Argument przekazany do sentence to jest liczba wyrazów. Ok, teraz PersonSeeder:

use App\Models\Person;
use App\Models\Address;
use App\Models\Note;
class PersonSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        Person::factory()
        ->count(5)
        ->male()
        ->create()
        ->each(function($person){

            $person->address()->save(Address::factory()->make());

            $notes = Note::factory()
            ->count(random_int(1,5))
            ->make();

            $person->notes()->saveMany($notes);
        });

        Person::factory()
        ->count(5)
        ->female()
        ->create()
        ->each(function($person){

            $person->address()->save(Address::factory()->make());

            $notes = Note::factory()
            ->count(random_int(1,5))
            ->make();
            
            $person->notes()->saveMany($notes);
        });

        Person::factory()
        ->count(5)
        ->kids()
        ->create()
        ->each(function($person){

            $person->address()->save(Address::factory()->make());

            $notes = Note::factory()
            ->count(random_int(1,5))
            ->make();
            
            $person->notes()->saveMany($notes);
        });

        Person::factory()
        ->count(5)
        ->adults()
        ->create()
        ->each(function($person){

            $person->address()->save(Address::factory()->make());

            $notes = Note::factory()
            ->count(random_int(1,5))
            ->make();
            
            $person->notes()->saveMany($notes);
        });
    }
}

Czemu tak? Cóż:

  • factory wywołuje fabrykę
  • count podaje ile razy z fabryki skorzystać
  • dalej mamy stan (kids, adults, male, female)
  • create oznacza utwórz
  • each pozwala po utworzeniu coś jeszcze wykonać (np. zająć się relacjami)
  • do person odwołujemy się do address->save, aby zapisać 1 do 1
  • aby utworzyć adres bierzemy fabrykę i make (make tworzy bez zapisywania, zostanie zapisane przez save)
  • tak samo możemy utworzyć przez make kilka notatek
  • jako że relacja jeden do wielu i samych notatek jest potencjalnie więcej niż jedna używamy saveMany

No i najważniejsze, zawsze zapominam tej komendy:

php artisan db:seed --class=PersonSeeder

W bazie danych już mamy dobrze potworzone rekordy z relacjami.