Laravel - Seeding Many-to-Many Relationship

30,741

Solution 1

You can use attach() or sync() method on a many-to-many relationship.

There are multiple ways you can approach this. Here one of them:

// Populate roles
factory(App\Role::class, 20)->create();

// Populate users
factory(App\User::class, 50)->create();

// Get all the roles attaching up to 3 random roles to each user
$roles = App\Role::all();

// Populate the pivot table
App\User::all()->each(function ($user) use ($roles) { 
    $user->roles()->attach(
        $roles->random(rand(1, 3))->pluck('id')->toArray()
    ); 
});

Solution 2

Another way is to use saveMany() function

public function run()
{

   factory(App\User::class,3)->create();

   $roles = factory(App\Role::class,3)->create();

   App\User::All()->each(function ($user) use ($roles){
      $user->roles()->saveMany($roles);
   });
}

Solution 3

Just for a seeder you can use something like this:

   for ($i = 0; $i < 50; $i++) {
        $user = factory(App\User::class)->create();

        $role = factory(App\Role::class)->create();

        DB::table('role_user')->insert([
            'user_id' => $user->id,
            'role_id' => $role->id
        ]);
    }

But normally you need to define relation like has many through https://laravel.com/docs/5.4/eloquent-relationships#has-many-through

Then you will be able to use:

$user->roles()->save($role);

Solution 4

A much cleaner method can be: after you define the factory for App\User and App\Roles you can call the afterCreating method like this:

$factory->define(App\User::class, function ...);
$factory->define(App\Role::class, function ...);

$factory->afterCreating(App\User::class, function ($row, $faker) {
    $row->roles()->attach(rand(1,20));
});

Then in Seeds you first create the roles, then the users

public function run()
{
    factory(App\Role::class, 20)->create();
    factory(App\User::class, 50)->create();
}

Now you have 50 users each of them with one role attached.

Share:
30,741
Bilal Khawar
Author by

Bilal Khawar

Updated on July 09, 2022

Comments

  • Bilal Khawar
    Bilal Khawar almost 2 years

    I have a users table and a roles table that has a many-to-many relationship. These two tables are connected to a junction table called role_user.

    This is a model of the tables and its connections.

    Below are the Models in my Laravel project:

    User

    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class User extends Model
    {
        public function roles()
        {
            return $this->belongsToMany('App\Role');
        }
    }
    

    Role

    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Role extends Model
    {
        public function users()
        {
            return $this->belongsToMany('App\User');
        }
    }
    

    Below is the Factory file in the Laravel project:

    $factory->define(App\User::class, function (Faker\Generator $faker) {
        return [
            'name' => $faker->name,
            'email' => $faker->unique()->safeEmail,
            'password' => $password ?: $password = bcrypt('secret'),
        ];
    });
    
    $factory->define(App\Role::class, function (Faker\Generator $faker) {
        return [
            'role' => $faker->realText($maxNbChars = 2),
            'description' => $faker->realText($maxNbChars = 20),
        ];
    });
    

    Below is the Seed file in the Laravel project:

    public function run()
    {
        factory(App\User::class, 50)->create()->each(function ($u) {
            $u->roles()->save(factory(App\Role::class)->make());
        });
    
        factory(App\Role::class, 20)->create()->each(function ($u) {
            $u->users()->save(factory(App\User::class)->make());
        });
    }
    

    This should populate the users table and the roles table but how do I go about populating the role_user table? (I don't have a Model file for the junction table.)

    I'm very new at this so any help would be appreciated. Thanks.

  • Tharindu Sathischandra
    Tharindu Sathischandra about 5 years
    Can anyone explain why it chooses random between 1 and 3 instead of random between 1 and 20 (As there are 20 records in Roles, not 3)?
  • Othyn
    Othyn almost 5 years
    Could also say $roles->random(rand(1, $roles->count())) to get from 1 to the max available amount of roles
  • C0chett0
    C0chett0 over 4 years
    This will attach between 1 and 3 random roles to the user. NOT choose a role between id 1 and 3! I guess @peterm wanted to show how to limit (min and max) the number of roles you want to attach.
  • Jacek Dziurdzikowski
    Jacek Dziurdzikowski over 4 years
    This is going to attach 3 new roles separately to each user, it is not the real many-to-many relation mockup, but many-to-one in fact.
  • miken32
    miken32 over 2 years
    "Getting all roles and saving them to variable is not too good idea" why not? There are only 20 values, this is a negligible use of resources. Also this whole method is obsolete with modern versions of Laravel; factory() helper isn't even there any more.
  • Oybek Odilov
    Oybek Odilov over 2 years
    We don't need all the records stored in the variable to quantify them. Instead, we can immediately grab a count of records. if the person who asked the question uses the @peterm's solution elsewhere he will have performance issues (in this case here is 20 values, but I think, we should give universal answers).