dr24's avatar
Level 2

How to seed database with many to many relationship?

I have user_interests table which has the following columns

user_interests

 user_id   field_id   value_id

user_id references id on users table, field_id references id on fields table, and value_id references column value in field_values table. They are as follows.

fields table

id    name
1     gender
2     looking_for

field_values table

field_id   value   label
1          1       Men 
1          2       Women
2          1       Relationship
2          2       Chatting

users table

id   username   email
1    authuser   [email protected]

Currently I can seed users, fields, field_values table but I can not seed user_interests table. Any help is appreciated on how to do that. Here is my code.

User.php

<?php

namespace App;

use Carbon\Carbon;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
    * The attributes that are mass assignable.
    *
    * @var array
    */
    protected $fillable = [
        'username', 
        'email', 
    ];

    public function userInterests() 
    {
        return $this->belongsToMany(UserInterest::class, 'user_interests', 'id', 'user_id');    
    }
    

}

UserInterest.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class UserInterest extends Model
{
    protected $table = 'user_interests';
    protected $primaryKey = 'user_id';
    protected $fillable = ['*'];
    public $timestamps = false;
    
    public function users() 
    {
        return $this->belongsToMany(User::class, 'user_interests', 'id', 'user_id');    
    }
}

Field.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Field extends Model
{
    protected $table = 'fields';
    
    protected $guarded = [];

    public function fieldValues()
    {
        return $this->hasMany(FieldValue::class, 'field_id');
    }
}

FieldValue.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class FieldValue extends Model
{
    protected $table = 'field_values';

    protected $guarded = [];

    public function userFields() 
    {
        return $this->belongsTo(Field::class, 'field_id');    
    }
}

UserTableSeeder.php

<?php

use App\City;
use App\User;
use App\Gender;
use Carbon\Carbon;
use Faker\Factory as Faker;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

/**
* Class UserSeeder
*/
class UserTableSeeder extends Seeder
{
    use ChunkSeeder;
    /**
    * Run the database seeds.
    *
    * @return void
    */
    public function run()
    {

        $seed = [];

        for ($i = 0, $n = 150; $i < $n; $i++) {
            $seed[] = factory(User::class)->make(
                [
                    'username'          => $faker->userName,
                    'email'             => $faker->unique()->safeEmail,

                ]
            )->toArray();
        }

        $this->seedChunks($seed, [User::class, 'insert']);

    }
}
0 likes
5 replies
bwrigley's avatar

Something along these lines in your User factory?

Generates 30 users, grabs 0-4 random fields and attaches them in your join.

        factory(User::class, 30)
            ->create()
            ->each(function($user) {
                $randomFields= Fields::all()->random( rand(0, 4) )->pluck('id');
                $user->fields()->attach($randomFields);
        });
1 like
dr24's avatar
Level 2

@bwrigley

My current UserFactory is like this. I am having trouble wiriting factory like your example in mine. Can you help?

$factory->define(
    User::class,
    function (Faker $faker) {
        return [
            'username'          => $faker->userName,
            'email'             => $faker->unique()->safeEmail,
        ];
    }
);
bwrigley's avatar

So how I would do it is

Field Factory:

use Faker\Generator as Faker;

$factory->define(App\Field::class, function (Faker $faker) {
    return [
        'label' => $faker->randomElement(['Men','Women','Relationship','Chatting']),
        'value' => $faker->boolean(50) ? 1 : 2,
        'sort' => $faker->boolean(50) 1: 2,
    ];
});

(not sure what value and sort are for so just guessing at their values)

User Factory:

use Faker\Generator as Faker;

$factory->define(App\User::class, function (Faker $faker) {

    return [
        'username' => $faker->userName,
        'email' => $faker->unique()->safeEmail,
    ];
});

User Seeder:


use App\User;
use App\Field;

class UsersTableSeeder extends Seeder
{

    public function run()
    {
        factory(User::class, 150)
            ->create()
            ->each(function($user) {
        $user->fields()->saveMany(factory(Field::class, rand(0, 4))->make());
            });
    }
}

I'm not quite following your structure, but if I have understood, then this Seeder with create 150 User models each with 0-4 Field models attached. Is that what you mean?

dr24's avatar
Level 2

@bwrigley

I need to insert values in user_interests table not fields. For users, fields, and field_values table I already have seeders and they work as they should. I need to write in user_interests table 'user_id' (id from users table), 'field_id' (id from fields table), and 'value_id' (value column from field_values table). Field and FieldValue models are connected through hasMany relationship. Take a look in my question. Can you help?

bwrigley's avatar

@dr24 sorry for delay, I didn't get alerted to your reply.

Assuming you have set up the relationships correctly, then what I have shown you will create entries in the user_interests table.

$user->fields()->saveMany(factory(Field::class, rand(0, 4))->make());

creates 0-4 new Field models and 'attaches' them to the User model, this will create entries in your joining table.

Please or to participate in this conversation.