Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Ookma-Kyi's avatar

Best way to handle seeder with recyclables

I had the pleasure of talking to Larry with an issue I am having:

Me:
How do I pass a variable to a seeder from another seeder?

Lary:

In Laravel, seeders are used to populate your database with test or initial data. If you want to pass a variable from one seeder to another, you can't directly pass variables between them since each seeder is executed independently by the db:seed Artisan command.

However, you can achieve a similar effect by using a few different approaches:

    Database State: The most common way to share data between seeders is to rely on the database state. For example, you could create a record in one seeder and then look it up in another seeder.

// FirstSeeder.php
public function run()
{
    DB::table('users')->insert([
        'name' => 'John Doe',
        'email' => '[email protected]',
        'password' => bcrypt('password'),
    ]);
}

// SecondSeeder.php
public function run()
{
    $user = DB::table('users')->where('email', '[email protected]')->first();
    // Now you have the user variable that you can use
}

    Static Properties or Methods: You can define a static property or method in one seeder and access it from another seeder.

// FirstSeeder.php
public static $sharedData;

public function run()
{
    self::$sharedData = 'Some data';
    // Seed the relevant data
}

// SecondSeeder.php
public function run()
{
    $data = FirstSeeder::$sharedData;
    // Use the $data variable
}

    Service Container: You can bind data to Laravel's service container in one seeder and resolve it in another.

// FirstSeeder.php
public function run()
{
    app()->singleton('sharedData', function () {
        return 'Some data';
    });
    // Seed the relevant data
}

// SecondSeeder.php
public function run()
{
    $data = app('sharedData');
    // Use the $data variable
}

    Configurations: You can temporarily set a configuration value in one seeder and get it in another.

// FirstSeeder.php
public function run()
{
    config(['seeder.sharedData' => 'Some data']);
    // Seed the relevant data
}

// SecondSeeder.php
public function run()
{
    $data = config('seeder.sharedData');
    // Use the $data variable
}

Remember that these methods are not typical use cases for seeders, and you should carefully consider if you really need to share data between seeders or if there's a better way to structure your seeders to avoid tight coupling. Seeders are generally meant to be idempotent and independent to ensure that they can be run in any order or multiple times without causing issues.

Note at the very end it suggests:

Seeders are generally meant to be idempotent and independent to ensure that they can be run in any order or multiple times without causing issues.

My question is this, assuming the character seeder:

<?php

namespace Database\Seeders;

use App\Models\Character;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class CharacterSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
        $user = DB::table('users')->where('email', '[email protected]')->first();

        Character::factory()->
        recycle($user)->
        create([
            'name' => 'admin',
            'xp' => 0,
            'wins' => 0,
            'loses' => 0,
            'draws' => 0
        ]);
    }
}

Where a user has the possibility of multiple characters, what is the suggested "use case"?

0 likes
1 reply
LaryAI's avatar
Level 58

The suggested "use case" for handling a situation where a user can have multiple characters would be to ensure that the CharacterSeeder is designed to handle the creation of multiple characters for a single user without relying on external state from other seeders. Here's how you might structure the CharacterSeeder:

<?php

namespace Database\Seeders;

use App\Models\Character;
use App\Models\User;
use Illuminate\Database\Seeder;

class CharacterSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        // Retrieve the user by email or create a new one
        $user = User::firstOrCreate(
            ['email' => '[email protected]'],
            [
                'name' => 'Admin User',
                'password' => bcrypt('password'), // You should use a secure password here
                // ... other necessary user attributes
            ]
        );

        // Create multiple characters for the user
        Character::factory()->count(3)->create([
            'user_id' => $user->id,
            // 'name' => 'admin', // You might want to generate unique names for each character
            'xp' => 0,
            'wins' => 0,
            'loses' => 0,
            'draws' => 0,
        ]);

        // If you want to create specific characters, you can do so like this:
        Character::create([
            'user_id' => $user->id,
            'name' => 'admin',
            'xp' => 0,
            'wins' => 0,
            'loses' => 0,
            'draws' => 0,
        ]);

        // Add more characters as needed
    }
}

In this example, the CharacterSeeder is responsible for ensuring that the user exists before creating characters for that user. It uses firstOrCreate to either find the existing user or create a new one if the user doesn't exist. This makes the seeder idempotent, meaning it can be run multiple times without creating duplicate users.

The Character::factory()->count(3)->create([...]) line is an example of how you can create multiple characters for the user using a factory. If you want to create specific characters with unique attributes, you can call Character::create([...]) for each character.

Remember to replace 'password' => bcrypt('password') with a secure password or a password generation mechanism appropriate for your application.

By structuring your seeders this way, you ensure that they are independent and can be run in any order or multiple times without causing issues. This approach also avoids tight coupling between seeders, which is a good practice in database seeding.

Please or to participate in this conversation.