Welcome back to today's episode. You learnt everything about setting up your database: creating models, different approaches to running database queries and running migrations in the last episode. This episode builds on that by teaching you how to create database factories and seed our database tables with sample data we can use for our blog.
You should be able to learn the following at the end of this tutorial:
- What model factories are.
- How to create and write model factories.
- What database seeders are.
- How to create and write database seeders.
- How to run database seeders in order to seed our blog's database with some sample data.
Model Factories
Model factories in Laravel allow you to generate dummy/fake data using the Faker PHP library. The Faker library allows generating random data by specifying various attributes. With factories you define fake data to be generated for each attribute/column of your model. This not only saves you time of manually inserting database records, but enables you to save thousands of records in your database within seconds.
Creating Factories
Factories are created using the Laravel make:factory Artisan command, like so:
php artisan make:factory PostFactory
This creates the PostFactory
factory in the database/factories folder with no model specified. To specify a model the factory belongs to, you can append the --model option to the above command. You can also create a factory when creating a new model with -f option and that model will eventually be created when the factory is run, as we did in the previous tutorial.
If you open the database/factories/PostFactory.php file you should notice the factory class definition is similar to this:
<?php
namespace Database\Factories;
use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Post::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
//
];
}
}
A Laravel factory basically extends the base Factory class and defines two important members: a $model
the factory will be creating and a definition
method that defines the values to be applied when the factory is executed. The $model
property will be automatically filled when you create the factory with the make:factory
command by specifying the --model
option and when you specify the -f
option when creating a model.
Writing Factories
Though our factory is created, we'll have to tell Laravel how we want our data to be generated when this factory is run. To do that, we have to define each attribute/column of the Post
model/post table and its corresponding value as an associative array of key-value pairs in the definition
method of our factory.
The base Laravel Factory class has a Faker instance and so each factory has access to this Faker instance. You generate values for each of your columns using this Faker instance. So, the definition for our Post
model's attributes will look like below:
// tall-blog/database/factories/PostFactory.php
...
...
...
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'category' => $this->faker->text(100),
'body' => $this->faker->paragraphs(15, true),
'title' => $this->faker->sentence(15),
'excerpt' => $this->faker->sentences(3, true),
'featured_image' => "post.png",
'published_date' => $this->faker->date(),
'user_id' => 1,
];
}
You notice that we've "hard-coded" some values such as the user_id
and the featured_image
fields. This is because auto-generating these values will not be the best since they depend on other factors. We've also left out the is_published
field since we provided a default false
value for it and want a post to stay unpublished until we decide to publish it.
One thing we'd want to add to our factory is a published state. This can be used to modify the default value of the is_published
column(which, by default, is false
) whenever we want to make a particular post as published. Add this method at the end of the PostFactory
class to do that:
// tall-blog/database/factories/PostFactory.php
...
...
...
/**
* Indicates the post is published.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function published()
{
return $this->state(function (array $attributes) {
return [
'is_published' => true,
'published_date' => now(),
];
});
}
You see that this method uses the state
method provided by the base factory class, which accepts a closure containing the attributes we defined for this factory in the definition
method as argument and returns the attributes to modify. Here we're just changing the is_published
column to true
and providing the current date time as the published date.
Using Factories
After creating and defining your factories, the next thing is to use them to create models. This can be achieved by using the factory
method provided by the HasFactory
trait we talked about in the previous episode like so:
//Creates a post without persisting to database
$post = Post::factory()->make();
// Same as above, but creates five(5) posts
$post = Post::factory()->count(5)->make();
// Same as above, but sets the published state to true
$post = Post::factory()->count(5)->published()->make();
//Creates a post and persists it to database
$post = Post::factory()->create();
// Same as persisting, but creates five(5) posts
$post = Post::factory()->count(5)->create();
// Same as persisting, but sets the published state to true
$post = Post::factory()->count(5)->published()->create();
Database Seeders
While model factories let you create sample data for your models, database seeders actually insert these data into the database, though seeders don't necessarily have to depend on factories to insert data. This means you can either use factories to seed data into your database or manually utilize Eloquent and the Query Builder to do so.
Seeders are placed in the database/seeders directory of your Laravel installation and, by default, contain a single run
method - which is called when the db:seed
command is executed. By default, Laravel creates a DatabaseSeeder
class for you out of the box. You can use this class to run other seeders by providing them to the call
method. This allows you to properly organize and arrange your seeders in any order you desire and also helps you run many seeders at once.
Creating Database Seeders
Just like other features of the Laravel framework, database seeders are created by running Artisan commands. You execute the make:seeder
Artisan command and provide the name of the seeder to create, like so:
php artisan make:seeder PostSeeder
Writing Database Seeders
As I already mentioned above, seeders, by default, contains a single run
method that is executed when the db:seed
command is run. In the run
method you insert your data by manually running Eloquent queries or by using factories. We're using the latter for this tutorial.
To insert data, we're going to make use of the PostFactory
we created in the previous sections. Within the run
method put this:
// tall-blog/database/seeders/PostSeeder.php
...
...
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Post::factory()
->count(20)
->published()
->create();
}
...
...
We're creating 20 records of the Post
model into our database whilst specifying that each post's state must be published, as opposed to the default unpublished behavior.
The last thing we want to do is open the DatabaseSeeder
class and add the PostSeeder
class to the call
method's arguments in the run
method:
// tall-blog/database/seeders/DatabaseSeeder.php
...
...
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call([
PostSeeder::class,
]);
}
...
...
Though we could just run the PostSeeder
without adding it here, doing it this way keeps your seeders organized and decoupled and can be run from a single central point.
Running the Seeder
Now that our seeder and factory are defined, we can proceed to seed our database with sample data. As pointed out already, seeders are run using the db:seed
command and optionally providing the --class
option, which is used to specify the seeder class we want to run:
php artisan db:seed
I didn't provide the --class
option because Laravel runs the DatabaseSeeder
class by default if it is not provided. Running the above will produce an output such as this:
kamil@kamil-sc650:~/Projects/Web/tall-blog$ php artisan db:seed
Seeding: Database\Seeders\PostSeeder
Seeded: Database\Seeders\PostSeeder (3,633.28ms)
Database seeding completed successfully.
Check your database to see the posts table filled with 20 posts.
This brings us to the end of the fourth episode of Creating Your First Blog With TALL tutorial series. Our next episode will teach you how to create and write your first Livewire components. See you then.
Top comments (1)
If anyone else has issues with running the seeder and getting a Post class not found error, be sure to add "use App\Models\Post;" to the top of the PostSeeder.php file.