Laravel - Seeding Many-to-Many Relationship

Viewed 35972

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.

5 Answers

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);
   });
}

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.

Better to use this structure:

App\Role::factory()->count(20)->create();

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

// Getting all roles and saving them to variable is not too good idea.
// Instead, get count of rows.
$rolesCount = App\Role::count();

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