Laravel101: A Practical Guide for Seeders and Factories
Tags: laravel, php, database, seed
Published: 2023-08-31 08:09:57

During the development process, there are times when we need to evaluate the functionality of a system by using data. In Laravel, we have two useful tools called seeders and factories that help us generate random data. In this article, we’ll explore these tools and learn how to use them effectively.

---

The factory class in Laravel acts like a factory that generates random data for our database tables. If you navigate to the `database/factories` directory in your project, you’ll find a class called `UserFactory`:
```php
class UserFactory extends Factory
{
    public function definition(): array
    {
        return [
            'name' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}
```
In each factory class, there is an important function called `definition` that specifies how each attribute should be filled out. To accomplish this, Laravel utilizes a powerful package called [fakerPHP](https://github.com/FakerPHP/Faker), which can generate random data such as names, sentences, paragraphs, and even images. You can find more information about the helper functions and features of this package at the following link.

{% embed https://fakerphp.github.io %}

Another point in `UserFactory` class is that the string that is considered a fixed password is the hashed word “password”.

Laravel includes a variety of global helper PHP functions, and one of them is called `Str`. This helper function is useful for working with strings, such as generating random strings. You can refer to the documentation for this helper function at [here](https://laravel.com/docs/8.x/helpers#strings-method-list).

Now, let’s get back to our project and generate a factory for our tags. To create a factory, we can use the following artisan command:
```sh
php artisan make:factory TagFactory
```
It’s generally recommended to use a singular name for factory classes. However, if you want to specify the model while generating the factory, you can use the “-m” option in the command, like this:
```sh
php artisan make:factory TagFactory -m Tag
```
In our Tag model, we only have a simple “name” attribute, which can be defined as follows:
```php
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Tag extends Model
{
    use HasFactory;
}
```
Once we have set up the factory, we can use it to create instances of our model. To do this, simply call the factory method whenever you want to create a model instance.

You can also control the number of random data entries you want to generate. You can achieve this by using either the factory function or the count function. For example, if you want to create 5 random tags, you can use the following code:
```sh
Tag::factory(5)->create();
```
Furthermore, it’s possible to define a specific attribute with a desired value while generating the data. For instance, if you want to create 5 users with the name “test,” but you don’t care about the other attributes, you can use the following code:
```php
User::factory(5)->create(['name' => 'test']);
```
In our project, we currently have two factories for our user and tag models. Now, we need to create another factory for our task model.

When defining the factory model, it is important to consider the relational model. In our task model, each task is associated with a user. So, what we want to achieve is creating a random task with the id of a given user.

However, during testing your application, there might be situations where no user has been created in the environment. In such cases, generating a random user could be a viable solution. To accomplish this, you can use factory model again just like bellow:
```php
public function definition(): array
{
    return [
        "title" => fake()->sentence(),
        "description" => fake()->paragraph(),
        "expired_at" => fake()->dateTimeThisMonth(),
        "user_id" => User::factory(),
    ];
}
```
If you run the code in Tinker, you will notice that a new user has been created for the task model.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4o9s3ibiq52vrna30i4t.png)

Also we have the option to specify a user_id when generating a task. However, I suggest refactoring the code to utilize the users that are likely to already exist in database:
```php
public function definition(): array
{
    return [
        "title" => fake()->sentence(),
        "description" => fake()->paragraph(),
        "expired_at" => fake()->dateTimeThisMonth(),
        "user_id" => User::query()->inRandomOrder()->first()?->id ?? 
           User::factory(),
    ];
}
```
To generate random data more efficiently in Laravel, we have a better solution than using Tinker. It’s called a seeder.

In the `database/seeders` directory, you will find a class named `DatabaseSeeder`, which allows us to manage the generation of random data.

Let's update the `DatabaseSeeder` class as shown below, and then execute an artisan command to run this function.
```php
class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        Task::factory()->create();
    }
}
```
And here is the artisan command for seeding:
```sh
php artisan db:seed
```
That’s it!

With Seeder, we can easily create a random task record in our database using artisan. Additionally, we have the flexibility to create multiple seeders for different scenarios. To create a seeder, you simply need to run `php artisan make:seed <seeder-name>` command.

Now, let’s create a `TaskSeeder` that generates 5 random task records, with each task associated with two random tags:
```php
namespace Database\Seeders;

use App\Models\Tag;
use App\Models\Task;
use Illuminate\Database\Seeder;

class TaskSeeder extends Seeder
{
    public function run(): void
    {
        Task::factory(5)->hasTags(2)->create();
    }
}
```
To run this seeder, you can use the artisan command by specifying your desired seed class.
```sh
php artisan db:seed TaskSeeder
```
Or you can use call method inside `DatabaseSeeder` to execute your seed classes:
```php
class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call(TaskSeeder::class);
    }
}
```
Initial data model

Well, sometimes there are certain values that are need to be initialized, such as the status of an article (e.g., published or draft) or the status of a transaction (e.g., paid or non-payment).

I want to apply a similar approach to tags in this project. We have a couple of options to achieve this.

One option is to store the initial values in a configuration file. To do this, we can create a PHP file called “defaults” at the specified config path and define the desired values there:
```php
<?php

return [
    'tags' => ['php', 'laravel', 'develop', 'backend']
];
```
We can then initialize these values using a migration file.

Alternatively, we can initialize these values using a seeder. This means we would define a seeder like `TagSeeder` that populates the default value in the database.

Both approaches work, but I prefer to use seeder because it’s more clear:

Let’s define `TagSeeder` and initialize it’s values:
```php
class TagSeeder extends Seeder
{
    public function run(): void
    {
        foreach (config('defaults.tags') as $value) {
            Tag::firstOrCreate(['name' => $value]);
        }
    }
}
```
As you can see, the helper function config in Laravel is utilized to retrieve static information from config files.

Here I use `firstOrCreate` method which adds a new tag record only if it hasn’t been previously added.

Great! Now, let’s all come together and work on implementing a scenario like the one described below inside our `TaskSeeder`:
```php
namespace Database\Seeders;

use App\Models\Tag;
use App\Models\Task;
use App\Models\User;
use Illuminate\Database\Seeder;

class TaskSeeder extends Seeder
{
    public function run(): void
    {
        // create a user with specified credentials
        $user = User::factory()->create(['email' => 'test@test.dev']);

        // init tag with defined value
        $this->call(TagSeeder::class);

        // create 5 random tasks for the user
        $tasks = Task::factory(5)->create(['user_id' => $user->id]);

        // assosiate each generated tasks with 2 predefined tags
        foreach ($tasks as $task) {
            $tags = Tag::query()->inRandomOrder()->take(2)->pluck('id');
            $task->tags()->attach($tags);
        }
    }
}
```
Now let’s rebuild our database and fill it with this defined seeder. To rebuild the database you can run `migrate:fresh` artisan command which will drop all tables and re-run all of your migrations:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gzxr94jhigem9pmdnlt9.png)

And if you login with the user you’ll see the tasks generated successfully:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z8eplt6x3fnkinsr6s9r.png)

---


I hope this explanation clarifies the process of using seeders and factories in Laravel. If you have any further questions, feel free to ask!