Good day, I guess you are having a "codie" day. Today, I will putting you through, how to seed tables with relationships in laravel . As we all know laravel provides an out of the box way to populate our database with data, that makes population of user interface feel less painful.
In the laravel 8 version, on of the major changes is the addition use HasFactory; in our models. which has changed the way we change our user model.
While seeding data or building an application in laravel, it is common to have one class for each database table. But what if there are relationships? I will show you two ways you can deal with it.
Seeding 1 to 1 relationship
Imagine we have a database structure where we have users table and profiles. Our User table will be holding the login details, which is the first details user will be providing when registering while our profiles table will be holding other possible data of the user.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
* User Table schema
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->timestamps();
$table->rememberToken();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
Below is the profile table schema, the user_id will be our foreign key on the profile table.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProfilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('profiles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('occupation')->nullable();
$table->string('mobile')->nullable();
$table->string('address')->nullable();
$table->string('city')->nullable();
$table->string('state')->nullable();
$table->string('postcode')->nullable();
$table->string('country')->nullable();
$table->text('about')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('profiles');
}
}
Now let define the relationships in our models
In the user model we will define our 1 to 1 relationship as shown below
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* Get the profile record associated with the user.
*/
public function profile()
{
return $this->hasOne(Profile::class);
}
}
In the profile model we will define our 1 to 1 relationship as shown below <?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model;
class Profile extends Model { use HasFactory;
/**
* Get the user record associated with the profile.
*/
public function user()
{
return $this->belongsTo(User::class);
}
}
Now let define our factories
database/factories/UserFactory.php:
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
}
and database/factories/ProfileFactory.php:
<?php
namespace Database\Factories;
use App\Models\Profile;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProfileFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Profile::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
//
'mobile' => $this->faker->phoneNumber,
'occupation' => $this->faker->jobTitle,
'address' => $this->faker->address,
'city' => $this->faker->city,
'state' => $this->faker->state,
'postcode' => $this->faker->postcode,
'country' => $this->faker->country,
'about' => $this->faker->text,
];
}
}
Now as you can see no porfile.user_id defined. Here’s where we have a few options:
Version 1. Create profile inside of user seed
The user seeder comes with laravel installation out of the box, so let fill the file database/seeds/UserSeeder.php with this:
User::factory(10)->create()->each(function ($user) {
$user->profile()->save(Profile::factory()->make());
});
Basically, we’re creating 10 users, and for each of them we’re creating one profile, using Eloquent relationship in app/models/User.php:
/**
* Get the profile record associated with the user.
*/
public function profile()
{
return $this->hasOne(Profile::class);
}
Now before running the seeder command, populate your databaseeder file where our seeder files are called, with the below code.
public function run()
{
$this->call([
UserSeeder::class,
]);
}
now run the below command, your database will be migrated and seeded with 10 users with their corresponding profile on the profiles table.
php artisan migrate:fresh && php artisan db:seed
Version 2. Create profile along with the user
The other way around would be to use seed for Profiles.
php artisan make:seeder ProfileSeeder And then add only this line in database/seeds/ProfileSeeder.php:
public function run()
{
Profile::factory(10)->create();
}
You’re probably wondering where the relationship would come from? We can create a “parent” entry directly in the factory! Like this:
database/factories/ProfileFactory.php:
<?php
namespace Database\Factories;
use App\Models\Profile;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProfileFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Profile::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
//
'user_id' => User::factory()->create()->id,
'mobile' => $this->faker->phoneNumber,
'occupation' => $this->faker->jobTitle,
'address' => $this->faker->address,
'city' => $this->faker->city,
'state' => $this->faker->state,
'postcode' => $this->faker->postcode,
'country' => $this->faker->country,
'about' => $this->faker->text,
];
}
}
See the first field? We’re using parent factory and creating a user “on-the-fly”.
That’s it, isn’t it simple?
Now before running the seeder command, populate your databaseeder file where our seeder files are called, with the below code.
public function run()
{
$this->call([
ProfileSeeder::class,
]);
}
now run the below command, your database will be migrated and seeded with 10 profiles with their corresponding users on the users table.
php artisan migrate:fresh && php artisan db:seed
In official Laravel documentation you can find more information about seeding and using factories with Faker .